use of org.graalvm.compiler.nodes.ControlSinkNode in project graal by oracle.
the class SnippetTemplate method instantiate.
/**
* Replaces a given fixed node with this specialized snippet.
*
* @param metaAccess
* @param replacee the node that will be replaced
* @param replacer object that replaces the usages of {@code replacee}
* @param args the arguments to be bound to the flattened positional parameters of the snippet
* @param killReplacee is true, the replacee node is deleted
* @return the map of duplicated nodes (original -> duplicate)
*/
@SuppressWarnings("try")
public UnmodifiableEconomicMap<Node, Node> instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) {
DebugContext debug = replacee.getDebug();
assert assertSnippetKills(replacee);
try (DebugCloseable a = args.info.instantiationTimer.start(debug)) {
args.info.instantiationCounter.increment(debug);
// Inline the snippet nodes, replacing parameters with the given args in the process
StartNode entryPointNode = snippet.start();
FixedNode firstCFGNode = entryPointNode.next();
StructuredGraph replaceeGraph = replacee.graph();
EconomicMap<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
replacements.put(entryPointNode, AbstractBeginNode.prevBegin(replacee));
UnmodifiableEconomicMap<Node, Node> duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements);
// Re-wire the control flow graph around the replacee
FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
replacee.replaceAtPredecessor(firstCFGNodeDuplicate);
rewireFrameStates(replacee, duplicates);
if (replacee instanceof DeoptimizingNode) {
DeoptimizingNode replaceeDeopt = (DeoptimizingNode) replacee;
FrameState stateBefore = null;
FrameState stateDuring = null;
FrameState stateAfter = null;
if (replaceeDeopt.canDeoptimize()) {
if (replaceeDeopt instanceof DeoptimizingNode.DeoptBefore) {
stateBefore = ((DeoptimizingNode.DeoptBefore) replaceeDeopt).stateBefore();
}
if (replaceeDeopt instanceof DeoptimizingNode.DeoptDuring) {
stateDuring = ((DeoptimizingNode.DeoptDuring) replaceeDeopt).stateDuring();
}
if (replaceeDeopt instanceof DeoptimizingNode.DeoptAfter) {
stateAfter = ((DeoptimizingNode.DeoptAfter) replaceeDeopt).stateAfter();
}
}
for (DeoptimizingNode deoptNode : deoptNodes) {
DeoptimizingNode deoptDup = (DeoptimizingNode) duplicates.get(deoptNode.asNode());
if (deoptDup.canDeoptimize()) {
if (deoptDup instanceof DeoptimizingNode.DeoptBefore) {
((DeoptimizingNode.DeoptBefore) deoptDup).setStateBefore(stateBefore);
}
if (deoptDup instanceof DeoptimizingNode.DeoptDuring) {
DeoptimizingNode.DeoptDuring deoptDupDuring = (DeoptimizingNode.DeoptDuring) deoptDup;
if (stateDuring != null) {
deoptDupDuring.setStateDuring(stateDuring);
} else if (stateAfter != null) {
deoptDupDuring.computeStateDuring(stateAfter);
} else if (stateBefore != null) {
assert !deoptDupDuring.hasSideEffect() : "can't use stateBefore as stateDuring for state split " + deoptDupDuring;
deoptDupDuring.setStateDuring(stateBefore);
}
}
if (deoptDup instanceof DeoptimizingNode.DeoptAfter) {
DeoptimizingNode.DeoptAfter deoptDupAfter = (DeoptimizingNode.DeoptAfter) deoptDup;
if (stateAfter != null) {
deoptDupAfter.setStateAfter(stateAfter);
} else {
assert !deoptDupAfter.hasSideEffect() : "can't use stateBefore as stateAfter for state split " + deoptDupAfter;
deoptDupAfter.setStateAfter(stateBefore);
}
}
}
}
}
updateStamps(replacee, duplicates);
rewireMemoryGraph(replacee, duplicates);
// Replace all usages of the replacee with the value returned by the snippet
ValueNode returnValue = null;
if (returnNode != null && !(replacee instanceof ControlSinkNode)) {
ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
returnValue = returnDuplicate.result();
if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryCheckpoint) {
replacer.replace(replacee, null);
} else {
assert returnValue != null || replacee.hasNoUsages();
replacer.replace(replacee, returnValue);
}
if (returnDuplicate.isAlive()) {
FixedNode next = null;
if (replacee instanceof FixedWithNextNode) {
FixedWithNextNode fwn = (FixedWithNextNode) replacee;
next = fwn.next();
fwn.setNext(null);
}
returnDuplicate.replaceAndDelete(next);
}
}
if (killReplacee) {
// Remove the replacee from its graph
GraphUtil.killCFG(replacee);
}
debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this);
return duplicates;
}
}
use of org.graalvm.compiler.nodes.ControlSinkNode in project graal by oracle.
the class BinaryGraphPrinter method nodeProperties.
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void nodeProperties(GraphInfo info, Node node, Map<String, Object> props) {
node.getDebugProperties((Map) props);
Graph graph = info.graph;
ControlFlowGraph cfg = info.cfg;
NodeMap<Block> nodeToBlocks = info.nodeToBlocks;
if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) {
try {
props.put("probability", cfg.blockFor(node).probability());
} catch (Throwable t) {
props.put("probability", 0.0);
props.put("probability-exception", t);
}
}
try {
props.put("NodeCost-Size", node.estimatedNodeSize());
props.put("NodeCost-Cycles", node.estimatedNodeCycles());
} catch (Throwable t) {
props.put("node-cost-exception", t.getMessage());
}
if (nodeToBlocks != null) {
Object block = getBlockForNode(node, nodeToBlocks);
if (block != null) {
props.put("node-to-block", block);
}
}
if (node instanceof ControlSinkNode) {
props.put("category", "controlSink");
} else if (node instanceof ControlSplitNode) {
props.put("category", "controlSplit");
} else if (node instanceof AbstractMergeNode) {
props.put("category", "merge");
} else if (node instanceof AbstractBeginNode) {
props.put("category", "begin");
} else if (node instanceof AbstractEndNode) {
props.put("category", "end");
} else if (node instanceof FixedNode) {
props.put("category", "fixed");
} else if (node instanceof VirtualState) {
props.put("category", "state");
} else if (node instanceof PhiNode) {
props.put("category", "phi");
} else if (node instanceof ProxyNode) {
props.put("category", "proxy");
} else {
if (node instanceof ConstantNode) {
ConstantNode cn = (ConstantNode) node;
updateStringPropertiesForConstant((Map) props, cn);
}
props.put("category", "floating");
}
if (getSnippetReflectionProvider() != null) {
for (Map.Entry<String, Object> prop : props.entrySet()) {
if (prop.getValue() instanceof JavaConstantFormattable) {
props.put(prop.getKey(), ((JavaConstantFormattable) prop.getValue()).format(this));
}
}
}
}
use of org.graalvm.compiler.nodes.ControlSinkNode in project graal by oracle.
the class PostOrderNodeIterator method apply.
public void apply() {
FixedNode current = start;
do {
if (current instanceof InvokeWithExceptionNode) {
invoke((Invoke) current);
queueSuccessors(current, null);
current = nextQueuedNode();
} else if (current instanceof LoopBeginNode) {
state.loopBegin((LoopBeginNode) current);
nodeStates.put(current, state);
state = state.clone();
loopBegin((LoopBeginNode) current);
current = ((LoopBeginNode) current).next();
assert current != null;
} else if (current instanceof LoopEndNode) {
loopEnd((LoopEndNode) current);
finishLoopEnds((LoopEndNode) current);
current = nextQueuedNode();
} else if (current instanceof AbstractMergeNode) {
merge((AbstractMergeNode) current);
current = ((AbstractMergeNode) current).next();
assert current != null;
} else if (current instanceof FixedWithNextNode) {
FixedNode next = ((FixedWithNextNode) current).next();
assert next != null : current;
node(current);
current = next;
} else if (current instanceof EndNode) {
end((EndNode) current);
queueMerge((EndNode) current);
current = nextQueuedNode();
} else if (current instanceof ControlSinkNode) {
node(current);
current = nextQueuedNode();
} else if (current instanceof ControlSplitNode) {
Set<Node> successors = controlSplit((ControlSplitNode) current);
queueSuccessors(current, successors);
current = nextQueuedNode();
} else {
assert false : current;
}
} while (current != null);
finished();
}
use of org.graalvm.compiler.nodes.ControlSinkNode in project graal by oracle.
the class PartialEscapeClosure method processNodeWithScalarReplacedInputs.
/**
* This tries to canonicalize the node based on improved (replaced) inputs.
*/
@SuppressWarnings("unchecked")
private boolean processNodeWithScalarReplacedInputs(ValueNode node, FixedNode insertBefore, BlockT state, GraphEffectList effects) {
ValueNode canonicalizedValue = node;
if (node instanceof Canonicalizable.Unary<?>) {
Canonicalizable.Unary<ValueNode> canonicalizable = (Canonicalizable.Unary<ValueNode>) node;
ObjectState valueObj = getObjectState(state, canonicalizable.getValue());
ValueNode valueAlias = valueObj != null ? valueObj.getMaterializedValue() : getScalarAlias(canonicalizable.getValue());
if (valueAlias != canonicalizable.getValue()) {
canonicalizedValue = (ValueNode) canonicalizable.canonical(tool, valueAlias);
}
} else if (node instanceof Canonicalizable.Binary<?>) {
Canonicalizable.Binary<ValueNode> canonicalizable = (Canonicalizable.Binary<ValueNode>) node;
ObjectState xObj = getObjectState(state, canonicalizable.getX());
ValueNode xAlias = xObj != null ? xObj.getMaterializedValue() : getScalarAlias(canonicalizable.getX());
ObjectState yObj = getObjectState(state, canonicalizable.getY());
ValueNode yAlias = yObj != null ? yObj.getMaterializedValue() : getScalarAlias(canonicalizable.getY());
if (xAlias != canonicalizable.getX() || yAlias != canonicalizable.getY()) {
canonicalizedValue = (ValueNode) canonicalizable.canonical(tool, xAlias, yAlias);
}
} else {
return false;
}
if (canonicalizedValue != node && canonicalizedValue != null) {
if (canonicalizedValue.isAlive()) {
ValueNode alias = getAliasAndResolve(state, canonicalizedValue);
if (alias instanceof VirtualObjectNode) {
addVirtualAlias((VirtualObjectNode) alias, node);
effects.deleteNode(node);
} else {
effects.replaceAtUsages(node, alias, insertBefore);
addScalarAlias(node, alias);
}
} else {
if (!prepareCanonicalNode(canonicalizedValue, state, effects)) {
VirtualUtil.trace(node.getOptions(), debug, "replacement via canonicalization too complex: %s -> %s", node, canonicalizedValue);
return false;
}
if (canonicalizedValue instanceof ControlSinkNode) {
effects.replaceWithSink((FixedWithNextNode) node, (ControlSinkNode) canonicalizedValue);
state.markAsDead();
} else {
effects.replaceAtUsages(node, canonicalizedValue, insertBefore);
addScalarAlias(node, canonicalizedValue);
}
}
VirtualUtil.trace(node.getOptions(), debug, "replaced via canonicalization: %s -> %s", node, canonicalizedValue);
return true;
}
return false;
}
use of org.graalvm.compiler.nodes.ControlSinkNode 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);
}
}
Aggregations