Search in sources :

Example 41 with LoopBeginNode

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

the class BytecodeParser method appendLoopBegin.

@SuppressWarnings("try")
private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext, int startBci) {
    try (DebugCloseable context = openNodeContext(frameState, startBci)) {
        EndNode preLoopEnd = graph.add(new EndNode());
        LoopBeginNode loopBegin = graph.add(new LoopBeginNode());
        if (disableLoopSafepoint()) {
            loopBegin.disableSafepoint();
        }
        fixedWithNext.setNext(preLoopEnd);
        // Add the single non-loop predecessor of the loop header.
        loopBegin.addForwardEnd(preLoopEnd);
        return loopBegin;
    }
}
Also used : LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) EndNode(org.graalvm.compiler.nodes.EndNode) DebugCloseable(org.graalvm.compiler.debug.DebugCloseable)

Example 42 with LoopBeginNode

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

the class BytecodeParser method createTarget.

@SuppressWarnings("try")
private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
    assert block != null && state != null;
    assert !block.isExceptionEntry || state.stackSize() == 1;
    try (DebugCloseable context = openNodeContext(state, block.startBci)) {
        if (getFirstInstruction(block) == null) {
            /*
                 * This is the first time we see this block as a branch target. Create and return a
                 * placeholder that later can be replaced with a MergeNode when we see this block
                 * again.
                 */
            FixedNode targetNode;
            if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
                setFirstInstruction(block, lastInstr);
                lastInstr = null;
            } else {
                setFirstInstruction(block, graph.add(new BeginNode()));
            }
            targetNode = getFirstInstruction(block);
            Target target = checkLoopExit(targetNode, block, state);
            FixedNode result = target.fixed;
            FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
            setEntryState(block, currentEntryState);
            currentEntryState.clearNonLiveLocals(block, liveness, true);
            debug.log("createTarget %s: first visit, result: %s", block, targetNode);
            return result;
        }
        // We already saw this block before, so we have to merge states.
        if (!getEntryState(block).isCompatibleWith(state)) {
            throw bailout("stacks do not match; bytecodes would not verify");
        }
        if (getFirstInstruction(block) instanceof LoopBeginNode) {
            assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
            /*
                 * Backward loop edge. We need to create a special LoopEndNode and merge with the
                 * loop begin node created before.
                 */
            LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block);
            LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
            Target target = checkLoopExit(loopEnd, block, state);
            FixedNode result = target.fixed;
            getEntryState(block).merge(loopBegin, target.state);
            debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
            return result;
        }
        assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
        assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block";
        if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) {
            /*
                 * This is the second time we see this block. Create the actual MergeNode and the
                 * End Node for the already existing edge.
                 */
            AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block);
            // The EndNode for the already existing edge.
            EndNode end = graph.add(new EndNode());
            // The MergeNode that replaces the placeholder.
            AbstractMergeNode mergeNode = graph.add(new MergeNode());
            FixedNode next = beginNode.next();
            if (beginNode.predecessor() instanceof ControlSplitNode) {
                beginNode.setNext(end);
            } else {
                beginNode.replaceAtPredecessor(end);
                beginNode.safeDelete();
            }
            mergeNode.addForwardEnd(end);
            mergeNode.setNext(next);
            setFirstInstruction(block, mergeNode);
        }
        AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block);
        // The EndNode for the newly merged edge.
        EndNode newEnd = graph.add(new EndNode());
        Target target = checkLoopExit(newEnd, block, state);
        FixedNode result = target.fixed;
        getEntryState(block).merge(mergeNode, target.state);
        mergeNode.addForwardEnd(newEnd);
        debug.log("createTarget %s: merging state, result: %s", block, result);
        return result;
    }
}
Also used : AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) EndNode(org.graalvm.compiler.nodes.EndNode) BeginNode(org.graalvm.compiler.nodes.BeginNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) KillingBeginNode(org.graalvm.compiler.nodes.KillingBeginNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) DebugCloseable(org.graalvm.compiler.debug.DebugCloseable) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode)

Example 43 with LoopBeginNode

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

the class ControlFlowGraph method identifyBlocks.

/**
 * Identify and connect blocks (including loop backward edges). Predecessors need to be in the
 * order expected when iterating phi inputs.
 */
private void identifyBlocks() {
    // Find all block headers.
    int numBlocks = 0;
    for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) {
        Block block = new Block(begin);
        identifyBlock(block);
        numBlocks++;
    }
    // Compute reverse post order.
    int count = 0;
    NodeMap<Block> nodeMap = this.nodeToBlock;
    Block[] stack = new Block[numBlocks];
    int tos = 0;
    Block startBlock = blockFor(graph.start());
    stack[0] = startBlock;
    startBlock.setPredecessors(Block.EMPTY_ARRAY);
    do {
        Block block = stack[tos];
        int id = block.getId();
        if (id == BLOCK_ID_INITIAL) {
            // First time we see this block: push all successors.
            FixedNode last = block.getEndNode();
            if (last instanceof EndNode) {
                EndNode endNode = (EndNode) last;
                Block suxBlock = nodeMap.get(endNode.merge());
                if (suxBlock.getId() == BLOCK_ID_INITIAL) {
                    stack[++tos] = suxBlock;
                }
                block.setSuccessors(new Block[] { suxBlock });
            } else if (last instanceof IfNode) {
                IfNode ifNode = (IfNode) last;
                Block trueSucc = nodeMap.get(ifNode.trueSuccessor());
                stack[++tos] = trueSucc;
                Block falseSucc = nodeMap.get(ifNode.falseSuccessor());
                stack[++tos] = falseSucc;
                block.setSuccessors(new Block[] { trueSucc, falseSucc });
                Block[] ifPred = new Block[] { block };
                trueSucc.setPredecessors(ifPred);
                falseSucc.setPredecessors(ifPred);
            } else if (last instanceof LoopEndNode) {
                LoopEndNode loopEndNode = (LoopEndNode) last;
                block.setSuccessors(new Block[] { nodeMap.get(loopEndNode.loopBegin()) });
            // Nothing to do push onto the stack.
            } else if (last instanceof ControlSinkNode) {
                block.setSuccessors(Block.EMPTY_ARRAY);
            } else {
                assert !(last instanceof AbstractEndNode) : "Algorithm only supports EndNode and LoopEndNode.";
                int startTos = tos;
                Block[] ifPred = new Block[] { block };
                for (Node suxNode : last.successors()) {
                    Block sux = nodeMap.get(suxNode);
                    stack[++tos] = sux;
                    sux.setPredecessors(ifPred);
                }
                int suxCount = tos - startTos;
                Block[] successors = new Block[suxCount];
                System.arraycopy(stack, startTos + 1, successors, 0, suxCount);
                block.setSuccessors(successors);
            }
            block.setId(BLOCK_ID_VISITED);
            AbstractBeginNode beginNode = block.getBeginNode();
            if (beginNode instanceof LoopBeginNode) {
                computeLoopPredecessors(nodeMap, block, (LoopBeginNode) beginNode);
            } else if (beginNode instanceof MergeNode) {
                MergeNode mergeNode = (MergeNode) beginNode;
                int forwardEndCount = mergeNode.forwardEndCount();
                Block[] predecessors = new Block[forwardEndCount];
                for (int i = 0; i < forwardEndCount; ++i) {
                    predecessors[i] = nodeMap.get(mergeNode.forwardEndAt(i));
                }
                block.setPredecessors(predecessors);
            }
        } else if (id == BLOCK_ID_VISITED) {
            // Second time we see this block: All successors have been processed, so add block
            // to result list. Can safely reuse the stack for this.
            --tos;
            count++;
            int index = numBlocks - count;
            stack[index] = block;
            block.setId(index);
        } else {
            throw GraalError.shouldNotReachHere();
        }
    } while (tos >= 0);
    // Compute reverse postorder and number blocks.
    assert count == numBlocks : "all blocks must be reachable";
    this.reversePostOrder = stack;
}
Also used : ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) IfNode(org.graalvm.compiler.nodes.IfNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) Node(org.graalvm.compiler.graph.Node) EndNode(org.graalvm.compiler.nodes.EndNode) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) ControlSinkNode(org.graalvm.compiler.nodes.ControlSinkNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) IfNode(org.graalvm.compiler.nodes.IfNode) ControlSinkNode(org.graalvm.compiler.nodes.ControlSinkNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) EndNode(org.graalvm.compiler.nodes.EndNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode)

Example 44 with LoopBeginNode

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

the class ControlFlowGraph method computeLoopInformation.

private void computeLoopInformation() {
    loops = new ArrayList<>();
    if (graph.hasLoops()) {
        Block[] stack = new Block[this.reversePostOrder.length];
        for (Block block : reversePostOrder) {
            AbstractBeginNode beginNode = block.getBeginNode();
            if (beginNode instanceof LoopBeginNode) {
                Loop<Block> parent = block.getLoop();
                Loop<Block> loop = new HIRLoop(parent, loops.size(), block);
                if (parent != null) {
                    parent.getChildren().add(loop);
                }
                loops.add(loop);
                block.setLoop(loop);
                loop.getBlocks().add(block);
                LoopBeginNode loopBegin = (LoopBeginNode) beginNode;
                for (LoopEndNode end : loopBegin.loopEnds()) {
                    Block endBlock = nodeToBlock.get(end);
                    computeLoopBlocks(endBlock, loop, stack, true);
                }
                if (graph.getGuardsStage() != GuardsStage.AFTER_FSA) {
                    for (LoopExitNode exit : loopBegin.loopExits()) {
                        Block exitBlock = nodeToBlock.get(exit);
                        assert exitBlock.getPredecessorCount() == 1;
                        computeLoopBlocks(exitBlock.getFirstPredecessor(), loop, stack, true);
                        loop.addExit(exitBlock);
                    }
                    // The following loop can add new blocks to the end of the loop's block
                    // list.
                    int size = loop.getBlocks().size();
                    for (int i = 0; i < size; ++i) {
                        Block b = loop.getBlocks().get(i);
                        for (Block sux : b.getSuccessors()) {
                            if (sux.getLoop() != loop) {
                                AbstractBeginNode begin = sux.getBeginNode();
                                if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
                                    graph.getDebug().log(DebugContext.VERBOSE_LEVEL, "Unexpected loop exit with %s, including whole branch in the loop", sux);
                                    computeLoopBlocks(sux, loop, stack, false);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    /*
         * Compute the loop exit blocks after FSA.
         */
    if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) {
        for (Block b : reversePostOrder) {
            if (b.getLoop() != null) {
                for (Block succ : b.getSuccessors()) {
                    // if the loop of the succ is a different one (or none)
                    if (b.getLoop() != succ.getLoop()) {
                        // and the succ loop is not a child loop of the curr one
                        if (succ.getLoop() == null) {
                            // we might exit multiple loops if b.loops is not a loop at depth 0
                            Loop<Block> curr = b.getLoop();
                            while (curr != null) {
                                curr.addExit(succ);
                                curr = curr.getParent();
                            }
                        } else {
                            /*
                                 * succ also has a loop, might be a child loop
                                 *
                                 * if it is a child loop we do not exit a loop. if it is a loop
                                 * different than b.loop and not a child loop it must be a parent
                                 * loop, thus we exit all loops between b.loop and succ.loop
                                 *
                                 * if we exit multiple loops immediately after each other the
                                 * bytecode parser might generate loop exit nodes after another and
                                 * the CFG will identify them as separate blocks, we just take the
                                 * first one and exit all loops at this one
                                 */
                            if (succ.getLoop().getParent() != b.getLoop()) {
                                assert succ.getLoop().getDepth() < b.getLoop().getDepth();
                                // b.loop must not be a transitive parent of succ.loop
                                assert !Loop.transitiveParentLoop(succ.getLoop(), b.getLoop());
                                Loop<Block> curr = b.getLoop();
                                while (curr != null && curr != succ.getLoop()) {
                                    curr.addExit(succ);
                                    curr = curr.getParent();
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode)

Example 45 with LoopBeginNode

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

the class GraphUtil method normalizeLoops.

/**
 * Remove loop header without loop ends. This can happen with degenerated loops like this one:
 *
 * <pre>
 * for (;;) {
 *     try {
 *         break;
 *     } catch (UnresolvedException iioe) {
 *     }
 * }
 * </pre>
 */
public static void normalizeLoops(StructuredGraph graph) {
    boolean loopRemoved = false;
    for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) {
        if (begin.loopEnds().isEmpty()) {
            assert begin.forwardEndCount() == 1;
            graph.reduceDegenerateLoopBegin(begin);
            loopRemoved = true;
        } else {
            normalizeLoopBegin(begin);
        }
    }
    if (loopRemoved) {
        /*
             * Removing a degenerated loop can make non-loop phi functions unnecessary. Therefore,
             * we re-check all phi functions and remove redundant ones.
             */
        for (Node node : graph.getNodes()) {
            if (node instanceof PhiNode) {
                checkRedundantPhi((PhiNode) node);
            }
        }
    }
}
Also used : LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) MonitorIdNode(org.graalvm.compiler.nodes.java.MonitorIdNode) MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) LoadIndexedNode(org.graalvm.compiler.nodes.java.LoadIndexedNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) VirtualObjectNode(org.graalvm.compiler.nodes.virtual.VirtualObjectNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) PiNode(org.graalvm.compiler.nodes.PiNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) VirtualArrayNode(org.graalvm.compiler.nodes.virtual.VirtualArrayNode) GuardNode(org.graalvm.compiler.nodes.GuardNode) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) LoopEndNode(org.graalvm.compiler.nodes.LoopEndNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) Node(org.graalvm.compiler.graph.Node) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) ProxyNode(org.graalvm.compiler.nodes.ProxyNode)

Aggregations

LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)61 FixedNode (org.graalvm.compiler.nodes.FixedNode)30 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)26 LoopExitNode (org.graalvm.compiler.nodes.LoopExitNode)24 LoopEndNode (org.graalvm.compiler.nodes.LoopEndNode)23 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)22 Node (org.graalvm.compiler.graph.Node)21 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)21 EndNode (org.graalvm.compiler.nodes.EndNode)20 PhiNode (org.graalvm.compiler.nodes.PhiNode)20 ValueNode (org.graalvm.compiler.nodes.ValueNode)20 AbstractEndNode (org.graalvm.compiler.nodes.AbstractEndNode)19 ControlSplitNode (org.graalvm.compiler.nodes.ControlSplitNode)14 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)13 MergeNode (org.graalvm.compiler.nodes.MergeNode)11 ProxyNode (org.graalvm.compiler.nodes.ProxyNode)10 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)10 ArrayList (java.util.ArrayList)9 IfNode (org.graalvm.compiler.nodes.IfNode)9 LogicNode (org.graalvm.compiler.nodes.LogicNode)9