Search in sources :

Example 1 with ProxyPlaceholder

use of org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder in project graal by oracle.

the class LoopDetector method handleLoopExplosionBegin.

protected void handleLoopExplosionBegin(MethodScope methodScope, LoopScope loopScope, LoopBeginNode loopBegin) {
    checkLoopExplosionIteration(methodScope, loopScope);
    List<EndNode> predecessors = loopBegin.forwardEnds().snapshot();
    FixedNode successor = loopBegin.next();
    FrameState frameState = loopBegin.stateAfter();
    if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
        LoopExplosionState queryState = new LoopExplosionState(frameState, null);
        LoopExplosionState existingState = loopScope.iterationStates.get(queryState);
        if (existingState != null) {
            loopBegin.replaceAtUsagesAndDelete(existingState.merge);
            successor.safeDelete();
            for (EndNode predecessor : predecessors) {
                existingState.merge.addForwardEnd(predecessor);
            }
            return;
        }
    }
    MergeNode merge = graph.add(new MergeNode());
    methodScope.loopExplosionMerges.add(merge);
    if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
        if (loopScope.iterationStates.size() == 0 && loopScope.loopDepth == 1) {
            if (methodScope.loopExplosionHead != null) {
                throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion must not have more than one top-level loop", LoopExplosionKind.MERGE_EXPLODE);
            }
            methodScope.loopExplosionHead = merge;
        }
        List<ValueNode> newFrameStateValues = new ArrayList<>();
        for (ValueNode frameStateValue : frameState.values) {
            if (frameStateValue == null || frameStateValue.isConstant() || !graph.isNew(methodScope.methodStartMark, frameStateValue)) {
                newFrameStateValues.add(frameStateValue);
            } else {
                ProxyPlaceholder newFrameStateValue = graph.unique(new ProxyPlaceholder(frameStateValue, merge));
                newFrameStateValues.add(newFrameStateValue);
                /*
                     * We do not have the orderID of the value anymore, so we need to search through
                     * the complete list of nodes to find a match.
                     */
                for (int i = 0; i < loopScope.createdNodes.length; i++) {
                    if (loopScope.createdNodes[i] == frameStateValue) {
                        loopScope.createdNodes[i] = newFrameStateValue;
                    }
                }
                if (loopScope.initialCreatedNodes != null) {
                    for (int i = 0; i < loopScope.initialCreatedNodes.length; i++) {
                        if (loopScope.initialCreatedNodes[i] == frameStateValue) {
                            loopScope.initialCreatedNodes[i] = newFrameStateValue;
                        }
                    }
                }
            }
        }
        FrameState newFrameState = graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(), frameState.stackSize(), frameState.rethrowException(), frameState.duringCall(), frameState.monitorIds(), frameState.virtualObjectMappings()));
        frameState.replaceAtUsagesAndDelete(newFrameState);
        frameState = newFrameState;
    }
    loopBegin.replaceAtUsagesAndDelete(merge);
    merge.setStateAfter(frameState);
    merge.setNext(successor);
    for (EndNode predecessor : predecessors) {
        merge.addForwardEnd(predecessor);
    }
    if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
        LoopExplosionState explosionState = new LoopExplosionState(frameState, merge);
        loopScope.iterationStates.put(explosionState, explosionState);
    }
}
Also used : ArrayList(java.util.ArrayList) ProxyPlaceholder(org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder) PermanentBailoutException(org.graalvm.compiler.core.common.PermanentBailoutException)

Example 2 with ProxyPlaceholder

use of org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder in project graal by oracle.

the class LoopDetector method handleLoopExplosionProxyNodes.

protected void handleLoopExplosionProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopScope outerScope, LoopExitNode loopExit, int loopExitOrderId) {
    assert loopExit.stateAfter() == null;
    int stateAfterOrderId = readOrderId(methodScope);
    BeginNode begin = graph.add(new BeginNode());
    FixedNode loopExitSuccessor = loopExit.next();
    loopExit.replaceAtPredecessor(begin);
    MergeNode loopExitPlaceholder = null;
    if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth == 1) {
        /*
             * This exit might end up as a loop exit of a loop detected after partial evaluation. We
             * need to be able to create a FrameState and the necessary proxy nodes in this case.
             */
        loopExitPlaceholder = graph.add(new MergeNode());
        methodScope.loopExplosionMerges.add(loopExitPlaceholder);
        EndNode end = graph.add(new EndNode());
        begin.setNext(end);
        loopExitPlaceholder.addForwardEnd(end);
        begin = graph.add(new BeginNode());
        loopExitPlaceholder.setNext(begin);
    }
    /*
         * In the original graph, the loop exit is not a merge node. Multiple exploded loop
         * iterations now take the same loop exit, so we have to introduce a new merge node to
         * handle the merge.
         */
    MergeNode merge = null;
    Node existingExit = lookupNode(outerScope, loopExitOrderId);
    if (existingExit == null) {
        /* First loop iteration that exits. No merge necessary yet. */
        registerNode(outerScope, loopExitOrderId, begin, false, false);
        begin.setNext(loopExitSuccessor);
    } else if (existingExit instanceof BeginNode) {
        /* Second loop iteration that exits. Create the merge. */
        merge = graph.add(new MergeNode());
        registerNode(outerScope, loopExitOrderId, merge, true, false);
        /* Add the first iteration. */
        EndNode firstEnd = graph.add(new EndNode());
        ((BeginNode) existingExit).setNext(firstEnd);
        merge.addForwardEnd(firstEnd);
        merge.setNext(loopExitSuccessor);
    } else {
        /* Subsequent loop iteration. Merge already created. */
        merge = (MergeNode) existingExit;
    }
    if (merge != null) {
        EndNode end = graph.add(new EndNode());
        begin.setNext(end);
        merge.addForwardEnd(end);
    }
    /*
         * Possibly create phi nodes for the original proxy nodes that flow out of the loop. Note
         * that we definitely do not need a proxy node itself anymore, since the loop was exploded
         * and is no longer present.
         */
    int numProxies = methodScope.reader.getUVInt();
    boolean phiCreated = false;
    for (int i = 0; i < numProxies; i++) {
        int proxyOrderId = readOrderId(methodScope);
        ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId);
        ValueNode phiInput = proxy.value();
        if (loopExitPlaceholder != null) {
            if (!phiInput.isConstant()) {
                phiInput = graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder));
            }
            registerNode(loopScope, proxyOrderId, phiInput, true, false);
        }
        ValueNode replacement;
        ValueNode existing = (ValueNode) outerScope.createdNodes[proxyOrderId];
        if (existing == null || existing == phiInput) {
            /*
                 * We are at the first loop exit, or the proxy carries the same value for all exits.
                 * We do not need a phi node yet.
                 */
            registerNode(outerScope, proxyOrderId, phiInput, true, false);
            replacement = phiInput;
        } else if (!merge.isPhiAtMerge(existing)) {
            /* Now we have two different values, so we need to create a phi node. */
            PhiNode phi;
            if (proxy instanceof ValueProxyNode) {
                phi = graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(NodeView.DEFAULT), merge));
            } else if (proxy instanceof GuardProxyNode) {
                phi = graph.addWithoutUnique(new GuardPhiNode(merge));
            } else {
                throw GraalError.shouldNotReachHere();
            }
            /* Add the inputs from all previous exits. */
            for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) {
                phi.addInput(existing);
            }
            /* Add the input from this exit. */
            phi.addInput(phiInput);
            registerNode(outerScope, proxyOrderId, phi, true, false);
            replacement = phi;
            phiCreated = true;
        } else {
            /* Phi node has been created before, so just add the new input. */
            PhiNode phi = (PhiNode) existing;
            phi.addInput(phiInput);
            replacement = phi;
        }
        proxy.replaceAtUsagesAndDelete(replacement);
    }
    if (loopExitPlaceholder != null) {
        registerNode(loopScope, stateAfterOrderId, null, true, true);
        loopExitPlaceholder.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId));
    }
    if (merge != null && (merge.stateAfter() == null || phiCreated)) {
        FrameState oldStateAfter = merge.stateAfter();
        registerNode(outerScope, stateAfterOrderId, null, true, true);
        merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, outerScope, stateAfterOrderId));
        if (oldStateAfter != null) {
            oldStateAfter.safeDelete();
        }
    }
    loopExit.safeDelete();
    assert loopExitSuccessor.predecessor() == null;
    if (merge != null) {
        merge.getNodeClass().getSuccessorEdges().update(merge, null, loopExitSuccessor);
    } else {
        begin.getNodeClass().getSuccessorEdges().update(begin, null, loopExitSuccessor);
    }
}
Also used : IntegerSwitchNode(org.graalvm.compiler.nodes.extended.IntegerSwitchNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) Node(org.graalvm.compiler.graph.Node) ProxyPlaceholder(org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder)

Example 3 with ProxyPlaceholder

use of org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder in project graal by oracle.

the class LoopDetector method assignLoopExitState.

/**
 * During graph decoding, we create a FrameState for every exploded loop iteration. This is
 * mostly the state that we want, we only need to tweak it a little bit: we need to insert the
 * appropriate ProxyNodes for all values that are created inside the loop and that flow out of
 * the loop.
 */
private void assignLoopExitState(LoopExitNode loopExit, AbstractMergeNode loopExplosionMerge, AbstractEndNode loopExplosionEnd) {
    FrameState oldState = loopExplosionMerge.stateAfter();
    /* Collect all nodes that are in the FrameState at the LoopBegin. */
    EconomicSet<Node> loopBeginValues = EconomicSet.create(Equivalence.IDENTITY);
    for (FrameState state = loopExit.loopBegin().stateAfter(); state != null; state = state.outerFrameState()) {
        for (ValueNode value : state.values()) {
            if (value != null && !value.isConstant() && !loopExit.loopBegin().isPhiAtMerge(value)) {
                loopBeginValues.add(ProxyPlaceholder.unwrap(value));
            }
        }
    }
    List<ValueNode> newValues = new ArrayList<>(oldState.values().size());
    for (ValueNode v : oldState.values()) {
        ValueNode value = v;
        ValueNode realValue = ProxyPlaceholder.unwrap(value);
        /*
             * The LoopExit is inserted before the existing merge, i.e., separately for every branch
             * that leads to the merge. So for phi functions of the merge, we need to take the input
             * that corresponds to our branch.
             */
        if (realValue instanceof PhiNode && loopExplosionMerge.isPhiAtMerge(realValue)) {
            value = ((PhiNode) realValue).valueAt(loopExplosionEnd);
            realValue = ProxyPlaceholder.unwrap(value);
        }
        if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !graph.isNew(methodScope.methodStartMark, realValue)) {
            newValues.add(realValue);
        } else {
            /*
                 * The node is not in the FrameState of the LoopBegin, i.e., it is a value computed
                 * inside the loop.
                 */
            GraalError.guarantee(value instanceof ProxyPlaceholder && ((ProxyPlaceholder) value).proxyPoint == loopExplosionMerge, "Value flowing out of loop, but we are not prepared to insert a ProxyNode");
            ProxyPlaceholder proxyPlaceholder = (ProxyPlaceholder) value;
            ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, graph);
            proxyPlaceholder.setValue(proxy);
            newValues.add(proxy);
        }
    }
    FrameState newState = new FrameState(oldState.outerFrameState(), oldState.getCode(), oldState.bci, newValues, oldState.localsSize(), oldState.stackSize(), oldState.rethrowException(), oldState.duringCall(), oldState.monitorIds(), oldState.virtualObjectMappings());
    assert loopExit.stateAfter() == null;
    loopExit.setStateAfter(graph.add(newState));
}
Also used : IntegerSwitchNode(org.graalvm.compiler.nodes.extended.IntegerSwitchNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) Node(org.graalvm.compiler.graph.Node) ArrayList(java.util.ArrayList) ProxyPlaceholder(org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder)

Aggregations

ProxyPlaceholder (org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder)3 ArrayList (java.util.ArrayList)2 Node (org.graalvm.compiler.graph.Node)2 FloatingNode (org.graalvm.compiler.nodes.calc.FloatingNode)2 IntegerSwitchNode (org.graalvm.compiler.nodes.extended.IntegerSwitchNode)2 PermanentBailoutException (org.graalvm.compiler.core.common.PermanentBailoutException)1