use of org.graalvm.compiler.nodes.MergeNode in project graal by oracle.
the class PEGraphDecoder method finishInlining.
@Override
protected void finishInlining(MethodScope is) {
PEMethodScope inlineScope = (PEMethodScope) is;
ResolvedJavaMethod inlineMethod = inlineScope.method;
PEMethodScope methodScope = inlineScope.caller;
LoopScope loopScope = inlineScope.callerLoopScope;
InvokeData invokeData = inlineScope.invokeData;
Invoke invoke = invokeData.invoke;
FixedNode invokeNode = invoke.asNode();
ValueNode exceptionValue = null;
int returnNodeCount = 0;
int unwindNodeCount = 0;
List<ControlSinkNode> returnAndUnwindNodes = inlineScope.returnAndUnwindNodes;
for (int i = 0; i < returnAndUnwindNodes.size(); i++) {
FixedNode fixedNode = returnAndUnwindNodes.get(i);
if (fixedNode instanceof ReturnNode) {
returnNodeCount++;
} else if (fixedNode.isAlive()) {
assert fixedNode instanceof UnwindNode;
unwindNodeCount++;
}
}
if (unwindNodeCount > 0) {
FixedNode unwindReplacement;
if (invoke instanceof InvokeWithExceptionNode) {
/* Decoding continues for the exception handler. */
unwindReplacement = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId);
} else {
/* No exception handler available, so the only thing we can do is deoptimize. */
unwindReplacement = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
}
if (unwindNodeCount == 1) {
/* Only one UnwindNode, we can use the exception directly. */
UnwindNode unwindNode = getSingleMatchingNode(returnAndUnwindNodes, returnNodeCount > 0, UnwindNode.class);
exceptionValue = unwindNode.exception();
unwindNode.replaceAndDelete(unwindReplacement);
} else {
/*
* More than one UnwindNode. This can happen with the loop explosion strategy
* FULL_EXPLODE_UNTIL_RETURN, where we keep exploding after the loop and therefore
* also explode exception paths. Merge the exception in a similar way as multiple
* return values.
*/
MergeNode unwindMergeNode = graph.add(new MergeNode());
exceptionValue = InliningUtil.mergeValueProducers(unwindMergeNode, getMatchingNodes(returnAndUnwindNodes, returnNodeCount > 0, UnwindNode.class, unwindNodeCount), null, unwindNode -> unwindNode.exception());
unwindMergeNode.setNext(unwindReplacement);
ensureExceptionStateDecoded(inlineScope);
unwindMergeNode.setStateAfter(inlineScope.exceptionState.duplicateModified(JavaKind.Object, JavaKind.Object, exceptionValue));
}
}
assert invoke.next() == null;
assert !(invoke instanceof InvokeWithExceptionNode) || ((InvokeWithExceptionNode) invoke).exceptionEdge() == null;
ValueNode returnValue;
if (returnNodeCount == 0) {
returnValue = null;
} else if (returnNodeCount == 1) {
ReturnNode returnNode = getSingleMatchingNode(returnAndUnwindNodes, unwindNodeCount > 0, ReturnNode.class);
returnValue = returnNode.result();
FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode));
returnNode.replaceAndDelete(n);
} else {
AbstractMergeNode merge = graph.add(new MergeNode());
merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
returnValue = InliningUtil.mergeReturns(merge, getMatchingNodes(returnAndUnwindNodes, unwindNodeCount > 0, ReturnNode.class, returnNodeCount));
FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge);
merge.setNext(n);
}
invokeNode.replaceAtUsages(returnValue);
/*
* Usage the handles that we have on the return value and the exception to update the
* orderId->Node table.
*/
registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true);
if (invoke instanceof InvokeWithExceptionNode) {
registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
}
if (inlineScope.exceptionPlaceholderNode != null) {
inlineScope.exceptionPlaceholderNode.replaceAtUsagesAndDelete(exceptionValue);
}
deleteInvoke(invoke);
for (InlineInvokePlugin plugin : inlineInvokePlugins) {
plugin.notifyAfterInline(inlineMethod);
}
}
use of org.graalvm.compiler.nodes.MergeNode 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;
}
}
use of org.graalvm.compiler.nodes.MergeNode 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;
}
use of org.graalvm.compiler.nodes.MergeNode in project graal by oracle.
the class ExpandLogicPhase method processIf.
@SuppressWarnings("try")
private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, double shortCircuitProbability) {
try (DebugCloseable context = ifNode.withNodeSourcePosition()) {
/*
* this method splits an IfNode, which has a ShortCircuitOrNode as its condition, into
* two separate IfNodes: if(X) and if(Y)
*
* for computing the probabilities P(X) and P(Y), we use two different approaches. The
* first one assumes that the shortCircuitProbability and the probability on the IfNode
* were created with each other in mind. If this assumption does not hold, we fall back
* to another mechanism for computing the probabilities.
*/
AbstractBeginNode trueTarget = ifNode.trueSuccessor();
AbstractBeginNode falseTarget = ifNode.falseSuccessor();
// 1st approach
// assumption: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * P(Y))
double firstIfTrueProbability = shortCircuitProbability;
double secondIfTrueProbability = sanitizeProbability((ifNode.getTrueSuccessorProbability() - shortCircuitProbability) / (1 - shortCircuitProbability));
double expectedOriginalIfTrueProbability = firstIfTrueProbability + (1 - firstIfTrueProbability) * secondIfTrueProbability;
if (!doubleEquals(ifNode.getTrueSuccessorProbability(), expectedOriginalIfTrueProbability)) {
/*
* 2nd approach
*
* the assumption above did not hold, so we either used an artificial probability as
* shortCircuitProbability or the ShortCircuitOrNode was moved to some other IfNode.
*
* so, we distribute the if's trueSuccessorProbability between the newly generated
* if nodes according to the shortCircuitProbability. the following invariant is
* always true in this case: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) *
* P(Y))
*/
firstIfTrueProbability = ifNode.getTrueSuccessorProbability() * shortCircuitProbability;
secondIfTrueProbability = sanitizeProbability(1 - (ifNode.probability(falseTarget) / (1 - firstIfTrueProbability)));
}
ifNode.clearSuccessors();
Graph graph = ifNode.graph();
AbstractMergeNode trueTargetMerge = graph.add(new MergeNode());
trueTargetMerge.setNext(trueTarget);
EndNode firstTrueEnd = graph.add(new EndNode());
EndNode secondTrueEnd = graph.add(new EndNode());
trueTargetMerge.addForwardEnd(firstTrueEnd);
trueTargetMerge.addForwardEnd(secondTrueEnd);
AbstractBeginNode firstTrueTarget = BeginNode.begin(firstTrueEnd);
AbstractBeginNode secondTrueTarget = BeginNode.begin(secondTrueEnd);
if (yNegated) {
secondIfTrueProbability = 1.0 - secondIfTrueProbability;
}
if (xNegated) {
firstIfTrueProbability = 1.0 - firstIfTrueProbability;
}
AbstractBeginNode secondIf = BeginNode.begin(graph.add(new IfNode(y, yNegated ? falseTarget : secondTrueTarget, yNegated ? secondTrueTarget : falseTarget, secondIfTrueProbability)));
IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondIf : firstTrueTarget, xNegated ? firstTrueTarget : secondIf, firstIfTrueProbability));
ifNode.replaceAtPredecessor(firstIf);
ifNode.safeDelete();
}
}
use of org.graalvm.compiler.nodes.MergeNode 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;
}
Aggregations