use of org.graalvm.compiler.nodes.memory.MemoryAnchorNode in project graal by oracle.
the class SnippetTemplate method instantiate.
/**
* Replaces a given floating node with this specialized snippet.
*
* This snippet must be pure data-flow
*
* @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
*/
@SuppressWarnings("try")
public void instantiate(MetaAccessProvider metaAccess, FloatingNode replacee, UsageReplacer replacer, 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();
assert entryPointNode.next() == (memoryAnchor == null ? returnNode : memoryAnchor) : entryPointNode.next();
StructuredGraph replaceeGraph = replacee.graph();
EconomicMap<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
MemoryAnchorNode anchorDuplicate = null;
if (memoryAnchor != null) {
anchorDuplicate = replaceeGraph.add(new MemoryAnchorNode());
replacements.put(memoryAnchor, anchorDuplicate);
}
List<Node> floatingNodes = new ArrayList<>(nodes.size() - 2);
for (Node n : nodes) {
if (n != entryPointNode && n != returnNode) {
floatingNodes.add(n);
}
}
UnmodifiableEconomicMap<Node, Node> duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements);
rewireFrameStates(replacee, duplicates);
updateStamps(replacee, duplicates);
rewireMemoryGraph(replacee, duplicates);
assert anchorDuplicate == null || anchorDuplicate.isDeleted();
// Replace all usages of the replacee with the value returned by the snippet
ValueNode returnValue = (ValueNode) duplicates.get(returnNode.result());
replacer.replace(replacee, returnValue);
debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this);
}
}
use of org.graalvm.compiler.nodes.memory.MemoryAnchorNode in project graal by oracle.
the class SnippetTemplate method rewireMemoryGraph.
private void rewireMemoryGraph(ValueNode replacee, UnmodifiableEconomicMap<Node, Node> duplicates) {
if (replacee.graph().isAfterFloatingReadPhase()) {
// rewire outgoing memory edges
replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates));
if (returnNode != null) {
ReturnNode ret = (ReturnNode) duplicates.get(returnNode);
if (ret != null) {
MemoryMapNode memoryMap = ret.getMemoryMap();
if (memoryMap != null) {
ret.setMemoryMap(null);
memoryMap.safeDelete();
}
}
}
if (memoryAnchor != null) {
// rewire incoming memory edges
MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor);
replaceMemoryUsages(memoryDuplicate, new MemoryInputMap(replacee));
if (memoryDuplicate.hasNoUsages()) {
if (memoryDuplicate.next() != null) {
memoryDuplicate.graph().removeFixed(memoryDuplicate);
} else {
// this was a dummy memory node used when instantiating pure data-flow
// snippets: it was not attached to the control flow.
memoryDuplicate.safeDelete();
}
}
}
}
}
use of org.graalvm.compiler.nodes.memory.MemoryAnchorNode in project graal by oracle.
the class SnippetTemplate method assertSnippetKills.
private boolean assertSnippetKills(ValueNode replacee) {
if (!replacee.graph().isAfterFloatingReadPhase()) {
// no floating reads yet, ignore locations created while lowering
return true;
}
if (returnNode == null) {
// The snippet terminates control flow
return true;
}
MemoryMapNode memoryMap = returnNode.getMemoryMap();
if (memoryMap == null || memoryMap.isEmpty()) {
// there are no kills in the snippet graph
return true;
}
EconomicSet<LocationIdentity> kills = EconomicSet.create(Equivalence.DEFAULT);
kills.addAll(memoryMap.getLocations());
if (replacee instanceof MemoryCheckpoint.Single) {
// check if some node in snippet graph also kills the same location
LocationIdentity locationIdentity = ((MemoryCheckpoint.Single) replacee).getLocationIdentity();
if (locationIdentity.isAny()) {
assert !(memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) : replacee + " kills ANY_LOCATION, but snippet does not";
// if the replacee kills ANY_LOCATION, the snippet can kill arbitrary locations
return true;
}
assert kills.contains(locationIdentity) : replacee + " kills " + locationIdentity + ", but snippet doesn't contain a kill to this location";
kills.remove(locationIdentity);
}
assert !(replacee instanceof MemoryCheckpoint.Multi) : replacee + " multi not supported (yet)";
// remove ANY_LOCATION if it's just a kill by the start node
if (memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) {
kills.remove(any());
}
// node can only lower to a ANY_LOCATION kill if the replacee also kills ANY_LOCATION
assert !kills.contains(any()) : "snippet graph contains a kill to ANY_LOCATION, but replacee (" + replacee + ") doesn't kill ANY_LOCATION. kills: " + kills;
/*
* Kills to private locations are safe, since there can be no floating read to these
* locations except reads that are introduced by the snippet itself or related snippets in
* the same lowering round. These reads are anchored to a MemoryAnchor at the beginning of
* their snippet, so they can not float above a kill in another instance of the same
* snippet.
*/
for (LocationIdentity p : this.info.privateLocations) {
kills.remove(p);
}
assert kills.isEmpty() : "snippet graph kills non-private locations " + kills + " that replacee (" + replacee + ") doesn't kill";
return true;
}
Aggregations