use of org.graalvm.compiler.nodes.LoopBeginNode in project graal by oracle.
the class BytecodeParser method appendLoopBegin.
@SuppressWarnings("try")
private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext, int startBci) {
try (DebugCloseable context = openNodeContext(frameState, startBci)) {
EndNode preLoopEnd = graph.add(new EndNode());
LoopBeginNode loopBegin = graph.add(new LoopBeginNode());
if (disableLoopSafepoint()) {
loopBegin.disableSafepoint();
}
fixedWithNext.setNext(preLoopEnd);
// Add the single non-loop predecessor of the loop header.
loopBegin.addForwardEnd(preLoopEnd);
return loopBegin;
}
}
use of org.graalvm.compiler.nodes.LoopBeginNode in project graal by oracle.
the class BytecodeParser method createTarget.
@SuppressWarnings("try")
private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
assert block != null && state != null;
assert !block.isExceptionEntry || state.stackSize() == 1;
try (DebugCloseable context = openNodeContext(state, block.startBci)) {
if (getFirstInstruction(block) == null) {
/*
* This is the first time we see this block as a branch target. Create and return a
* placeholder that later can be replaced with a MergeNode when we see this block
* again.
*/
FixedNode targetNode;
if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
setFirstInstruction(block, lastInstr);
lastInstr = null;
} else {
setFirstInstruction(block, graph.add(new BeginNode()));
}
targetNode = getFirstInstruction(block);
Target target = checkLoopExit(targetNode, block, state);
FixedNode result = target.fixed;
FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
setEntryState(block, currentEntryState);
currentEntryState.clearNonLiveLocals(block, liveness, true);
debug.log("createTarget %s: first visit, result: %s", block, targetNode);
return result;
}
// We already saw this block before, so we have to merge states.
if (!getEntryState(block).isCompatibleWith(state)) {
throw bailout("stacks do not match; bytecodes would not verify");
}
if (getFirstInstruction(block) instanceof LoopBeginNode) {
assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
/*
* Backward loop edge. We need to create a special LoopEndNode and merge with the
* loop begin node created before.
*/
LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block);
LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
Target target = checkLoopExit(loopEnd, block, state);
FixedNode result = target.fixed;
getEntryState(block).merge(loopBegin, target.state);
debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
return result;
}
assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block";
if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) {
/*
* This is the second time we see this block. Create the actual MergeNode and the
* End Node for the already existing edge.
*/
AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block);
// The EndNode for the already existing edge.
EndNode end = graph.add(new EndNode());
// The MergeNode that replaces the placeholder.
AbstractMergeNode mergeNode = graph.add(new MergeNode());
FixedNode next = beginNode.next();
if (beginNode.predecessor() instanceof ControlSplitNode) {
beginNode.setNext(end);
} else {
beginNode.replaceAtPredecessor(end);
beginNode.safeDelete();
}
mergeNode.addForwardEnd(end);
mergeNode.setNext(next);
setFirstInstruction(block, mergeNode);
}
AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block);
// The EndNode for the newly merged edge.
EndNode newEnd = graph.add(new EndNode());
Target target = checkLoopExit(newEnd, block, state);
FixedNode result = target.fixed;
getEntryState(block).merge(mergeNode, target.state);
mergeNode.addForwardEnd(newEnd);
debug.log("createTarget %s: merging state, result: %s", block, result);
return result;
}
}
use of org.graalvm.compiler.nodes.LoopBeginNode in project graal by oracle.
the class ControlFlowGraph method identifyBlocks.
/**
* Identify and connect blocks (including loop backward edges). Predecessors need to be in the
* order expected when iterating phi inputs.
*/
private void identifyBlocks() {
// Find all block headers.
int numBlocks = 0;
for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) {
Block block = new Block(begin);
identifyBlock(block);
numBlocks++;
}
// Compute reverse post order.
int count = 0;
NodeMap<Block> nodeMap = this.nodeToBlock;
Block[] stack = new Block[numBlocks];
int tos = 0;
Block startBlock = blockFor(graph.start());
stack[0] = startBlock;
startBlock.setPredecessors(Block.EMPTY_ARRAY);
do {
Block block = stack[tos];
int id = block.getId();
if (id == BLOCK_ID_INITIAL) {
// First time we see this block: push all successors.
FixedNode last = block.getEndNode();
if (last instanceof EndNode) {
EndNode endNode = (EndNode) last;
Block suxBlock = nodeMap.get(endNode.merge());
if (suxBlock.getId() == BLOCK_ID_INITIAL) {
stack[++tos] = suxBlock;
}
block.setSuccessors(new Block[] { suxBlock });
} else if (last instanceof IfNode) {
IfNode ifNode = (IfNode) last;
Block trueSucc = nodeMap.get(ifNode.trueSuccessor());
stack[++tos] = trueSucc;
Block falseSucc = nodeMap.get(ifNode.falseSuccessor());
stack[++tos] = falseSucc;
block.setSuccessors(new Block[] { trueSucc, falseSucc });
Block[] ifPred = new Block[] { block };
trueSucc.setPredecessors(ifPred);
falseSucc.setPredecessors(ifPred);
} else if (last instanceof LoopEndNode) {
LoopEndNode loopEndNode = (LoopEndNode) last;
block.setSuccessors(new Block[] { nodeMap.get(loopEndNode.loopBegin()) });
// Nothing to do push onto the stack.
} else if (last instanceof ControlSinkNode) {
block.setSuccessors(Block.EMPTY_ARRAY);
} else {
assert !(last instanceof AbstractEndNode) : "Algorithm only supports EndNode and LoopEndNode.";
int startTos = tos;
Block[] ifPred = new Block[] { block };
for (Node suxNode : last.successors()) {
Block sux = nodeMap.get(suxNode);
stack[++tos] = sux;
sux.setPredecessors(ifPred);
}
int suxCount = tos - startTos;
Block[] successors = new Block[suxCount];
System.arraycopy(stack, startTos + 1, successors, 0, suxCount);
block.setSuccessors(successors);
}
block.setId(BLOCK_ID_VISITED);
AbstractBeginNode beginNode = block.getBeginNode();
if (beginNode instanceof LoopBeginNode) {
computeLoopPredecessors(nodeMap, block, (LoopBeginNode) beginNode);
} else if (beginNode instanceof MergeNode) {
MergeNode mergeNode = (MergeNode) beginNode;
int forwardEndCount = mergeNode.forwardEndCount();
Block[] predecessors = new Block[forwardEndCount];
for (int i = 0; i < forwardEndCount; ++i) {
predecessors[i] = nodeMap.get(mergeNode.forwardEndAt(i));
}
block.setPredecessors(predecessors);
}
} else if (id == BLOCK_ID_VISITED) {
// Second time we see this block: All successors have been processed, so add block
// to result list. Can safely reuse the stack for this.
--tos;
count++;
int index = numBlocks - count;
stack[index] = block;
block.setId(index);
} else {
throw GraalError.shouldNotReachHere();
}
} while (tos >= 0);
// Compute reverse postorder and number blocks.
assert count == numBlocks : "all blocks must be reachable";
this.reversePostOrder = stack;
}
use of org.graalvm.compiler.nodes.LoopBeginNode in project graal by oracle.
the class ControlFlowGraph method computeLoopInformation.
private void computeLoopInformation() {
loops = new ArrayList<>();
if (graph.hasLoops()) {
Block[] stack = new Block[this.reversePostOrder.length];
for (Block block : reversePostOrder) {
AbstractBeginNode beginNode = block.getBeginNode();
if (beginNode instanceof LoopBeginNode) {
Loop<Block> parent = block.getLoop();
Loop<Block> loop = new HIRLoop(parent, loops.size(), block);
if (parent != null) {
parent.getChildren().add(loop);
}
loops.add(loop);
block.setLoop(loop);
loop.getBlocks().add(block);
LoopBeginNode loopBegin = (LoopBeginNode) beginNode;
for (LoopEndNode end : loopBegin.loopEnds()) {
Block endBlock = nodeToBlock.get(end);
computeLoopBlocks(endBlock, loop, stack, true);
}
if (graph.getGuardsStage() != GuardsStage.AFTER_FSA) {
for (LoopExitNode exit : loopBegin.loopExits()) {
Block exitBlock = nodeToBlock.get(exit);
assert exitBlock.getPredecessorCount() == 1;
computeLoopBlocks(exitBlock.getFirstPredecessor(), loop, stack, true);
loop.addExit(exitBlock);
}
// The following loop can add new blocks to the end of the loop's block
// list.
int size = loop.getBlocks().size();
for (int i = 0; i < size; ++i) {
Block b = loop.getBlocks().get(i);
for (Block sux : b.getSuccessors()) {
if (sux.getLoop() != loop) {
AbstractBeginNode begin = sux.getBeginNode();
if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
graph.getDebug().log(DebugContext.VERBOSE_LEVEL, "Unexpected loop exit with %s, including whole branch in the loop", sux);
computeLoopBlocks(sux, loop, stack, false);
}
}
}
}
}
}
}
}
/*
* Compute the loop exit blocks after FSA.
*/
if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) {
for (Block b : reversePostOrder) {
if (b.getLoop() != null) {
for (Block succ : b.getSuccessors()) {
// if the loop of the succ is a different one (or none)
if (b.getLoop() != succ.getLoop()) {
// and the succ loop is not a child loop of the curr one
if (succ.getLoop() == null) {
// we might exit multiple loops if b.loops is not a loop at depth 0
Loop<Block> curr = b.getLoop();
while (curr != null) {
curr.addExit(succ);
curr = curr.getParent();
}
} else {
/*
* succ also has a loop, might be a child loop
*
* if it is a child loop we do not exit a loop. if it is a loop
* different than b.loop and not a child loop it must be a parent
* loop, thus we exit all loops between b.loop and succ.loop
*
* if we exit multiple loops immediately after each other the
* bytecode parser might generate loop exit nodes after another and
* the CFG will identify them as separate blocks, we just take the
* first one and exit all loops at this one
*/
if (succ.getLoop().getParent() != b.getLoop()) {
assert succ.getLoop().getDepth() < b.getLoop().getDepth();
// b.loop must not be a transitive parent of succ.loop
assert !Loop.transitiveParentLoop(succ.getLoop(), b.getLoop());
Loop<Block> curr = b.getLoop();
while (curr != null && curr != succ.getLoop()) {
curr.addExit(succ);
curr = curr.getParent();
}
}
}
}
}
}
}
}
}
use of org.graalvm.compiler.nodes.LoopBeginNode in project graal by oracle.
the class GraphUtil method normalizeLoops.
/**
* Remove loop header without loop ends. This can happen with degenerated loops like this one:
*
* <pre>
* for (;;) {
* try {
* break;
* } catch (UnresolvedException iioe) {
* }
* }
* </pre>
*/
public static void normalizeLoops(StructuredGraph graph) {
boolean loopRemoved = false;
for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) {
if (begin.loopEnds().isEmpty()) {
assert begin.forwardEndCount() == 1;
graph.reduceDegenerateLoopBegin(begin);
loopRemoved = true;
} else {
normalizeLoopBegin(begin);
}
}
if (loopRemoved) {
/*
* Removing a degenerated loop can make non-loop phi functions unnecessary. Therefore,
* we re-check all phi functions and remove redundant ones.
*/
for (Node node : graph.getNodes()) {
if (node instanceof PhiNode) {
checkRedundantPhi((PhiNode) node);
}
}
}
}
Aggregations