Search in sources :

Example 6 with NodeBitMap

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

the class GraphOrder method assertNonCyclicGraph.

/**
 * Quick (and imprecise) assertion that there are no (invalid) cycles in the given graph. First,
 * an ordered list of all nodes in the graph (a total ordering) is created. A second run over
 * this list checks whether inputs are scheduled before their usages.
 *
 * @param graph the graph to be checked.
 * @throws AssertionError if a cycle was detected.
 */
public static boolean assertNonCyclicGraph(StructuredGraph graph) {
    List<Node> order = createOrder(graph);
    NodeBitMap visited = graph.createNodeBitMap();
    visited.clearAll();
    for (Node node : order) {
        if (node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode) {
            assert visited.isMarked(((PhiNode) node).valueAt(0));
        // nothing to do
        } else {
            for (Node input : node.inputs()) {
                if (!visited.isMarked(input)) {
                    if (input instanceof FrameState) {
                    // nothing to do - frame states are known, allowed cycles
                    } else {
                        assert false : "unexpected cycle detected at input " + node + " -> " + input;
                    }
                }
            }
        }
        visited.mark(node);
    }
    return true;
}
Also used : LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) NodeBitMap(org.graalvm.compiler.graph.NodeBitMap) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) VirtualObjectNode(org.graalvm.compiler.nodes.virtual.VirtualObjectNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) Node(org.graalvm.compiler.graph.Node) EndNode(org.graalvm.compiler.nodes.EndNode) FullInfopointNode(org.graalvm.compiler.nodes.FullInfopointNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) ProxyNode(org.graalvm.compiler.nodes.ProxyNode) FrameState(org.graalvm.compiler.nodes.FrameState)

Example 7 with NodeBitMap

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

the class LoopDetector method findLoops.

private List<Loop> findLoops() {
    /* Mapping from the loop header node to additional loop information. */
    EconomicMap<MergeNode, Loop> unorderedLoops = EconomicMap.create(Equivalence.IDENTITY);
    /* Loops in reverse order of, i.e., inner loops before outer loops. */
    List<Loop> orderedLoops = new ArrayList<>();
    /*
         * Ensure we have an outermost loop that we can use to eliminate irreducible loops. This
         * loop can remain empty (no ends), in which case it is ignored.
         */
    irreducibleLoopHandler = findOrCreateLoop(unorderedLoops, methodScope.loopExplosionHead);
    NodeBitMap visited = graph.createNodeBitMap();
    NodeBitMap active = graph.createNodeBitMap();
    Deque<Node> stack = new ArrayDeque<>();
    visited.mark(methodScope.loopExplosionHead);
    stack.push(methodScope.loopExplosionHead);
    while (!stack.isEmpty()) {
        Node current = stack.peek();
        assert visited.isMarked(current);
        if (active.isMarked(current)) {
            /* We are back-tracking, i.e., all successor nodes have been processed. */
            stack.pop();
            active.clear(current);
            if (current instanceof MergeNode) {
                Loop loop = unorderedLoops.get((MergeNode) current);
                if (loop != null) {
                    /*
                         * Since nodes are popped in reverse order that they were pushed, we add
                         * inner loops before outer loops here.
                         */
                    assert !orderedLoops.contains(loop);
                    orderedLoops.add(loop);
                }
            }
        } else {
            /*
                 * Process the node. Note that we do not remove the node from the stack, i.e., we
                 * will peek it again. But the next time the node is marked as active, so we do not
                 * execute this code again.
                 */
            active.mark(current);
            for (Node successor : current.cfgSuccessors()) {
                if (active.isMarked(successor)) {
                    /* Detected a cycle, i.e., a backward branch of a loop. */
                    Loop loop = findOrCreateLoop(unorderedLoops, (MergeNode) successor);
                    assert !loop.ends.contains(current);
                    loop.ends.add((EndNode) current);
                } else if (visited.isMarked(successor)) {
                /* Forward merge into a branch we are already exploring. */
                } else {
                    /* Forward branch to a node we have not seen yet. */
                    visited.mark(successor);
                    stack.push(successor);
                }
            }
        }
    }
    return orderedLoops;
}
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 8 with NodeBitMap

use of org.graalvm.compiler.graph.NodeBitMap 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 9 with NodeBitMap

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

the class LoopFragment method computeNodes.

protected static NodeBitMap computeNodes(Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
    final NodeBitMap nodes = graph.createNodeBitMap();
    computeNodes(nodes, graph, blocks, earlyExits);
    return nodes;
}
Also used : NodeBitMap(org.graalvm.compiler.graph.NodeBitMap)

Example 10 with NodeBitMap

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

the class LoopFragment method patchNodes.

protected void patchNodes(final DuplicationReplacement dataFix) {
    if (isDuplicate() && !nodesReady) {
        assert !original.isDuplicate();
        final DuplicationReplacement cfgFix = original().getDuplicationReplacement();
        DuplicationReplacement dr;
        if (cfgFix == null && dataFix != null) {
            dr = dataFix;
        } else if (cfgFix != null && dataFix == null) {
            dr = cfgFix;
        } else if (cfgFix != null && dataFix != null) {
            dr = new DuplicationReplacement() {

                @Override
                public Node replacement(Node o) {
                    Node r1 = dataFix.replacement(o);
                    if (r1 != o) {
                        assert cfgFix.replacement(o) == o;
                        return r1;
                    }
                    Node r2 = cfgFix.replacement(o);
                    if (r2 != o) {
                        return r2;
                    }
                    return o;
                }
            };
        } else {
            dr = null;
        }
        beforeDuplication();
        NodeIterable<Node> nodesIterable = original().nodes();
        duplicationMap = graph().addDuplicates(nodesIterable, graph(), nodesIterable.count(), dr);
        finishDuplication();
        nodes = new NodeBitMap(graph());
        nodes.markAll(duplicationMap.getValues());
        nodesReady = true;
    } else {
    // TODO (gd) apply fix ?
    }
}
Also used : NodeBitMap(org.graalvm.compiler.graph.NodeBitMap) GuardNode(org.graalvm.compiler.nodes.GuardNode) ValuePhiNode(org.graalvm.compiler.nodes.ValuePhiNode) GuardProxyNode(org.graalvm.compiler.nodes.GuardProxyNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) VirtualObjectNode(org.graalvm.compiler.nodes.virtual.VirtualObjectNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) CommitAllocationNode(org.graalvm.compiler.nodes.virtual.CommitAllocationNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) ValueProxyNode(org.graalvm.compiler.nodes.ValueProxyNode) GuardPhiNode(org.graalvm.compiler.nodes.GuardPhiNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) MonitorEnterNode(org.graalvm.compiler.nodes.java.MonitorEnterNode) Node(org.graalvm.compiler.graph.Node) EndNode(org.graalvm.compiler.nodes.EndNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) ProxyNode(org.graalvm.compiler.nodes.ProxyNode) DuplicationReplacement(org.graalvm.compiler.graph.Graph.DuplicationReplacement)

Aggregations

NodeBitMap (org.graalvm.compiler.graph.NodeBitMap)14 Node (org.graalvm.compiler.graph.Node)11 FixedNode (org.graalvm.compiler.nodes.FixedNode)9 PhiNode (org.graalvm.compiler.nodes.PhiNode)9 ValueNode (org.graalvm.compiler.nodes.ValueNode)9 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)8 EndNode (org.graalvm.compiler.nodes.EndNode)7 AbstractEndNode (org.graalvm.compiler.nodes.AbstractEndNode)6 LoopExitNode (org.graalvm.compiler.nodes.LoopExitNode)6 ProxyNode (org.graalvm.compiler.nodes.ProxyNode)6 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)5 LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)5 Block (org.graalvm.compiler.nodes.cfg.Block)5 VirtualObjectNode (org.graalvm.compiler.nodes.virtual.VirtualObjectNode)5 ArrayList (java.util.ArrayList)4 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)4 MergeNode (org.graalvm.compiler.nodes.MergeNode)4 ValuePhiNode (org.graalvm.compiler.nodes.ValuePhiNode)4 ArrayDeque (java.util.ArrayDeque)3 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)3