use of org.graalvm.compiler.nodes.FixedWithNextNode in project graal by oracle.
the class EffectsClosure method applyEffects.
@Override
public void applyEffects() {
final StructuredGraph graph = cfg.graph;
final ArrayList<Node> obsoleteNodes = new ArrayList<>(0);
final ArrayList<GraphEffectList> effectList = new ArrayList<>();
/*
* Effects are applied during a ordered iteration over the blocks to apply them in the
* correct order, e.g., apply the effect that adds a node to the graph before the node is
* used.
*/
BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
@Override
protected Void getInitialState() {
return null;
}
private void apply(GraphEffectList effects) {
if (effects != null && !effects.isEmpty()) {
effectList.add(effects);
}
}
@Override
protected Void processBlock(Block block, Void currentState) {
apply(blockEffects.get(block));
return currentState;
}
@Override
protected Void merge(Block merge, List<Void> states) {
return null;
}
@Override
protected Void cloneState(Void oldState) {
return oldState;
}
@Override
protected List<Void> processLoop(Loop<Block> loop, Void initialState) {
LoopInfo<Void> info = ReentrantBlockIterator.processLoop(this, loop, initialState);
apply(loopMergeEffects.get(loop));
return info.exitStates;
}
};
ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
for (GraphEffectList effects : effectList) {
effects.apply(graph, obsoleteNodes, false);
}
/*
* Effects that modify the cfg (e.g., removing a branch for an if that got a constant
* condition) need to be performed after all other effects, because they change phi value
* indexes.
*/
for (GraphEffectList effects : effectList) {
effects.apply(graph, obsoleteNodes, true);
}
debug.dump(DebugContext.DETAILED_LEVEL, graph, "After applying effects");
assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
for (Node node : obsoleteNodes) {
if (node.isAlive() && node.hasNoUsages()) {
if (node instanceof FixedWithNextNode) {
assert ((FixedWithNextNode) node).next() == null;
}
node.replaceAtUsages(null);
GraphUtil.killWithUnusedFloatingInputs(node);
}
}
}
use of org.graalvm.compiler.nodes.FixedWithNextNode in project graal by oracle.
the class EffectsClosure method processBlock.
@Override
protected BlockT processBlock(Block block, BlockT state) {
if (!state.isDead()) {
GraphEffectList effects = blockEffects.get(block);
/*
* If we enter an if branch that is known to be unreachable, we mark it as dead and
* cease to do any more analysis on it. At merges, these dead branches will be ignored.
*/
if (block.getBeginNode().predecessor() instanceof IfNode) {
IfNode ifNode = (IfNode) block.getBeginNode().predecessor();
LogicNode condition = ifNode.condition();
Node alias = getScalarAlias(condition);
if (alias instanceof LogicConstantNode) {
LogicConstantNode constant = (LogicConstantNode) alias;
boolean isTrueSuccessor = block.getBeginNode() == ifNode.trueSuccessor();
if (constant.getValue() != isTrueSuccessor) {
state.markAsDead();
effects.killIfBranch(ifNode, constant.getValue());
return state;
}
}
}
OptionValues options = block.getBeginNode().getOptions();
VirtualUtil.trace(options, debug, "\nBlock: %s, preds: %s, succ: %s (", block, block.getPredecessors(), block.getSuccessors());
// a lastFixedNode is needed in case we want to insert fixed nodes
FixedWithNextNode lastFixedNode = null;
Iterable<? extends Node> nodes = schedule != null ? schedule.getBlockToNodesMap().get(block) : block.getNodes();
for (Node node : nodes) {
// reset the aliases (may be non-null due to iterative loop processing)
aliases.set(node, null);
if (node instanceof LoopExitNode) {
LoopExitNode loopExit = (LoopExitNode) node;
for (ProxyNode proxy : loopExit.proxies()) {
aliases.set(proxy, null);
changed |= processNode(proxy, state, effects, lastFixedNode) && isSignificantNode(node);
}
processLoopExit(loopExit, loopEntryStates.get(loopExit.loopBegin()), state, blockEffects.get(block));
}
changed |= processNode(node, state, effects, lastFixedNode) && isSignificantNode(node);
if (node instanceof FixedWithNextNode) {
lastFixedNode = (FixedWithNextNode) node;
}
if (state.isDead()) {
break;
}
}
VirtualUtil.trace(options, debug, ")\n end state: %s\n", state);
}
return state;
}
use of org.graalvm.compiler.nodes.FixedWithNextNode in project graal by oracle.
the class HostedBytecodeParser method finishInstruction.
/**
* Insert deopt entries after all state splits.
*/
@Override
protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder stateBuilder) {
if (getMethod().compilationInfo.isDeoptTarget() && !parsingIntrinsic()) {
FrameState stateAfter = null;
if (instr instanceof StateSplit && !(instr instanceof DeoptEntryNode)) {
/*
* The regular case: the instruction is a state split and we insert a DeoptEntryNode
* right after it.
*/
StateSplit stateSplit = (StateSplit) instr;
stateAfter = stateSplit.stateAfter();
} else if (instr instanceof AbstractBeginNode) {
/*
* We are at a block begin. If the block predecessor is a LoopExitNode or an
* InvokeWithException (both are state splits), we didn't inserted a deopt entry
* yet. So we do it at the begin of a block.
*
* Note that this only happens if the LoopExitNode/InvokeWithException is the
* _single_ predcessor of this block. In case of multiple predecessors, the block
* starts with a MergeNode and this is handled like a regular case.
*/
Node predecessor = instr.predecessor();
if (predecessor instanceof KillingBeginNode) {
/*
* This is between an InvokeWithException and the BlockPlaceholderNode.
*/
predecessor = predecessor.predecessor();
}
if (predecessor instanceof StateSplit && !(predecessor instanceof DeoptEntryNode)) {
stateAfter = ((StateSplit) predecessor).stateAfter();
}
}
boolean needsDeoptEntry = false;
boolean needsProxies = false;
if (stateAfter != null) {
if (getMethod().compilationInfo.isDeoptEntry(stateAfter.bci, stateAfter.duringCall(), stateAfter.rethrowException())) {
needsDeoptEntry = true;
needsProxies = true;
} else if (instr.predecessor() instanceof Invoke && getMethod().compilationInfo.isDeoptEntry(((Invoke) instr.predecessor()).bci(), true, false)) {
/*
* Invoke nodes can be implicit deoptimization entry points. But we cannot
* anchor proxy nodes on invocations: The invoke has two successors (normal and
* exception handler), and we need to proxy values at the beginning of both.
*/
needsProxies = true;
} else if (instr instanceof ExceptionObjectNode && getMethod().compilationInfo.isDeoptEntry(((ExceptionObjectNode) instr).stateAfter().bci, true, false)) {
/*
* The predecessor of the ExceptionObjectNode will be an Invoke, but the Invoke
* has not been created yet. So the check above for the predecessor does not
* trigger.
*/
needsProxies = true;
}
}
if (needsProxies) {
long encodedBci = FrameInfoEncoder.encodeBci(stateAfter.bci, stateAfter.duringCall(), stateAfter.rethrowException());
DeoptProxyAnchorNode existingDeoptEntry = deoptEntries.get(encodedBci);
if (existingDeoptEntry != STICKY_DEOPT_ENTRY) {
if (existingDeoptEntry != null) {
/*
* Some state splits (i.e. MergeNode and DispatchBeginNode) do not have a
* correspondent byte code. Therefore there can be a previously added deopt
* entry with the same BCI. For MergeNodes we replace the previous entry
* because the new frame state has less live locals.
*/
existingDeoptEntry.replaceAtUsages(null);
graph.removeFixed(existingDeoptEntry);
deoptEntries.remove(encodedBci);
if (existingDeoptEntry instanceof DeoptEntryNode) {
/*
* We already had a DeoptEntryNode registered earlier for some reason,
* so be conservative and create one again (and not just a
* DeoptProxyAnchorNode).
*/
needsDeoptEntry = true;
}
}
assert !deoptEntries.containsKey(encodedBci) : "duplicate deopt entry for encoded BCI " + encodedBci;
DeoptProxyAnchorNode deoptEntry = createDeoptEntry(stateBuilder, stateAfter, !needsDeoptEntry);
if (instr instanceof LoopBeginNode) {
/*
* Loop headers to not have their own bci. Never move a deopt entry for the
* loop header down, e.g., into a loop end (that might then end up to be
* dead code).
*/
deoptEntries.put(encodedBci, STICKY_DEOPT_ENTRY);
} else {
deoptEntries.put(encodedBci, deoptEntry);
}
assert instr.next() == null : "cannot append instruction to instruction which isn't end (" + instr + "->" + instr.next() + ")";
instr.setNext(deoptEntry);
return deoptEntry;
}
}
}
return super.finishInstruction(instr, stateBuilder);
}
use of org.graalvm.compiler.nodes.FixedWithNextNode in project graal by oracle.
the class SnippetTemplate method instantiate.
/**
* Replaces a given floating 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 tool lowering tool used to insert the snippet into the control-flow
* @param args the arguments to be bound to the flattened positional parameters of the snippet
*/
@SuppressWarnings("try")
public void instantiate(MetaAccessProvider metaAccess, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, Arguments args) {
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, tool.getCurrentGuardAnchor().asNode());
UnmodifiableEconomicMap<Node, Node> duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements);
FixedWithNextNode lastFixedNode = tool.lastFixedNode();
assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph + " lastFixed=" + lastFixedNode;
FixedNode next = lastFixedNode.next();
lastFixedNode.setNext(null);
FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
replaceeGraph.addAfterFixed(lastFixedNode, firstCFGNodeDuplicate);
rewireFrameStates(replacee, duplicates);
updateStamps(replacee, duplicates);
rewireMemoryGraph(replacee, duplicates);
// Replace all usages of the replacee with the value returned by the snippet
ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode);
ValueNode returnValue = returnDuplicate.result();
assert returnValue != null || replacee.hasNoUsages();
replacer.replace(replacee, returnValue);
if (returnDuplicate.isAlive()) {
returnDuplicate.replaceAndDelete(next);
}
debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this);
}
}
use of org.graalvm.compiler.nodes.FixedWithNextNode in project graal by oracle.
the class GraphKit method endIf.
/**
* Ends an if block started with {@link #startIf(LogicNode, double)}.
*
* @return the created merge node, or {@code null} if no merge node was required (for example,
* when one part ended with a control sink).
*/
public AbstractMergeNode endIf() {
IfStructure s = saveLastIfNode();
FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null;
FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null;
AbstractMergeNode merge = null;
if (thenPart != null && elsePart != null) {
/* Both parts are alive, we need a real merge. */
EndNode thenEnd = graph.add(new EndNode());
graph.addAfterFixed(thenPart, thenEnd);
EndNode elseEnd = graph.add(new EndNode());
graph.addAfterFixed(elsePart, elseEnd);
merge = graph.add(new MergeNode());
merge.addForwardEnd(thenEnd);
merge.addForwardEnd(elseEnd);
lastFixedNode = merge;
} else if (thenPart != null) {
/* elsePart ended with a control sink, so we can continue with thenPart. */
lastFixedNode = thenPart;
} else if (elsePart != null) {
/* thenPart ended with a control sink, so we can continue with elsePart. */
lastFixedNode = elsePart;
} else {
/* Both parts ended with a control sink, so no nodes can be added after the if. */
assert lastFixedNode == null;
}
s.state = IfState.FINISHED;
popStructure();
return merge;
}
Aggregations