Search in sources :

Example 11 with StartNode

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

the class InliningUtil method inline.

/**
 * Performs an actual inlining, thereby replacing the given invoke with the given
 * {@code inlineGraph}.
 *
 * @param invoke the invoke that will be replaced
 * @param inlineGraph the graph that the invoke will be replaced with
 * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
 *            false if no such check is required
 * @param inlineeMethod the actual method being inlined. Maybe be null for snippets.
 * @param reason the reason for inlining, used in tracing
 * @param phase the phase that invoked inlining
 */
@SuppressWarnings("try")
public static UnmodifiableEconomicMap<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, String reason, String phase) {
    FixedNode invokeNode = invoke.asNode();
    StructuredGraph graph = invokeNode.graph();
    final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
    assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
    assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
    if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
        nonNullReceiver(invoke);
    }
    ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
    ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
    ArrayList<Invoke> partialIntrinsicExits = new ArrayList<>();
    UnwindNode unwindNode = null;
    final StartNode entryPointNode = inlineGraph.start();
    FixedNode firstCFGNode = entryPointNode.next();
    if (firstCFGNode == null) {
        throw new IllegalStateException("Inlined graph is in invalid state: " + inlineGraph);
    }
    for (Node node : inlineGraph.getNodes()) {
        if (node == entryPointNode || (node == entryPointNode.stateAfter() && node.usages().count() == 1) || node instanceof ParameterNode) {
        // Do nothing.
        } else {
            nodes.add(node);
            if (node instanceof ReturnNode) {
                returnNodes.add((ReturnNode) node);
            } else if (node instanceof Invoke) {
                Invoke invokeInInlineGraph = (Invoke) node;
                if (invokeInInlineGraph.bci() == BytecodeFrame.UNKNOWN_BCI) {
                    ResolvedJavaMethod target1 = inlineeMethod;
                    ResolvedJavaMethod target2 = invokeInInlineGraph.callTarget().targetMethod();
                    assert target1.equals(target2) : String.format("invoke in inlined method expected to be partial intrinsic exit (i.e., call to %s), not a call to %s", target1.format("%H.%n(%p)"), target2.format("%H.%n(%p)"));
                    partialIntrinsicExits.add(invokeInInlineGraph);
                }
            } else if (node instanceof UnwindNode) {
                assert unwindNode == null;
                unwindNode = (UnwindNode) node;
            }
        }
    }
    final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(invokeNode);
    DuplicationReplacement localReplacement = new DuplicationReplacement() {

        @Override
        public Node replacement(Node node) {
            if (node instanceof ParameterNode) {
                return parameters.get(((ParameterNode) node).index());
            } else if (node == entryPointNode) {
                return prevBegin;
            }
            return node;
        }
    };
    assert invokeNode.successors().first() != null : invoke;
    assert invokeNode.predecessor() != null;
    Mark mark = graph.getMark();
    // Instead, attach the inlining log of the child graph to the current inlining log.
    EconomicMap<Node, Node> duplicates;
    try (InliningLog.UpdateScope scope = graph.getInliningLog().openDefaultUpdateScope()) {
        duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
        if (scope != null) {
            graph.getInliningLog().addDecision(invoke, true, reason, phase, duplicates, inlineGraph.getInliningLog());
        }
    }
    FrameState stateAfter = invoke.stateAfter();
    assert stateAfter == null || stateAfter.isAlive();
    FrameState stateAtExceptionEdge = null;
    if (invoke instanceof InvokeWithExceptionNode) {
        InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
        if (unwindNode != null) {
            ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
            stateAtExceptionEdge = obj.stateAfter();
        }
    }
    updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod), mark);
    if (stateAfter != null) {
        processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1);
        int callerLockDepth = stateAfter.nestedLockDepth();
        if (callerLockDepth != 0) {
            for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.TYPE)) {
                MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
                processMonitorId(invoke.stateAfter(), monitor);
            }
        }
    } else {
        assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
    }
    firstCFGNode = (FixedNode) duplicates.get(firstCFGNode);
    for (int i = 0; i < returnNodes.size(); i++) {
        returnNodes.set(i, (ReturnNode) duplicates.get(returnNodes.get(i)));
    }
    for (Invoke exit : partialIntrinsicExits) {
        // A partial intrinsic exit must be replaced with a call to
        // the intrinsified method.
        Invoke dup = (Invoke) duplicates.get(exit.asNode());
        if (dup instanceof InvokeNode) {
            InvokeNode repl = graph.add(new InvokeNode(invoke.callTarget(), invoke.bci()));
            dup.intrinsify(repl.asNode());
        } else {
            ((InvokeWithExceptionNode) dup).replaceWithNewBci(invoke.bci());
        }
    }
    if (unwindNode != null) {
        unwindNode = (UnwindNode) duplicates.get(unwindNode);
    }
    finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph);
    GraphUtil.killCFG(invokeNode);
    return duplicates;
}
Also used : AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) BeginNode(org.graalvm.compiler.nodes.BeginNode) MonitorIdNode(org.graalvm.compiler.nodes.java.MonitorIdNode) MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) ReturnNode(org.graalvm.compiler.nodes.ReturnNode) CallTargetNode(org.graalvm.compiler.nodes.CallTargetNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) PiNode(org.graalvm.compiler.nodes.PiNode) LogicNode(org.graalvm.compiler.nodes.LogicNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) MonitorExitNode(org.graalvm.compiler.nodes.java.MonitorExitNode) IsNullNode(org.graalvm.compiler.nodes.calc.IsNullNode) GuardingNode(org.graalvm.compiler.nodes.extended.GuardingNode) KillingBeginNode(org.graalvm.compiler.nodes.KillingBeginNode) StartNode(org.graalvm.compiler.nodes.StartNode) InvokeWithExceptionNode(org.graalvm.compiler.nodes.InvokeWithExceptionNode) ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) InvokeNode(org.graalvm.compiler.nodes.InvokeNode) ParameterNode(org.graalvm.compiler.nodes.ParameterNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) DeoptimizeNode(org.graalvm.compiler.nodes.DeoptimizeNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) UnwindNode(org.graalvm.compiler.nodes.UnwindNode) Node(org.graalvm.compiler.graph.Node) EndNode(org.graalvm.compiler.nodes.EndNode) ForeignCallNode(org.graalvm.compiler.nodes.extended.ForeignCallNode) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) PhiNode(org.graalvm.compiler.nodes.PhiNode) ArrayList(java.util.ArrayList) ExceptionObjectNode(org.graalvm.compiler.nodes.java.ExceptionObjectNode) Mark(org.graalvm.compiler.graph.Graph.Mark) FixedNode(org.graalvm.compiler.nodes.FixedNode) FrameState(org.graalvm.compiler.nodes.FrameState) Invoke(org.graalvm.compiler.nodes.Invoke) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) StructuredGraph(org.graalvm.compiler.nodes.StructuredGraph) ParameterNode(org.graalvm.compiler.nodes.ParameterNode) UnwindNode(org.graalvm.compiler.nodes.UnwindNode) MonitorIdNode(org.graalvm.compiler.nodes.java.MonitorIdNode) StartNode(org.graalvm.compiler.nodes.StartNode) DuplicationReplacement(org.graalvm.compiler.graph.Graph.DuplicationReplacement) ReturnNode(org.graalvm.compiler.nodes.ReturnNode) MethodCallTargetNode(org.graalvm.compiler.nodes.java.MethodCallTargetNode) InvokeWithExceptionNode(org.graalvm.compiler.nodes.InvokeWithExceptionNode) InliningLog(org.graalvm.compiler.nodes.InliningLog) ValueNode(org.graalvm.compiler.nodes.ValueNode) InvokeNode(org.graalvm.compiler.nodes.InvokeNode) ResolvedJavaMethod(jdk.vm.ci.meta.ResolvedJavaMethod)

Example 12 with StartNode

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

the class ComputeInliningRelevance method createLoopScope.

/**
 * Determines the parent of the given loop and creates a {@link Scope} object for each one. This
 * method will call itself recursively if no {@link Scope} for the parent loop exists.
 */
private Scope createLoopScope(LoopBeginNode loopBegin, EconomicMap<LoopBeginNode, Scope> loops, Scope topScope) {
    Scope scope = loops.get(loopBegin);
    if (scope == null) {
        final Scope parent;
        // look for the parent scope
        FixedNode current = loopBegin.forwardEnd();
        while (true) {
            if (current.predecessor() == null) {
                if (current instanceof LoopBeginNode) {
                    // if we reach a LoopBeginNode then we're within this loop
                    parent = createLoopScope((LoopBeginNode) current, loops, topScope);
                    break;
                } else if (current instanceof StartNode) {
                    // we're within the outermost scope
                    parent = topScope;
                    break;
                } else {
                    assert current instanceof MergeNode : current;
                    // follow any path upwards - it doesn't matter which one
                    current = ((AbstractMergeNode) current).forwardEndAt(0);
                }
            } else if (current instanceof LoopExitNode) {
                // if we reach a loop exit then we follow this loop and have the same parent
                parent = createLoopScope(((LoopExitNode) current).loopBegin(), loops, topScope).parent;
                break;
            } else {
                current = (FixedNode) current.predecessor();
            }
        }
        scope = new Scope(loopBegin, parent);
        loops.put(loopBegin, scope);
    }
    return scope;
}
Also used : AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) MergeNode(org.graalvm.compiler.nodes.MergeNode) StartNode(org.graalvm.compiler.nodes.StartNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode)

Example 13 with StartNode

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

the class FixedNodeProbabilityCache method applyAsDouble.

/**
 * <p>
 * Given a {@link FixedNode} this method finds the most immediate {@link AbstractBeginNode}
 * preceding it that either:
 * <ul>
 * <li>has no predecessor (ie, the begin-node is a merge, in particular a loop-begin, or the
 * start-node)</li>
 * <li>has a control-split predecessor</li>
 * </ul>
 * </p>
 *
 * <p>
 * The thus found {@link AbstractBeginNode} is equi-probable with the {@link FixedNode} it was
 * obtained from. When computed for the first time (afterwards a cache lookup returns it) that
 * probability is computed as follows, again depending on the begin-node's predecessor:
 * <ul>
 * <li>No predecessor. In this case the begin-node is either:</li>
 * <ul>
 * <li>a merge-node, whose probability adds up those of its forward-ends</li>
 * <li>a loop-begin, with probability as above multiplied by the loop-frequency</li>
 * </ul>
 * <li>Control-split predecessor: probability of the branch times that of the control-split</li>
 * </ul>
 * </p>
 *
 * <p>
 * As an exception to all the above, a probability of 1 is assumed for a {@link FixedNode} that
 * appears to be dead-code (ie, lacks a predecessor).
 * </p>
 */
@Override
public double applyAsDouble(FixedNode node) {
    assert node != null;
    computeNodeProbabilityCounter.increment(node.getDebug());
    FixedNode current = findBegin(node);
    if (current == null) {
        // this should only appear for dead code
        return 1D;
    }
    assert current instanceof AbstractBeginNode;
    Double cachedValue = cache.get(current);
    if (cachedValue != null) {
        return cachedValue;
    }
    double probability = 0.0;
    if (current.predecessor() == null) {
        if (current instanceof AbstractMergeNode) {
            probability = handleMerge(current, probability);
        } else {
            assert current instanceof StartNode;
            probability = 1D;
        }
    } else {
        ControlSplitNode split = (ControlSplitNode) current.predecessor();
        probability = multiplyProbabilities(split.probability((AbstractBeginNode) current), applyAsDouble(split));
    }
    assert !Double.isNaN(probability) && !Double.isInfinite(probability) : current + " " + probability;
    cache.put(current, probability);
    return probability;
}
Also used : StartNode(org.graalvm.compiler.nodes.StartNode) ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode)

Aggregations

StartNode (org.graalvm.compiler.nodes.StartNode)13 FixedNode (org.graalvm.compiler.nodes.FixedNode)10 Node (org.graalvm.compiler.graph.Node)8 ParameterNode (org.graalvm.compiler.nodes.ParameterNode)8 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)7 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)7 ValueNode (org.graalvm.compiler.nodes.ValueNode)7 DebugCloseable (org.graalvm.compiler.debug.DebugCloseable)6 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)6 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)6 DebugContext (org.graalvm.compiler.debug.DebugContext)5 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)5 LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)5 MergeNode (org.graalvm.compiler.nodes.MergeNode)5 ReturnNode (org.graalvm.compiler.nodes.ReturnNode)5 FrameState (org.graalvm.compiler.nodes.FrameState)4 PhiNode (org.graalvm.compiler.nodes.PhiNode)4 ControlSinkNode (org.graalvm.compiler.nodes.ControlSinkNode)3 DeoptimizingNode (org.graalvm.compiler.nodes.DeoptimizingNode)3 ArrayList (java.util.ArrayList)2