Search in sources :

Example 86 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class LoopDetector method decodeFloatingNode.

/**
 * Decodes a non-fixed node, but does not do any post-processing and does not register it.
 */
protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
    long readerByteIndex = methodScope.reader.getByteIndex();
    methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
    NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()];
    Node node = allocateFloatingNode(nodeClass);
    if (node instanceof FixedNode) {
        /*
             * This is a severe error that will lead to a corrupted graph, so it is better not to
             * continue decoding at all.
             */
        throw shouldNotReachHere("Not a floating node: " + node.getClass().getName());
    }
    /* Read the inputs of the node, possibly creating them recursively. */
    makeFloatingNodeInputs(methodScope, loopScope, node);
    /* Read the properties of the node. */
    readProperties(methodScope, node);
    /* There must not be any successors to read, since it is a non-fixed node. */
    assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0;
    methodScope.reader.setByteIndex(readerByteIndex);
    return node;
}
Also used : IntegerSwitchNode(org.graalvm.compiler.nodes.extended.IntegerSwitchNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) Node(org.graalvm.compiler.graph.Node)

Example 87 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class LoopDetector method findLoopExits.

private void findLoopExits(Loop loop) {
    /*
         * Backward marking of loop nodes: Starting with the known loop ends, we mark all nodes that
         * are reachable until we hit the loop begin. All successors of loop nodes that are not
         * marked as loop nodes themselves are exits of the loop. We mark all successors, and then
         * subtract the loop nodes, to find the exits.
         */
    List<Node> possibleExits = new ArrayList<>();
    NodeBitMap visited = graph.createNodeBitMap();
    Deque<Node> stack = new ArrayDeque<>();
    for (EndNode loopEnd : loop.ends) {
        stack.push(loopEnd);
        visited.mark(loopEnd);
    }
    while (!stack.isEmpty()) {
        Node current = stack.pop();
        if (current == loop.header) {
            continue;
        }
        if (!graph.isNew(methodScope.methodStartMark, current)) {
            /*
                 * The current node is before the method that contains the exploded loop. The loop
                 * must have a second entry point, i.e., it is an irreducible loop.
                 */
            loop.irreducible = true;
            return;
        }
        for (Node predecessor : current.cfgPredecessors()) {
            if (predecessor instanceof LoopExitNode) {
                /*
                     * Inner loop. We do not need to mark every node of it, instead we just continue
                     * marking at the loop header.
                     */
                LoopBeginNode innerLoopBegin = ((LoopExitNode) predecessor).loopBegin();
                if (!visited.isMarked(innerLoopBegin)) {
                    stack.push(innerLoopBegin);
                    visited.mark(innerLoopBegin);
                    /*
                         * All loop exits of the inner loop possibly need a LoopExit of our loop.
                         * Because we are processing inner loops first, we are guaranteed to already
                         * have all exits of the inner loop.
                         */
                    for (LoopExitNode exit : innerLoopBegin.loopExits()) {
                        possibleExits.add(exit);
                    }
                }
            } else if (!visited.isMarked(predecessor)) {
                stack.push(predecessor);
                visited.mark(predecessor);
                if (predecessor instanceof ControlSplitNode) {
                    for (Node succ : predecessor.cfgSuccessors()) {
                        /*
                             * We would not need to mark the current node, and would not need to
                             * mark visited nodes. But it is easier to just mark everything, since
                             * we subtract all visited nodes in the end anyway. Note that at this
                             * point we do not have the complete visited information, so we would
                             * always mark too many possible exits.
                             */
                        possibleExits.add(succ);
                    }
                }
            }
        }
    }
    /*
         * Now we know all the actual loop exits. Ideally, we would insert LoopExit nodes for them.
         * However, a LoopExit needs a valid FrameState that captures the state at the point where
         * we exit the loop. During graph decoding, we create a FrameState for every exploded loop
         * iteration. We need to do a forward marking until we hit the next such point. This puts
         * some nodes into the loop that are actually not part of the loop.
         *
         * In some cases, we did not create a FrameState during graph decoding: when there was no
         * LoopExit in the original loop that we exploded. This happens for code paths that lead
         * immediately to a DeoptimizeNode.
         *
         * Both cases mimic the behavior of the BytecodeParser, which also puts more nodes than
         * necessary into a loop because it computes loop information based on bytecodes, before the
         * actual parsing.
         */
    for (Node succ : possibleExits) {
        if (!visited.contains(succ)) {
            stack.push(succ);
            visited.mark(succ);
            assert !methodScope.loopExplosionMerges.contains(succ);
        }
    }
    while (!stack.isEmpty()) {
        Node current = stack.pop();
        assert visited.isMarked(current);
        assert current instanceof ControlSinkNode || current instanceof LoopEndNode || current.cfgSuccessors().iterator().hasNext() : "Must not reach a node that has not been decoded yet";
        for (Node successor : current.cfgSuccessors()) {
            if (visited.isMarked(successor)) {
            /* Already processed this successor. */
            } else if (methodScope.loopExplosionMerges.contains(successor)) {
                /*
                     * We have a FrameState for the successor. The LoopExit will be inserted between
                     * the current node and the successor node. Since the successor node is a
                     * MergeNode, the current node mus be a AbstractEndNode with only that MergeNode
                     * as the successor.
                     */
                assert successor instanceof MergeNode;
                assert !loop.exits.contains(current);
                loop.exits.add((AbstractEndNode) current);
            } else {
                /* Node we have not seen yet. */
                visited.mark(successor);
                stack.push(successor);
            }
        }
    }
}
Also used : NodeBitMap(org.graalvm.compiler.graph.NodeBitMap) IntegerSwitchNode(org.graalvm.compiler.nodes.extended.IntegerSwitchNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) Node(org.graalvm.compiler.graph.Node) ArrayList(java.util.ArrayList) ArrayDeque(java.util.ArrayDeque)

Example 88 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class GraphComparison method encode.

/**
 * Compresses a graph to a byte array. Multiple graphs can be compressed with the same
 * {@link GraphEncoder}.
 *
 * @param graph The graph to encode
 */
public int encode(StructuredGraph graph) {
    assert objectsArray != null && nodeClassesArray != null : "finishPrepare() must be called before encode()";
    NodeOrder nodeOrder = new NodeOrder(graph);
    int nodeCount = nodeOrder.nextOrderId;
    assert nodeOrder.orderIds.get(graph.start()) == START_NODE_ORDER_ID;
    assert nodeOrder.orderIds.get(graph.start().next()) == FIRST_NODE_ORDER_ID;
    long[] nodeStartOffsets = new long[nodeCount];
    UnmodifiableMapCursor<Node, Integer> cursor = nodeOrder.orderIds.getEntries();
    while (cursor.advance()) {
        Node node = cursor.getKey();
        Integer orderId = cursor.getValue();
        assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET;
        assert nodeStartOffsets[orderId] == 0;
        nodeStartOffsets[orderId] = writer.getBytesWritten();
        /* Write out the type, properties, and edges. */
        NodeClass<?> nodeClass = node.getNodeClass();
        writer.putUV(nodeClasses.getIndex(nodeClass));
        writeEdges(node, nodeClass.getEdges(Edges.Type.Inputs), nodeOrder);
        writeProperties(node, nodeClass.getData());
        writeEdges(node, nodeClass.getEdges(Edges.Type.Successors), nodeOrder);
        /* Special handling for some nodes that require additional information for decoding. */
        if (node instanceof AbstractEndNode) {
            AbstractEndNode end = (AbstractEndNode) node;
            AbstractMergeNode merge = end.merge();
            /*
                 * Write the orderId of the merge. The merge is not a successor in the Graal graph
                 * (only the merge has an input edge to the EndNode).
                 */
            writeOrderId(merge, nodeOrder);
            /*
                 * Write all phi mappings (the oderId of the phi input for this EndNode, and the
                 * orderId of the phi node.
                 */
            writer.putUV(merge.phis().count());
            for (PhiNode phi : merge.phis()) {
                writeOrderId(phi.valueAt(end), nodeOrder);
                writeOrderId(phi, nodeOrder);
            }
        } else if (node instanceof LoopExitNode) {
            LoopExitNode exit = (LoopExitNode) node;
            writeOrderId(exit.stateAfter(), nodeOrder);
            /* Write all proxy nodes of the LoopExitNode. */
            writer.putUV(exit.proxies().count());
            for (ProxyNode proxy : exit.proxies()) {
                writeOrderId(proxy, nodeOrder);
            }
        } else if (node instanceof Invoke) {
            Invoke invoke = (Invoke) node;
            assert invoke.stateDuring() == null : "stateDuring is not used in high-level graphs";
            writeObjectId(invoke.getContextType());
            writeOrderId(invoke.callTarget(), nodeOrder);
            writeOrderId(invoke.stateAfter(), nodeOrder);
            writeOrderId(invoke.next(), nodeOrder);
            if (invoke instanceof InvokeWithExceptionNode) {
                InvokeWithExceptionNode invokeWithExcpetion = (InvokeWithExceptionNode) invoke;
                ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExcpetion.exceptionEdge();
                writeOrderId(invokeWithExcpetion.next().next(), nodeOrder);
                writeOrderId(invokeWithExcpetion.exceptionEdge(), nodeOrder);
                writeOrderId(exceptionEdge.stateAfter(), nodeOrder);
                writeOrderId(exceptionEdge.next(), nodeOrder);
            }
        }
    }
    /*
         * Write out the metadata (maximum fixed node order id and the table of contents with the
         * start offset for all nodes).
         */
    int metadataStart = TypeConversion.asS4(writer.getBytesWritten());
    writer.putUV(nodeOrder.maxFixedNodeOrderId);
    writer.putUV(nodeCount);
    for (int i = 0; i < nodeCount; i++) {
        writer.putUV(metadataStart - nodeStartOffsets[i]);
    }
    /* Check that the decoding of the encode graph is the same as the input. */
    assert verifyEncoding(graph, new EncodedGraph(getEncoding(), metadataStart, getObjects(), getNodeClasses(), graph), architecture);
    return metadataStart;
}
Also used : ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) Node(org.graalvm.compiler.graph.Node) ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode)

Example 89 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class GraphComparison method verifyGraphsEqual.

public static boolean verifyGraphsEqual(StructuredGraph expectedGraph, StructuredGraph actualGraph) {
    NodeMap<Node> nodeMapping = new NodeMap<>(expectedGraph);
    Deque<Pair<Node, Node>> workList = new ArrayDeque<>();
    pushToWorklist(expectedGraph.start(), actualGraph.start(), nodeMapping, workList);
    while (!workList.isEmpty()) {
        Pair<Node, Node> pair = workList.removeFirst();
        Node expectedNode = pair.getLeft();
        Node actualNode = pair.getRight();
        assert expectedNode.getClass() == actualNode.getClass();
        NodeClass<?> nodeClass = expectedNode.getNodeClass();
        assert nodeClass == actualNode.getNodeClass();
        if (expectedNode instanceof MergeNode) {
            /* The order of the ends can be different, so ignore them. */
            verifyNodesEqual(expectedNode.inputs(), actualNode.inputs(), nodeMapping, workList, true);
        } else if (expectedNode instanceof PhiNode) {
            verifyPhi((PhiNode) expectedNode, (PhiNode) actualNode, nodeMapping, workList);
        } else {
            verifyNodesEqual(expectedNode.inputs(), actualNode.inputs(), nodeMapping, workList, false);
        }
        verifyNodesEqual(expectedNode.successors(), actualNode.successors(), nodeMapping, workList, false);
        if (expectedNode instanceof LoopEndNode) {
            LoopEndNode actualLoopEnd = (LoopEndNode) actualNode;
            assert actualLoopEnd.loopBegin().loopEnds().snapshot().indexOf(actualLoopEnd) == actualLoopEnd.endIndex();
        } else {
            for (int i = 0; i < nodeClass.getData().getCount(); i++) {
                Object expectedProperty = nodeClass.getData().get(expectedNode, i);
                Object actualProperty = nodeClass.getData().get(actualNode, i);
                assert Objects.equals(expectedProperty, actualProperty);
            }
        }
        if (expectedNode instanceof EndNode) {
            /* Visit the merge node, which is the one and only usage of the EndNode. */
            assert expectedNode.usages().count() == 1;
            assert actualNode.usages().count() == 1;
            verifyNodesEqual(expectedNode.usages(), actualNode.usages(), nodeMapping, workList, false);
        }
        if (expectedNode instanceof AbstractEndNode) {
            /* Visit the input values of the merge phi functions for this EndNode. */
            verifyPhis((AbstractEndNode) expectedNode, (AbstractEndNode) actualNode, nodeMapping, workList);
        }
    }
    return true;
}
Also used : ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) Node(org.graalvm.compiler.graph.Node) ArrayDeque(java.util.ArrayDeque) NodeMap(org.graalvm.compiler.graph.NodeMap) Pair(org.graalvm.collections.Pair)

Example 90 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class IfNode method splitIfAtPhi.

/**
 * Take an if that is immediately dominated by a merge with a single phi and split off any paths
 * where the test would be statically decidable creating a new merge below the approriate side
 * of the IfNode. Any undecidable tests will continue to use the original IfNode.
 *
 * @param tool
 */
private boolean splitIfAtPhi(SimplifierTool tool) {
    if (graph().getGuardsStage().areFrameStatesAtSideEffects()) {
        // Disabled until we make sure we have no FrameState-less merges at this stage
        return false;
    }
    if (!(predecessor() instanceof MergeNode)) {
        return false;
    }
    MergeNode merge = (MergeNode) predecessor();
    if (merge.forwardEndCount() == 1) {
        // Don't bother.
        return false;
    }
    if (merge.usages().count() != 1 || merge.phis().count() != 1) {
        return false;
    }
    if (merge.stateAfter() != null) {
        /* We'll get the chance to simplify this after frame state assignment. */
        return false;
    }
    PhiNode phi = merge.phis().first();
    if (phi.usages().count() != 1) {
        /*
             * For simplicity the below code assumes assumes the phi goes dead at the end so skip
             * this case.
             */
        return false;
    }
    /*
         * Check that the condition uses the phi and that there is only one user of the condition
         * expression.
         */
    if (!conditionUses(condition(), phi)) {
        return false;
    }
    /*
         * We could additionally filter for the case that at least some of the Phi inputs or one of
         * the condition inputs are constants but there are cases where a non-constant is
         * simplifiable, usually where the stamp allows the question to be answered.
         */
    /* Each successor of the if gets a new merge if needed. */
    MergeNode trueMerge = null;
    MergeNode falseMerge = null;
    assert merge.stateAfter() == null;
    for (EndNode end : merge.forwardEnds().snapshot()) {
        Node value = phi.valueAt(end);
        LogicNode result = computeCondition(tool, condition, phi, value);
        if (result instanceof LogicConstantNode) {
            merge.removeEnd(end);
            if (((LogicConstantNode) result).getValue()) {
                if (trueMerge == null) {
                    trueMerge = insertMerge(trueSuccessor());
                }
                trueMerge.addForwardEnd(end);
            } else {
                if (falseMerge == null) {
                    falseMerge = insertMerge(falseSuccessor());
                }
                falseMerge.addForwardEnd(end);
            }
        } else if (result != condition) {
            // Build a new IfNode using the new condition
            BeginNode trueBegin = graph().add(new BeginNode());
            BeginNode falseBegin = graph().add(new BeginNode());
            if (result.graph() == null) {
                result = graph().addOrUniqueWithInputs(result);
            }
            IfNode newIfNode = graph().add(new IfNode(result, trueBegin, falseBegin, trueSuccessorProbability));
            merge.removeEnd(end);
            ((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
            if (trueMerge == null) {
                trueMerge = insertMerge(trueSuccessor());
            }
            trueBegin.setNext(graph().add(new EndNode()));
            trueMerge.addForwardEnd((EndNode) trueBegin.next());
            if (falseMerge == null) {
                falseMerge = insertMerge(falseSuccessor());
            }
            falseBegin.setNext(graph().add(new EndNode()));
            falseMerge.addForwardEnd((EndNode) falseBegin.next());
            end.safeDelete();
        }
    }
    transferProxies(trueSuccessor(), trueMerge);
    transferProxies(falseSuccessor(), falseMerge);
    cleanupMerge(merge);
    cleanupMerge(trueMerge);
    cleanupMerge(falseMerge);
    return true;
}
Also used : CompareNode(org.graalvm.compiler.nodes.calc.CompareNode) LoadFieldNode(org.graalvm.compiler.nodes.java.LoadFieldNode) NormalizeCompareNode(org.graalvm.compiler.nodes.calc.NormalizeCompareNode) IntegerEqualsNode(org.graalvm.compiler.nodes.calc.IntegerEqualsNode) InstanceOfNode(org.graalvm.compiler.nodes.java.InstanceOfNode) IntegerLessThanNode(org.graalvm.compiler.nodes.calc.IntegerLessThanNode) ConditionalNode(org.graalvm.compiler.nodes.calc.ConditionalNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) IsNullNode(org.graalvm.compiler.nodes.calc.IsNullNode) ObjectEqualsNode(org.graalvm.compiler.nodes.calc.ObjectEqualsNode) Node(org.graalvm.compiler.graph.Node) UnboxNode(org.graalvm.compiler.nodes.extended.UnboxNode)

Aggregations

Node (org.graalvm.compiler.graph.Node)189 ValueNode (org.graalvm.compiler.nodes.ValueNode)105 FixedNode (org.graalvm.compiler.nodes.FixedNode)91 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)75 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)74 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)73 PhiNode (org.graalvm.compiler.nodes.PhiNode)64 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)61 LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)53 AbstractEndNode (org.graalvm.compiler.nodes.AbstractEndNode)47 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)43 FloatingNode (org.graalvm.compiler.nodes.calc.FloatingNode)41 ParameterNode (org.graalvm.compiler.nodes.ParameterNode)38 EndNode (org.graalvm.compiler.nodes.EndNode)37 LoopExitNode (org.graalvm.compiler.nodes.LoopExitNode)37 MethodCallTargetNode (org.graalvm.compiler.nodes.java.MethodCallTargetNode)37 MergeNode (org.graalvm.compiler.nodes.MergeNode)35 ReturnNode (org.graalvm.compiler.nodes.ReturnNode)35 VirtualObjectNode (org.graalvm.compiler.nodes.virtual.VirtualObjectNode)32 LogicNode (org.graalvm.compiler.nodes.LogicNode)31