use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class GraphOrder method assertNonCyclicGraph.
/**
* Quick (and imprecise) assertion that there are no (invalid) cycles in the given graph. First,
* an ordered list of all nodes in the graph (a total ordering) is created. A second run over
* this list checks whether inputs are scheduled before their usages.
*
* @param graph the graph to be checked.
* @throws AssertionError if a cycle was detected.
*/
public static boolean assertNonCyclicGraph(StructuredGraph graph) {
List<Node> order = createOrder(graph);
NodeBitMap visited = graph.createNodeBitMap();
visited.clearAll();
for (Node node : order) {
if (node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode) {
assert visited.isMarked(((PhiNode) node).valueAt(0));
// nothing to do
} else {
for (Node input : node.inputs()) {
if (!visited.isMarked(input)) {
if (input instanceof FrameState) {
// nothing to do - frame states are known, allowed cycles
} else {
assert false : "unexpected cycle detected at input " + node + " -> " + input;
}
}
}
}
visited.mark(node);
}
return true;
}
use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class LoopDetector method findLoops.
private List<Loop> findLoops() {
/* Mapping from the loop header node to additional loop information. */
EconomicMap<MergeNode, Loop> unorderedLoops = EconomicMap.create(Equivalence.IDENTITY);
/* Loops in reverse order of, i.e., inner loops before outer loops. */
List<Loop> orderedLoops = new ArrayList<>();
/*
* Ensure we have an outermost loop that we can use to eliminate irreducible loops. This
* loop can remain empty (no ends), in which case it is ignored.
*/
irreducibleLoopHandler = findOrCreateLoop(unorderedLoops, methodScope.loopExplosionHead);
NodeBitMap visited = graph.createNodeBitMap();
NodeBitMap active = graph.createNodeBitMap();
Deque<Node> stack = new ArrayDeque<>();
visited.mark(methodScope.loopExplosionHead);
stack.push(methodScope.loopExplosionHead);
while (!stack.isEmpty()) {
Node current = stack.peek();
assert visited.isMarked(current);
if (active.isMarked(current)) {
/* We are back-tracking, i.e., all successor nodes have been processed. */
stack.pop();
active.clear(current);
if (current instanceof MergeNode) {
Loop loop = unorderedLoops.get((MergeNode) current);
if (loop != null) {
/*
* Since nodes are popped in reverse order that they were pushed, we add
* inner loops before outer loops here.
*/
assert !orderedLoops.contains(loop);
orderedLoops.add(loop);
}
}
} else {
/*
* Process the node. Note that we do not remove the node from the stack, i.e., we
* will peek it again. But the next time the node is marked as active, so we do not
* execute this code again.
*/
active.mark(current);
for (Node successor : current.cfgSuccessors()) {
if (active.isMarked(successor)) {
/* Detected a cycle, i.e., a backward branch of a loop. */
Loop loop = findOrCreateLoop(unorderedLoops, (MergeNode) successor);
assert !loop.ends.contains(current);
loop.ends.add((EndNode) current);
} else if (visited.isMarked(successor)) {
/* Forward merge into a branch we are already exploring. */
} else {
/* Forward branch to a node we have not seen yet. */
visited.mark(successor);
stack.push(successor);
}
}
}
}
return orderedLoops;
}
use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class LoopDetector method findLoopExits.
private void findLoopExits(Loop loop) {
/*
* Backward marking of loop nodes: Starting with the known loop ends, we mark all nodes that
* are reachable until we hit the loop begin. All successors of loop nodes that are not
* marked as loop nodes themselves are exits of the loop. We mark all successors, and then
* subtract the loop nodes, to find the exits.
*/
List<Node> possibleExits = new ArrayList<>();
NodeBitMap visited = graph.createNodeBitMap();
Deque<Node> stack = new ArrayDeque<>();
for (EndNode loopEnd : loop.ends) {
stack.push(loopEnd);
visited.mark(loopEnd);
}
while (!stack.isEmpty()) {
Node current = stack.pop();
if (current == loop.header) {
continue;
}
if (!graph.isNew(methodScope.methodStartMark, current)) {
/*
* The current node is before the method that contains the exploded loop. The loop
* must have a second entry point, i.e., it is an irreducible loop.
*/
loop.irreducible = true;
return;
}
for (Node predecessor : current.cfgPredecessors()) {
if (predecessor instanceof LoopExitNode) {
/*
* Inner loop. We do not need to mark every node of it, instead we just continue
* marking at the loop header.
*/
LoopBeginNode innerLoopBegin = ((LoopExitNode) predecessor).loopBegin();
if (!visited.isMarked(innerLoopBegin)) {
stack.push(innerLoopBegin);
visited.mark(innerLoopBegin);
/*
* All loop exits of the inner loop possibly need a LoopExit of our loop.
* Because we are processing inner loops first, we are guaranteed to already
* have all exits of the inner loop.
*/
for (LoopExitNode exit : innerLoopBegin.loopExits()) {
possibleExits.add(exit);
}
}
} else if (!visited.isMarked(predecessor)) {
stack.push(predecessor);
visited.mark(predecessor);
if (predecessor instanceof ControlSplitNode) {
for (Node succ : predecessor.cfgSuccessors()) {
/*
* We would not need to mark the current node, and would not need to
* mark visited nodes. But it is easier to just mark everything, since
* we subtract all visited nodes in the end anyway. Note that at this
* point we do not have the complete visited information, so we would
* always mark too many possible exits.
*/
possibleExits.add(succ);
}
}
}
}
}
/*
* Now we know all the actual loop exits. Ideally, we would insert LoopExit nodes for them.
* However, a LoopExit needs a valid FrameState that captures the state at the point where
* we exit the loop. During graph decoding, we create a FrameState for every exploded loop
* iteration. We need to do a forward marking until we hit the next such point. This puts
* some nodes into the loop that are actually not part of the loop.
*
* In some cases, we did not create a FrameState during graph decoding: when there was no
* LoopExit in the original loop that we exploded. This happens for code paths that lead
* immediately to a DeoptimizeNode.
*
* Both cases mimic the behavior of the BytecodeParser, which also puts more nodes than
* necessary into a loop because it computes loop information based on bytecodes, before the
* actual parsing.
*/
for (Node succ : possibleExits) {
if (!visited.contains(succ)) {
stack.push(succ);
visited.mark(succ);
assert !methodScope.loopExplosionMerges.contains(succ);
}
}
while (!stack.isEmpty()) {
Node current = stack.pop();
assert visited.isMarked(current);
assert current instanceof ControlSinkNode || current instanceof LoopEndNode || current.cfgSuccessors().iterator().hasNext() : "Must not reach a node that has not been decoded yet";
for (Node successor : current.cfgSuccessors()) {
if (visited.isMarked(successor)) {
/* Already processed this successor. */
} else if (methodScope.loopExplosionMerges.contains(successor)) {
/*
* We have a FrameState for the successor. The LoopExit will be inserted between
* the current node and the successor node. Since the successor node is a
* MergeNode, the current node mus be a AbstractEndNode with only that MergeNode
* as the successor.
*/
assert successor instanceof MergeNode;
assert !loop.exits.contains(current);
loop.exits.add((AbstractEndNode) current);
} else {
/* Node we have not seen yet. */
visited.mark(successor);
stack.push(successor);
}
}
}
}
use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class LoopFragment method computeNodes.
protected static NodeBitMap computeNodes(Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
final NodeBitMap nodes = graph.createNodeBitMap();
computeNodes(nodes, graph, blocks, earlyExits);
return nodes;
}
use of org.graalvm.compiler.graph.NodeBitMap in project graal by oracle.
the class LoopFragment method patchNodes.
protected void patchNodes(final DuplicationReplacement dataFix) {
if (isDuplicate() && !nodesReady) {
assert !original.isDuplicate();
final DuplicationReplacement cfgFix = original().getDuplicationReplacement();
DuplicationReplacement dr;
if (cfgFix == null && dataFix != null) {
dr = dataFix;
} else if (cfgFix != null && dataFix == null) {
dr = cfgFix;
} else if (cfgFix != null && dataFix != null) {
dr = new DuplicationReplacement() {
@Override
public Node replacement(Node o) {
Node r1 = dataFix.replacement(o);
if (r1 != o) {
assert cfgFix.replacement(o) == o;
return r1;
}
Node r2 = cfgFix.replacement(o);
if (r2 != o) {
return r2;
}
return o;
}
};
} else {
dr = null;
}
beforeDuplication();
NodeIterable<Node> nodesIterable = original().nodes();
duplicationMap = graph().addDuplicates(nodesIterable, graph(), nodesIterable.count(), dr);
finishDuplication();
nodes = new NodeBitMap(graph());
nodes.markAll(duplicationMap.getValues());
nodesReady = true;
} else {
// TODO (gd) apply fix ?
}
}
Aggregations