Search in sources :

Example 1 with LoopFragmentWhole

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

the class LoopTransformations method unswitch.

public static void unswitch(LoopEx loop, List<ControlSplitNode> controlSplitNodeSet, boolean isTrivialUnswitch) {
    ControlSplitNode firstNode = controlSplitNodeSet.iterator().next();
    LoopFragmentWhole originalLoop = loop.whole();
    StructuredGraph graph = firstNode.graph();
    if (!isTrivialUnswitch) {
        loop.loopBegin().incrementUnswitches();
    }
    // create new control split out of loop
    ControlSplitNode newControlSplit = (ControlSplitNode) firstNode.copyWithInputs();
    originalLoop.entryPoint().replaceAtPredecessor(newControlSplit);
    /*
         * The code below assumes that all of the control split nodes have the same successor
         * structure, which should have been enforced by findUnswitchable.
         */
    Iterator<Position> successors = firstNode.successorPositions().iterator();
    assert successors.hasNext();
    // original loop is used as first successor
    Position firstPosition = successors.next();
    AbstractBeginNode originalLoopBegin = BeginNode.begin(originalLoop.entryPoint());
    firstPosition.set(newControlSplit, originalLoopBegin);
    originalLoopBegin.setNodeSourcePosition(firstPosition.get(firstNode).getNodeSourcePosition());
    while (successors.hasNext()) {
        Position position = successors.next();
        // create a new loop duplicate and connect it.
        LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
        AbstractBeginNode newBegin = BeginNode.begin(duplicateLoop.entryPoint());
        newBegin.setNodeSourcePosition(position.get(firstNode).getNodeSourcePosition());
        position.set(newControlSplit, newBegin);
        // For each cloned ControlSplitNode, simplify the proper path
        for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
            ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
            if (duplicatedControlSplit.isAlive()) {
                AbstractBeginNode survivingSuccessor = (AbstractBeginNode) position.get(duplicatedControlSplit);
                survivingSuccessor.replaceAtUsages(newBegin, InputType.Guard);
                graph.removeSplitPropagate(duplicatedControlSplit, survivingSuccessor);
            }
        }
    }
    // original loop is simplified last to avoid deleting controlSplitNode too early
    for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
        if (controlSplitNode.isAlive()) {
            AbstractBeginNode survivingSuccessor = (AbstractBeginNode) firstPosition.get(controlSplitNode);
            survivingSuccessor.replaceAtUsages(originalLoopBegin, InputType.Guard);
            graph.removeSplitPropagate(controlSplitNode, survivingSuccessor);
        }
    }
// TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
}
Also used : LoopFragmentWhole(org.graalvm.compiler.nodes.loop.LoopFragmentWhole) StructuredGraph(org.graalvm.compiler.nodes.StructuredGraph) Position(org.graalvm.compiler.graph.Position) ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode)

Example 2 with LoopFragmentWhole

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

the class LoopTransformations method insertPrePostLoops.

// This function splits candidate loops into pre, main and post loops,
// dividing the iteration space to facilitate the majority of iterations
// being executed in a main loop, which will have RCE implemented upon it.
// The initial loop form is constrained to single entry/exit, but can have
// flow. The translation looks like:
// 
// @formatter:off
// 
// (Simple Loop entry)                   (Pre Loop Entry)
// |                                  |
// (LoopBeginNode)                    (LoopBeginNode)
// |                                  |
// (Loop Control Test)<------   ==>  (Loop control Test)<------
// /               \       \         /               \       \
// (Loop Exit)      (Loop Body) |    (Loop Exit)      (Loop Body) |
// |                |       |        |                |       |
// (continue code)     (Loop End)  |  if (M < length)*   (Loop End)  |
// \       /       /      \           \      /
// ----->        /       |            ----->
// /  if ( ... )*
// /     /       \
// /     /         \
// /     /           \
// |     /     (Main Loop Entry)
// |    |             |
// |    |      (LoopBeginNode)
// |    |             |
// |    |     (Loop Control Test)<------
// |    |      /               \        \
// |    |  (Loop Exit)      (Loop Body) |
// \   \      |                |       |
// \   \     |            (Loop End)  |
// \   \    |                \       /
// \   \   |                 ------>
// \   \  |
// (Main Loop Merge)*
// |
// (Post Loop Entry)
// |
// (LoopBeginNode)
// |
// (Loop Control Test)<-----
// /               \       \
// (Loop Exit)     (Loop Body) |
// |               |       |
// (continue code)    (Loop End)  |
// \      /
// ----->
// 
// Key: "*" = optional.
// @formatter:on
// 
// The value "M" is the maximal value of the loop trip for the original
// loop. The value of "length" is applicable to the number of arrays found
// in the loop but is reduced if some or all of the arrays are known to be
// the same length as "M". The maximum number of tests can be equal to the
// number of arrays in the loop, where multiple instances of an array are
// subsumed into a single test for that arrays length.
// 
// If the optional main loop entry tests are absent, the Pre Loop exit
// connects to the Main loops entry and there is no merge hanging off the
// main loops exit to converge flow from said tests. All split use data
// flow is mitigated through phi(s) in the main merge if present and
// passed through the main and post loop phi(s) from the originating pre
// loop with final phi(s) and data flow patched to the "continue code".
// The pre loop is constrained to one iteration for now and will likely
// be updated to produce vector alignment if applicable.
public static PreMainPostResult insertPrePostLoops(LoopEx loop) {
    assert loop.loopBegin().loopExits().isEmpty() || loop.loopBegin().graph().isAfterStage(StageFlag.VALUE_PROXY_REMOVAL) || loop.counted().getCountedExit() instanceof LoopExitNode : "Can only unroll loops, if they have exits, if the counted exit is a regular loop exit " + loop;
    StructuredGraph graph = loop.loopBegin().graph();
    // prepare clean exit states
    ensureExitsHaveUniqueStates(loop);
    graph.getDebug().log("LoopTransformations.insertPrePostLoops %s", loop);
    LoopFragmentWhole preLoop = loop.whole();
    CountedLoopInfo preCounted = loop.counted();
    LoopBeginNode preLoopBegin = loop.loopBegin();
    /*
         * When transforming counted loops with multiple loop exits the counted exit is the one that
         * is interesting for the pre-main-post transformation since it is the regular, non-early,
         * exit.
         */
    final AbstractBeginNode preLoopExitNode = preCounted.getCountedExit();
    assert preLoop.nodes().contains(preLoopBegin);
    assert preLoop.nodes().contains(preLoopExitNode);
    /*
         * Duplicate the original loop two times, each duplication will create a merge for the loop
         * exits of the original loop and the duplication one.
         */
    LoopFragmentWhole mainLoop = preLoop.duplicate();
    LoopBeginNode mainLoopBegin = mainLoop.getDuplicatedNode(preLoopBegin);
    AbstractBeginNode mainLoopExitNode = mainLoop.getDuplicatedNode(preLoopExitNode);
    EndNode mainEndNode = getBlockEndAfterLoopExit(mainLoopExitNode);
    AbstractMergeNode mainMergeNode = mainEndNode.merge();
    graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After  duplication of main loop %s", mainLoop);
    LoopFragmentWhole postLoop = preLoop.duplicate();
    LoopBeginNode postLoopBegin = postLoop.getDuplicatedNode(preLoopBegin);
    AbstractBeginNode postLoopExitNode = postLoop.getDuplicatedNode(preLoopExitNode);
    EndNode postEndNode = getBlockEndAfterLoopExit(postLoopExitNode);
    AbstractMergeNode postMergeNode = postEndNode.merge();
    graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After post loop duplication");
    preLoopBegin.incrementSplits();
    preLoopBegin.incrementSplits();
    preLoopBegin.setPreLoop();
    mainLoopBegin.setMainLoop();
    postLoopBegin.setPostLoop();
    if (graph.isBeforeStage(StageFlag.VALUE_PROXY_REMOVAL)) {
        // clear state to avoid problems with usages on the merge
        cleanupAndDeleteState(mainMergeNode);
        cleanupPostDominatingValues(mainLoopBegin, mainMergeNode, postEndNode);
        removeStateAndPhis(postMergeNode);
        /*
             * Fix the framestates for the pre loop exit node and the main loop exit node.
             *
             * The only exit that actually really exits the original loop is the loop exit of the
             * post-loop. All other paths have to fully go through pre->main->post loops. We can
             * never go from pre/main loop directly to the code after the loop, we always have to go
             * through the original loop header, thus we need to fix the correct state on the
             * pre/main loop exit.
             *
             * However, depending on the shape of the loop this is either
             *
             * for head counted loops: the loop header state with the values fixed
             *
             * for tail counted loops: the last state inside the body of the loop dominating the
             * tail check (This is different since tail counted loops have protection control flow
             * meaning it is possible to go pre -> after post, pre->main->after post, pre -> post ->
             * after post. For the protected main and post loops it is enough to deopt to the last
             * body state and the interpreter can then re-execute any failing counter check).
             *
             * For both scenarios we proxy the necessary nodes.
             */
        createExitState(preLoopBegin, (LoopExitNode) preLoopExitNode, loop.counted().isInverted(), preLoop);
        createExitState(mainLoopBegin, (LoopExitNode) mainLoopExitNode, loop.counted().isInverted(), mainLoop);
    }
    assert graph.isAfterStage(StageFlag.VALUE_PROXY_REMOVAL) || preLoopExitNode instanceof LoopExitNode : "Unrolling with proxies requires actual loop exit nodes as counted exits";
    rewirePreToMainPhis(preLoopBegin, mainLoop, preLoop, graph.isBeforeStage(StageFlag.VALUE_PROXY_REMOVAL) ? (LoopExitNode) preLoopExitNode : null, loop.counted().isInverted());
    AbstractEndNode postEntryNode = postLoopBegin.forwardEnd();
    // Exits have been merged, find the continuation below the merge
    FixedNode continuationNode = mainMergeNode.next();
    // In the case of no Bounds tests, we just flow right into the main loop
    AbstractBeginNode mainLandingNode = BeginNode.begin(postEntryNode);
    mainLoopExitNode.setNext(mainLandingNode);
    preLoopExitNode.setNext(mainLoopBegin.forwardEnd());
    // Add and update any phi edges as per merge usage as needed and update usages
    assert graph.isAfterStage(StageFlag.VALUE_PROXY_REMOVAL) || mainLoopExitNode instanceof LoopExitNode : "Unrolling with proxies requires actual loop exit nodes as counted exits";
    processPreLoopPhis(loop, graph.isBeforeStage(StageFlag.VALUE_PROXY_REMOVAL) ? (LoopExitNode) mainLoopExitNode : null, mainLoop, postLoop);
    graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After processing pre loop phis");
    continuationNode.predecessor().clearSuccessors();
    postLoopExitNode.setNext(continuationNode);
    cleanupMerge(postMergeNode, postLoopExitNode);
    cleanupMerge(mainMergeNode, mainLandingNode);
    // Change the preLoop to execute one iteration for now
    if (graph.isBeforeStage(StageFlag.VALUE_PROXY_REMOVAL)) {
        /*
             * The pre-loop exit's condition's induction variable start node might be already
             * re-written to be a phi of merged loop exits from a previous pre-main-post creation,
             * thus use an updated loop info.
             */
        loop.resetCounted();
        loop.detectCounted();
        updatePreLoopLimit(loop.counted());
    } else {
        updatePreLoopLimit(preCounted);
    }
    double originalFrequency = loop.localLoopFrequency();
    preLoopBegin.setLoopOrigFrequency(originalFrequency);
    mainLoopBegin.setLoopOrigFrequency(originalFrequency);
    postLoopBegin.setLoopOrigFrequency(originalFrequency);
    assert preLoopExitNode.predecessor() instanceof IfNode;
    assert mainLoopExitNode.predecessor() instanceof IfNode;
    assert postLoopExitNode.predecessor() instanceof IfNode;
    setSingleVisitedLoopFrequencySplitProbability(preLoopExitNode);
    setSingleVisitedLoopFrequencySplitProbability(postLoopExitNode);
    if (graph.isAfterStage(StageFlag.VALUE_PROXY_REMOVAL)) {
        // The pre and post loops don't require safepoints at all
        for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) {
            graph.removeFixed(safepoint);
        }
        for (SafepointNode safepoint : postLoop.nodes().filter(SafepointNode.class)) {
            graph.removeFixed(safepoint);
        }
    }
    graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "InsertPrePostLoops %s", loop);
    return new PreMainPostResult(preLoopBegin, mainLoopBegin, postLoopBegin, preLoop, mainLoop, postLoop);
}
Also used : LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) SafepointNode(org.graalvm.compiler.nodes.SafepointNode) CountedLoopInfo(org.graalvm.compiler.nodes.loop.CountedLoopInfo) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) IfNode(org.graalvm.compiler.nodes.IfNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) LoopFragmentWhole(org.graalvm.compiler.nodes.loop.LoopFragmentWhole) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) StructuredGraph(org.graalvm.compiler.nodes.StructuredGraph) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) EndNode(org.graalvm.compiler.nodes.EndNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode)

Aggregations

AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)2 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)2 LoopFragmentWhole (org.graalvm.compiler.nodes.loop.LoopFragmentWhole)2 Position (org.graalvm.compiler.graph.Position)1 AbstractEndNode (org.graalvm.compiler.nodes.AbstractEndNode)1 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)1 ControlSplitNode (org.graalvm.compiler.nodes.ControlSplitNode)1 EndNode (org.graalvm.compiler.nodes.EndNode)1 FixedNode (org.graalvm.compiler.nodes.FixedNode)1 IfNode (org.graalvm.compiler.nodes.IfNode)1 LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)1 LoopExitNode (org.graalvm.compiler.nodes.LoopExitNode)1 SafepointNode (org.graalvm.compiler.nodes.SafepointNode)1 CountedLoopInfo (org.graalvm.compiler.nodes.loop.CountedLoopInfo)1