use of org.graalvm.compiler.nodes.ProxyNode in project graal by oracle.
the class ReadEliminationClosure method processLoopExit.
@Override
protected void processLoopExit(LoopExitNode exitNode, ReadEliminationBlockState initialState, ReadEliminationBlockState exitState, GraphEffectList effects) {
if (exitNode.graph().hasValueProxies()) {
MapCursor<CacheEntry<?>, ValueNode> entry = exitState.getReadCache().getEntries();
while (entry.advance()) {
if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
ProxyNode proxy = new ValueProxyNode(exitState.getCacheEntry(entry.getKey()), exitNode);
effects.addFloatingNode(proxy, "readCacheProxy");
exitState.getReadCache().put(entry.getKey(), proxy);
}
}
}
}
use of org.graalvm.compiler.nodes.ProxyNode in project graal by oracle.
the class AssertValueNode method insert.
protected static void insert(ValueNode input, AssertValueNode assertionNode) {
StructuredGraph graph = input.graph();
/* Find the insertion point where we want to add the assertion node. */
FixedWithNextNode insertionPoint;
if (input instanceof ParameterNode) {
insertionPoint = graph.start();
} else if (input instanceof InvokeWithExceptionNode) {
insertionPoint = ((InvokeWithExceptionNode) input).next();
} else if (input instanceof FixedWithNextNode) {
insertionPoint = (FixedWithNextNode) input;
} else {
throw shouldNotReachHere("Node is not fixed: " + input);
}
/*
* When inserting after an invoke that is also a loop exit, a proxy node is inserted between
* the invoke and every usage. We need to be after this proxy node to avoid unschedulable
* graphs.
*/
ProxyNode proxyUsage = null;
boolean otherUsages = false;
for (Node usage : input.usages()) {
if (usage instanceof ProxyNode && ((ProxyNode) usage).proxyPoint() == insertionPoint) {
assert proxyUsage == null : "can have only one proxy";
proxyUsage = (ProxyNode) usage;
} else if (!(usage instanceof FrameState)) {
otherUsages = true;
}
}
assert proxyUsage == null || otherUsages == false : "cannot have other usages when having a proxy usage";
ValueNode assertInput = proxyUsage != null ? proxyUsage : input;
/*
* Replace the object at usages. We do not process usages at the frame state because it
* could be the stateAfter() of the insertion point. Since frame states are not doing
* anything in code, this is not a loss of assertion precision.
*/
for (Node usage : assertInput.usages().snapshot()) {
if (!(usage instanceof FrameState)) {
usage.replaceFirstInput(assertInput, assertionNode);
}
}
/*
* Set the input object of the assertion node, now that all other usages have been replaced.
*/
assertionNode.updateUsages(assertionNode.input, assertInput);
assertionNode.input = assertInput;
/* Insert assertion node in graph. */
graph.addAfterFixed(insertionPoint, assertionNode);
}
use of org.graalvm.compiler.nodes.ProxyNode 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.ProxyNode in project graal by oracle.
the class LoopFragment method mergeEarlyExits.
/**
* Merges the early exits (i.e. loop exits) that were duplicated as part of this fragment, with
* the original fragment's exits.
*/
protected void mergeEarlyExits() {
assert isDuplicate();
StructuredGraph graph = graph();
for (AbstractBeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().loop().getExits())) {
LoopExitNode loopEarlyExit = (LoopExitNode) earlyExit;
FixedNode next = loopEarlyExit.next();
if (loopEarlyExit.isDeleted() || !this.original().contains(loopEarlyExit)) {
continue;
}
AbstractBeginNode newEarlyExit = getDuplicatedNode(loopEarlyExit);
if (newEarlyExit == null) {
continue;
}
MergeNode merge = graph.add(new MergeNode());
EndNode originalEnd = graph.add(new EndNode());
EndNode newEnd = graph.add(new EndNode());
merge.addForwardEnd(originalEnd);
merge.addForwardEnd(newEnd);
loopEarlyExit.setNext(originalEnd);
newEarlyExit.setNext(newEnd);
merge.setNext(next);
FrameState exitState = loopEarlyExit.stateAfter();
if (exitState != null) {
FrameState originalExitState = exitState;
exitState = exitState.duplicateWithVirtualState();
loopEarlyExit.setStateAfter(exitState);
merge.setStateAfter(originalExitState);
/*
* Using the old exit's state as the merge's state is necessary because some of the
* VirtualState nodes contained in the old exit's state may be shared by other
* dominated VirtualStates. Those dominated virtual states need to see the
* proxy->phi update that are applied below.
*
* We now update the original fragment's nodes accordingly:
*/
originalExitState.applyToVirtual(node -> original.nodes.clearAndGrow(node));
exitState.applyToVirtual(node -> original.nodes.markAndGrow(node));
}
FrameState finalExitState = exitState;
for (Node anchored : loopEarlyExit.anchored().snapshot()) {
anchored.replaceFirstInput(loopEarlyExit, merge);
}
boolean newEarlyExitIsLoopExit = newEarlyExit instanceof LoopExitNode;
for (ProxyNode vpn : loopEarlyExit.proxies().snapshot()) {
if (vpn.hasNoUsages()) {
continue;
}
if (vpn.value() == null) {
assert vpn instanceof GuardProxyNode;
vpn.replaceAtUsages(null);
continue;
}
final ValueNode replaceWith;
ValueNode newVpn = prim(newEarlyExitIsLoopExit ? vpn : vpn.value());
if (newVpn != null) {
PhiNode phi;
if (vpn instanceof ValueProxyNode) {
phi = graph.addWithoutUnique(new ValuePhiNode(vpn.stamp(NodeView.DEFAULT), merge));
} else if (vpn instanceof GuardProxyNode) {
phi = graph.addWithoutUnique(new GuardPhiNode(merge));
} else {
throw GraalError.shouldNotReachHere();
}
phi.addInput(vpn);
phi.addInput(newVpn);
replaceWith = phi;
} else {
replaceWith = vpn.value();
}
vpn.replaceAtMatchingUsages(replaceWith, usage -> {
if (merge.isPhiAtMerge(usage)) {
return false;
}
if (usage instanceof VirtualState) {
VirtualState stateUsage = (VirtualState) usage;
if (finalExitState != null && finalExitState.isPartOfThisState(stateUsage)) {
return false;
}
}
return true;
});
}
}
}
use of org.graalvm.compiler.nodes.ProxyNode in project graal by oracle.
the class LoopFragment method computeNodes.
protected static void computeNodes(NodeBitMap nodes, Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
for (AbstractBeginNode b : blocks) {
if (b.isDeleted()) {
continue;
}
for (Node n : b.getBlockNodes()) {
if (n instanceof Invoke) {
nodes.mark(((Invoke) n).callTarget());
}
if (n instanceof NodeWithState) {
NodeWithState withState = (NodeWithState) n;
withState.states().forEach(state -> state.applyToVirtual(node -> nodes.mark(node)));
}
if (n instanceof AbstractMergeNode) {
// if a merge is in the loop, all of its phis are also in the loop
for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
nodes.mark(phi);
}
}
nodes.mark(n);
}
}
for (AbstractBeginNode earlyExit : earlyExits) {
if (earlyExit.isDeleted()) {
continue;
}
nodes.mark(earlyExit);
if (earlyExit instanceof LoopExitNode) {
LoopExitNode loopExit = (LoopExitNode) earlyExit;
FrameState stateAfter = loopExit.stateAfter();
if (stateAfter != null) {
stateAfter.applyToVirtual(node -> nodes.mark(node));
}
for (ProxyNode proxy : loopExit.proxies()) {
nodes.mark(proxy);
}
}
}
final NodeBitMap nonLoopNodes = graph.createNodeBitMap();
Deque<WorkListEntry> worklist = new ArrayDeque<>();
for (AbstractBeginNode b : blocks) {
if (b.isDeleted()) {
continue;
}
for (Node n : b.getBlockNodes()) {
if (n instanceof CommitAllocationNode) {
for (VirtualObjectNode obj : ((CommitAllocationNode) n).getVirtualObjects()) {
markFloating(worklist, obj, nodes, nonLoopNodes);
}
}
if (n instanceof MonitorEnterNode) {
markFloating(worklist, ((MonitorEnterNode) n).getMonitorId(), nodes, nonLoopNodes);
}
if (n instanceof AbstractMergeNode) {
/*
* Since we already marked all phi nodes as being in the loop to break cycles,
* we also have to iterate over their usages here.
*/
for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
for (Node usage : phi.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
}
}
}
for (Node usage : n.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
}
}
}
}
Aggregations