use of org.graalvm.compiler.nodes.LoopBeginNode in project graal by oracle.
the class GraphOrder method assertSchedulableGraph.
/**
* This method schedules the graph and makes sure that, for every node, all inputs are available
* at the position where it is scheduled. This is a very expensive assertion.
*/
public static boolean assertSchedulableGraph(final StructuredGraph graph) {
assert graph.getGuardsStage() != GuardsStage.AFTER_FSA : "Cannot use the BlockIteratorClosure after FrameState Assignment, HIR Loop Data Structures are no longer valid.";
try {
final SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST_OUT_OF_LOOPS, true);
final EconomicMap<LoopBeginNode, NodeBitMap> loopEntryStates = EconomicMap.create(Equivalence.IDENTITY);
schedulePhase.apply(graph, false);
final ScheduleResult schedule = graph.getLastSchedule();
BlockIteratorClosure<NodeBitMap> closure = new BlockIteratorClosure<NodeBitMap>() {
@Override
protected List<NodeBitMap> processLoop(Loop<Block> loop, NodeBitMap initialState) {
return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
}
@Override
protected NodeBitMap processBlock(final Block block, final NodeBitMap currentState) {
final List<Node> list = graph.getLastSchedule().getBlockToNodesMap().get(block);
/*
* A stateAfter is not valid directly after its associated state split, but
* right before the next fixed node. Therefore a pending stateAfter is kept that
* will be checked at the correct position.
*/
FrameState pendingStateAfter = null;
for (final Node node : list) {
if (node instanceof ValueNode) {
FrameState stateAfter = node instanceof StateSplit ? ((StateSplit) node).stateAfter() : null;
if (node instanceof FullInfopointNode) {
stateAfter = ((FullInfopointNode) node).getState();
}
if (pendingStateAfter != null && node instanceof FixedNode) {
pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
@Override
public void apply(Node usage, Node nonVirtualNode) {
assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode + " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list;
}
});
pendingStateAfter = null;
}
if (node instanceof AbstractMergeNode) {
// phis aren't scheduled, so they need to be added explicitly
currentState.markAll(((AbstractMergeNode) node).phis());
if (node instanceof LoopBeginNode) {
// remember the state at the loop entry, it's restored at exits
loopEntryStates.put((LoopBeginNode) node, currentState.copy());
}
} else if (node instanceof ProxyNode) {
assert false : "proxy nodes should not be in the schedule";
} else if (node instanceof LoopExitNode) {
if (graph.hasValueProxies()) {
for (ProxyNode proxy : ((LoopExitNode) node).proxies()) {
for (Node input : proxy.inputs()) {
if (input != proxy.proxyPoint()) {
assert currentState.isMarked(input) : input + " not available at " + proxy + " in block " + block + "\n" + list;
}
}
}
// loop contents are only accessible via proxies at the exit
currentState.clearAll();
currentState.markAll(loopEntryStates.get(((LoopExitNode) node).loopBegin()));
}
// Loop proxies aren't scheduled, so they need to be added
// explicitly
currentState.markAll(((LoopExitNode) node).proxies());
} else {
for (Node input : node.inputs()) {
if (input != stateAfter) {
if (input instanceof FrameState) {
((FrameState) input).applyToNonVirtual(new VirtualState.NodeClosure<Node>() {
@Override
public void apply(Node usage, Node nonVirtual) {
assert currentState.isMarked(nonVirtual) : nonVirtual + " not available at " + node + " in block " + block + "\n" + list;
}
});
} else {
assert currentState.isMarked(input) || input instanceof VirtualObjectNode || input instanceof ConstantNode : input + " not available at " + node + " in block " + block + "\n" + list;
}
}
}
}
if (node instanceof AbstractEndNode) {
AbstractMergeNode merge = ((AbstractEndNode) node).merge();
for (PhiNode phi : merge.phis()) {
ValueNode phiValue = phi.valueAt((AbstractEndNode) node);
assert phiValue == null || currentState.isMarked(phiValue) || phiValue instanceof ConstantNode : phiValue + " not available at phi " + phi + " / end " + node + " in block " + block;
}
}
if (stateAfter != null) {
assert pendingStateAfter == null;
pendingStateAfter = stateAfter;
}
currentState.mark(node);
}
}
if (pendingStateAfter != null) {
pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
@Override
public void apply(Node usage, Node nonVirtualNode) {
assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode + " not available at virtualstate " + usage + " at end of block " + block + " \n" + list;
}
});
}
return currentState;
}
@Override
protected NodeBitMap merge(Block merge, List<NodeBitMap> states) {
NodeBitMap result = states.get(0);
for (int i = 1; i < states.size(); i++) {
result.intersect(states.get(i));
}
return result;
}
@Override
protected NodeBitMap getInitialState() {
NodeBitMap ret = graph.createNodeBitMap();
ret.markAll(graph.getNodes().filter(ConstantNode.class));
return ret;
}
@Override
protected NodeBitMap cloneState(NodeBitMap oldState) {
return oldState.copy();
}
};
ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
} catch (Throwable t) {
graph.getDebug().handle(t);
}
return true;
}
use of org.graalvm.compiler.nodes.LoopBeginNode 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.nodes.LoopBeginNode 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.LoopBeginNode in project graal by oracle.
the class ReentrantNodeIterator method apply.
private static <StateT> EconomicMap<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, LoopBeginNode boundary) {
assert start != null;
Deque<AbstractBeginNode> nodeQueue = new ArrayDeque<>();
EconomicMap<FixedNode, StateT> blockEndStates = EconomicMap.create(Equivalence.IDENTITY);
StateT state = initialState;
FixedNode current = start;
do {
while (current instanceof FixedWithNextNode) {
if (boundary != null && current instanceof LoopExitNode && ((LoopExitNode) current).loopBegin() == boundary) {
blockEndStates.put(current, state);
current = null;
} else {
FixedNode next = ((FixedWithNextNode) current).next();
state = closure.processNode(current, state);
current = closure.continueIteration(state) ? next : null;
}
}
if (current != null) {
state = closure.processNode(current, state);
if (closure.continueIteration(state)) {
Iterator<Node> successors = current.successors().iterator();
if (!successors.hasNext()) {
if (current instanceof LoopEndNode) {
blockEndStates.put(current, state);
} else if (current instanceof EndNode) {
// add the end node and see if the merge is ready for processing
AbstractMergeNode merge = ((EndNode) current).merge();
if (merge instanceof LoopBeginNode) {
EconomicMap<LoopExitNode, StateT> loopExitState = closure.processLoop((LoopBeginNode) merge, state);
MapCursor<LoopExitNode, StateT> entry = loopExitState.getEntries();
while (entry.advance()) {
blockEndStates.put(entry.getKey(), entry.getValue());
nodeQueue.add(entry.getKey());
}
} else {
boolean endsVisited = true;
for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
if (forwardEnd != current && !blockEndStates.containsKey(forwardEnd)) {
endsVisited = false;
break;
}
}
if (endsVisited) {
ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
for (int i = 0; i < merge.forwardEndCount(); i++) {
AbstractEndNode forwardEnd = merge.forwardEndAt(i);
assert forwardEnd == current || blockEndStates.containsKey(forwardEnd);
StateT other = forwardEnd == current ? state : blockEndStates.removeKey(forwardEnd);
states.add(other);
}
state = closure.merge(merge, states);
current = closure.continueIteration(state) ? merge : null;
continue;
} else {
assert !blockEndStates.containsKey(current);
blockEndStates.put(current, state);
}
}
}
} else {
FixedNode firstSuccessor = (FixedNode) successors.next();
if (!successors.hasNext()) {
current = firstSuccessor;
continue;
} else {
do {
AbstractBeginNode successor = (AbstractBeginNode) successors.next();
StateT successorState = closure.afterSplit(successor, state);
if (closure.continueIteration(successorState)) {
blockEndStates.put(successor, successorState);
nodeQueue.add(successor);
}
} while (successors.hasNext());
state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state);
current = closure.continueIteration(state) ? firstSuccessor : null;
continue;
}
}
}
}
// get next queued block
if (nodeQueue.isEmpty()) {
return blockEndStates;
} else {
current = nodeQueue.removeFirst();
assert blockEndStates.containsKey(current);
state = blockEndStates.removeKey(current);
assert !(current instanceof AbstractMergeNode) && current instanceof AbstractBeginNode;
}
} while (true);
}
use of org.graalvm.compiler.nodes.LoopBeginNode in project graal by oracle.
the class SinglePassNodeIterator method finishLoopEnds.
/**
* Once all loop-end-nodes for a given loop-node have been visited.
* <ul>
* <li>the state for that loop-node is updated based on the states of the loop-end-nodes</li>
* <li>entries in {@link #nodeStates} are pruned for the loop (they aren't going to be looked up
* again, anyway)</li>
* </ul>
*
* <p>
* The entries removed by this method were inserted:
* <ul>
* <li>for the loop-begin, by {@link #apply()}</li>
* <li>for loop-ends, by (previous) invocations of this method</li>
* </ul>
* </p>
*/
private void finishLoopEnds(LoopEndNode end) {
assert !visitedEnds.isMarked(end);
visitedEnds.mark(end);
keepForLater(end, state);
LoopBeginNode begin = end.loopBegin();
boolean endsVisited = true;
for (LoopEndNode le : begin.loopEnds()) {
if (!visitedEnds.isMarked(le)) {
endsVisited = false;
break;
}
}
if (endsVisited) {
ArrayList<T> states = new ArrayList<>(begin.loopEnds().count());
for (LoopEndNode le : begin.orderedLoopEnds()) {
T leState = pruneEntry(le);
states.add(leState);
}
T loopBeginState = pruneEntry(begin);
loopBeginState.loopEnds(begin, states);
}
}
Aggregations