# HG changeset patch # User Michael Van De Vanter # Date 1425156625 28800 # Node ID 3ed1c541f420e52131d4378f4f11af6d30236e1c # Parent ac35617db2397332152eb0db4eecc8518b3d5a2e# Parent 68dd6598be5f74970e7fc1a4a2fa4ccd166dbb11 Merge with 68dd6598be5f74970e7fc1a4a2fa4ccd166dbb11 diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java Sat Feb 28 12:50:25 2015 -0800 @@ -24,8 +24,6 @@ import java.util.*; -import com.oracle.graal.compiler.common.*; - public interface AbstractControlFlowGraph> { int BLOCK_ID_INITIAL = -1; @@ -73,26 +71,22 @@ * True if block {@code a} is dominated by block {@code b}. */ static boolean isDominatedBy(AbstractBlockBase a, AbstractBlockBase b) { - assert a != null; - AbstractBlockBase dominator = a; - int i = 0; - while (dominator != null) { - if (i++ == Integer.MAX_VALUE) { // For safety - throw GraalInternalError.shouldNotReachHere(); - } - if (dominator == b) { - return true; - } - dominator = dominator.getDominator(); + assert a != null && b != null; + if (a == b) { + return true; } - return false; + if (a.getDominatorDepth() < b.getDominatorDepth()) { + return false; + } + + return b == (AbstractBlockBase) a.getDominator(a.getDominatorDepth() - b.getDominatorDepth()); } /** * True if block {@code a} dominates block {@code b}. */ static boolean dominates(AbstractBlockBase a, AbstractBlockBase b) { - assert a != null; + assert a != null && b != null; return isDominatedBy(b, a); } diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sat Feb 28 12:50:25 2015 -0800 @@ -330,12 +330,179 @@ index = iterateBlock(blocks, block); } + if (this.mergeExplosions) { + Debug.dump(currentGraph, "Before loop detection"); + detectLoops(startInstruction); + } + if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue() && this.beforeReturnNode != startInstruction) { Debug.dump(currentGraph, "Bytecodes parsed: " + method.getDeclaringClass().getUnqualifiedName() + "." + method.getName()); } } } + private void detectLoops(FixedNode startInstruction) { + NodeBitMap visited = currentGraph.createNodeBitMap(); + NodeBitMap active = currentGraph.createNodeBitMap(); + Stack stack = new Stack<>(); + stack.add(startInstruction); + visited.mark(startInstruction); + while (!stack.isEmpty()) { + Node next = stack.peek(); + assert next.isDeleted() || visited.isMarked(next); + if (next.isDeleted() || active.isMarked(next)) { + stack.pop(); + if (!next.isDeleted()) { + active.clear(next); + } + } else { + active.mark(next); + for (Node n : next.cfgSuccessors()) { + if (active.contains(n)) { + // Detected cycle. + assert n instanceof MergeNode; + assert next instanceof EndNode; + MergeNode merge = (MergeNode) n; + EndNode endNode = (EndNode) next; + merge.removeEnd(endNode); + FixedNode afterMerge = merge.next(); + if (!(afterMerge instanceof EndNode) || !(((EndNode) afterMerge).merge() instanceof LoopBeginNode)) { + merge.setNext(null); + LoopBeginNode newLoopBegin = this.appendLoopBegin(merge); + newLoopBegin.setNext(afterMerge); + } + LoopBeginNode loopBegin = (LoopBeginNode) ((EndNode) merge.next()).merge(); + LoopEndNode loopEnd = currentGraph.add(new LoopEndNode(loopBegin)); + endNode.replaceAndDelete(loopEnd); + } else if (visited.contains(n)) { + // Normal merge into a branch we are already exploring. + } else { + visited.mark(n); + stack.push(n); + } + } + } + } + + Debug.dump(currentGraph, "After loops detected"); + insertLoopEnds(startInstruction); + } + + private void insertLoopEnds(FixedNode startInstruction) { + NodeBitMap visited = currentGraph.createNodeBitMap(); + Stack stack = new Stack<>(); + stack.add(startInstruction); + visited.mark(startInstruction); + List loopBegins = new ArrayList<>(); + while (!stack.isEmpty()) { + Node next = stack.pop(); + assert visited.isMarked(next); + if (next instanceof LoopBeginNode) { + loopBegins.add((LoopBeginNode) next); + } + for (Node n : next.cfgSuccessors()) { + if (visited.contains(n)) { + // Nothing to do. + } else { + visited.mark(n); + stack.push(n); + } + } + } + + IdentityHashMap> innerLoopsMap = new IdentityHashMap<>(); + for (int i = loopBegins.size() - 1; i >= 0; --i) { + LoopBeginNode loopBegin = loopBegins.get(i); + insertLoopExits(loopBegin, innerLoopsMap); + if (GraalOptions.DumpDuringGraphBuilding.getValue()) { + Debug.dump(currentGraph, "After building loop exits for %s.", loopBegin); + } + } + + // Remove degenerated merges with only one predecessor. + for (LoopBeginNode loopBegin : loopBegins) { + Node pred = loopBegin.forwardEnd().predecessor(); + if (pred instanceof MergeNode) { + MergeNode.removeMergeIfDegenerated((MergeNode) pred); + } + } + } + + private void insertLoopExits(LoopBeginNode loopBegin, IdentityHashMap> innerLoopsMap) { + NodeBitMap visited = currentGraph.createNodeBitMap(); + Stack stack = new Stack<>(); + for (LoopEndNode loopEnd : loopBegin.loopEnds()) { + stack.push(loopEnd); + visited.mark(loopEnd); + } + + List controlSplits = new ArrayList<>(); + List innerLoopBegins = new ArrayList<>(); + + while (!stack.isEmpty()) { + Node current = stack.pop(); + if (current == loopBegin) { + continue; + } + for (Node pred : current.cfgPredecessors()) { + if (!visited.isMarked(pred)) { + visited.mark(pred); + if (pred instanceof LoopExitNode) { + // Inner loop + LoopExitNode loopExitNode = (LoopExitNode) pred; + LoopBeginNode innerLoopBegin = loopExitNode.loopBegin(); + if (!visited.isMarked(innerLoopBegin)) { + stack.push(innerLoopBegin); + visited.mark(innerLoopBegin); + innerLoopBegins.add(innerLoopBegin); + } + } else { + if (pred instanceof ControlSplitNode) { + ControlSplitNode controlSplitNode = (ControlSplitNode) pred; + controlSplits.add(controlSplitNode); + } + stack.push(pred); + } + } + } + } + + for (ControlSplitNode controlSplit : controlSplits) { + for (Node succ : controlSplit.cfgSuccessors()) { + if (!visited.isMarked(succ)) { + LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin)); + FixedNode next = ((FixedWithNextNode) succ).next(); + next.replaceAtPredecessor(loopExit); + loopExit.setNext(next); + } + } + } + + for (LoopBeginNode inner : innerLoopBegins) { + addLoopExits(loopBegin, inner, innerLoopsMap, visited); + if (GraalOptions.DumpDuringGraphBuilding.getValue()) { + Debug.dump(currentGraph, "After adding loop exits for %s.", inner); + } + } + + innerLoopsMap.put(loopBegin, innerLoopBegins); + } + + private void addLoopExits(LoopBeginNode loopBegin, LoopBeginNode inner, IdentityHashMap> innerLoopsMap, NodeBitMap visited) { + for (LoopExitNode exit : inner.loopExits()) { + if (!visited.isMarked(exit)) { + LoopExitNode newLoopExit = currentGraph.add(new LoopExitNode(loopBegin)); + FixedNode next = exit.next(); + next.replaceAtPredecessor(newLoopExit); + newLoopExit.setNext(next); + } + } + + for (LoopBeginNode innerInner : innerLoopsMap.get(inner)) { + addLoopExits(loopBegin, innerInner, innerLoopsMap, visited); + } + } + private int iterateBlock(BciBlock[] blocks, BciBlock block) { if (block.isLoopHeader && this.explodeLoops) { return iterateExplodedLoopHeader(blocks, block); @@ -1501,7 +1668,7 @@ // time mark the context loop begin as hit during the current // iteration. if (this.mergeExplosions) { - this.addToMergeCache(state.copy(), nextPeelIteration); + this.addToMergeCache(state, nextPeelIteration); } context.targetPeelIteration[context.targetPeelIteration.length - 1] = nextPeelIteration++; if (nextPeelIteration > MaximumLoopExplosionCount.getValue()) { @@ -1712,11 +1879,7 @@ // Create the loop header block, which later will merge the backward branches of // the loop. controlFlowSplit = true; - EndNode preLoopEnd = currentGraph.add(new EndNode()); - LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode()); - lastInstr.setNext(preLoopEnd); - // Add the single non-loop predecessor of the loop header. - loopBegin.addForwardEnd(preLoopEnd); + LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr); lastInstr = loopBegin; // Create phi functions for all local variables and operand stack slots. @@ -1736,6 +1899,8 @@ setEntryState(block, this.getCurrentDimension(), frameState.copy()); Debug.log(" created loop header %s", loopBegin); + } else if (block.isLoopHeader && explodeLoops && this.mergeExplosions) { + frameState = frameState.copy(); } assert lastInstr.next() == null : "instructions already appended at block " + block; Debug.log(" frameState: %s", frameState); @@ -1804,6 +1969,15 @@ } } + private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) { + EndNode preLoopEnd = currentGraph.add(new EndNode()); + LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode()); + fixedWithNext.setNext(preLoopEnd); + // Add the single non-loop predecessor of the loop header. + loopBegin.addForwardEnd(preLoopEnd); + return loopBegin; + } + /** * A hook for derived classes to modify the last instruction or add other instructions. * diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Sat Feb 28 12:50:25 2015 -0800 @@ -175,13 +175,13 @@ negated = true; } LogicNode ifTest = ifNode.condition(); - if (!(ifTest instanceof IntegerLessThanNode)) { + if (!(ifTest instanceof IntegerLessThanNode) && !(ifTest instanceof IntegerEqualsNode)) { if (ifTest instanceof IntegerBelowNode) { Debug.log("Ignored potential Counted loop at %s with |<|", loopBegin); } return false; } - IntegerLessThanNode lessThan = (IntegerLessThanNode) ifTest; + CompareNode lessThan = (CompareNode) ifTest; Condition condition = null; InductionVariable iv = null; ValueNode limit = null; @@ -198,6 +198,9 @@ limit = lessThan.getY(); } } + if (iv != null && iv.isConstantStride() && iv.constantStride() != 1 && !(ifTest instanceof IntegerLessThanNode)) { + return false; + } if (condition == null) { return false; } @@ -206,6 +209,24 @@ } boolean oneOff = false; switch (condition) { + case EQ: + return false; + case NE: { + IntegerStamp initStamp = (IntegerStamp) iv.initNode().stamp(); + IntegerStamp limitStamp = (IntegerStamp) limit.stamp(); + if (iv.direction() == Direction.Up) { + if (initStamp.upperBound() > limitStamp.lowerBound()) { + return false; + } + } else { + assert iv.direction() == Direction.Down; + if (initStamp.lowerBound() < limitStamp.upperBound()) { + return false; + } + } + oneOff = true; + break; + } case LE: oneOff = true; // fall through case LT: diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Sat Feb 28 12:50:25 2015 -0800 @@ -36,4 +36,21 @@ public MergeNode() { super(TYPE); } + + public static void removeMergeIfDegenerated(MergeNode node) { + if (node.forwardEndCount() == 1 && node.hasNoUsages()) { + FixedNode currentNext = node.next(); + node.setNext(null); + EndNode forwardEnd = node.forwardEndAt(0); + forwardEnd.replaceAtPredecessor(currentNext); + node.markDeleted(); + forwardEnd.markDeleted(); + } + } + + @Override + public boolean verify() { + assertTrue(this.forwardEndCount() > 1, "Must merge more than one end."); + return true; + } } diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Sat Feb 28 12:50:25 2015 -0800 @@ -173,6 +173,7 @@ // First time we see this block: push all successors. for (Node suxNode : block.getEndNode().cfgSuccessors()) { Block suxBlock = blockFor(suxNode); + assert suxBlock != null : suxNode; if (suxBlock.getId() == BLOCK_ID_INITIAL) { stack.add(suxBlock); } diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Sat Feb 28 12:50:25 2015 -0800 @@ -322,11 +322,11 @@ @Override protected void run(StructuredGraph graph) { assert GraphOrder.assertNonCyclicGraph(graph); - cfg = ControlFlowGraph.compute(graph, true, true, true, true); + cfg = ControlFlowGraph.compute(graph, true, true, true, false); earliestCache = graph.createNodeMap(); blockToNodesMap = new BlockMap<>(cfg); - if (selectedStrategy != SchedulingStrategy.EARLIEST) { + if (selectedStrategy != SchedulingStrategy.EARLIEST && graph.isAfterFloatingReadPhase()) { blockToKillSet = new BlockMap<>(cfg); } @@ -359,7 +359,6 @@ for (Block b : getCFG().getBlocks()) { buf.format("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth()); buf.format("dom: %s. ", b.getDominator()); - buf.format("post-dom: %s. ", b.getPostdominator()); buf.format("preds: %s. ", b.getPredecessors()); buf.format("succs: %s ====%n", b.getSuccessors()); BlockMap killSets = blockToKillSet; @@ -1083,9 +1082,8 @@ addUnscheduledToLatestSorting(stateAfter, state); // Now predecessors and inputs are scheduled => we can add this node. - if (!state.containsInstruction(i)) { - state.addInstruction(i); - } + assert !state.containsInstruction(i); + state.addInstruction(i); if (state.readsSize() != 0 && i instanceof FloatingReadNode) { state.removeRead(i); diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java Sat Feb 28 12:50:25 2015 -0800 @@ -100,19 +100,19 @@ switch (bc) { case Bytecode.CONST: value = bytecodes[bci + 1]; - trace("%d: CONST %s", bci, value); + trace("%d (%d): CONST %s", bci, topOfStack, value); setInt(frame, ++topOfStack, value); bci = bci + 2; continue; case Bytecode.RETURN: - trace("%d: RETURN", bci); + trace("%d (%d): RETURN", bci, topOfStack); return getInt(frame, topOfStack); case Bytecode.ADD: { int left = getInt(frame, topOfStack); int right = getInt(frame, topOfStack - 1); - trace("%d: ADD %d %d", bci, left, right); + trace("%d (%d): ADD %d %d", bci, topOfStack, left, right); setInt(frame, topOfStack - 1, left + right); topOfStack--; bci = bci + 1; @@ -120,7 +120,7 @@ } case Bytecode.IFZERO: - trace("%d: IFZERO", bci); + trace("%d (%d): IFZERO", bci, topOfStack); if (getInt(frame, topOfStack--) == 0) { bci = bytecodes[bci + 1]; continue; @@ -130,18 +130,18 @@ } case Bytecode.POP: - trace("%d: POP", bci); + trace("%d (%d): POP", bci, topOfStack); topOfStack--; bci++; continue; case Bytecode.JMP: - trace("%d: JMP", bci); + trace("%d (%d): JMP", bci, topOfStack); bci = bytecodes[bci + 1]; continue; case Bytecode.DUP: - trace("%d: DUP", bci); + trace("%d (%d): DUP", bci, topOfStack); setInt(frame, topOfStack + 1, getInt(frame, topOfStack)); topOfStack++; bci++; @@ -217,7 +217,6 @@ } @Test - @Ignore public void simpleLoopProgram() { byte[] bytecodes = new byte[]{ /* 0: */Bytecode.CONST, @@ -234,7 +233,38 @@ /* 11: */4, /* 12: */Bytecode.POP, /* 13: */Bytecode.RETURN}; - assertPartialEvalEqualsAndRunsCorrect(new Program("ifAndPopProgram", bytecodes, 0, 3)); + assertPartialEvalEqualsAndRunsCorrect(new Program("simpleLoopProgram", bytecodes, 0, 3)); + } + + @Test + public void nestedLoopsProgram() { + byte[] bytecodes = new byte[]{ + /* 0: */Bytecode.CONST, + /* 1: */42, + /* 2: */Bytecode.CONST, + /* 3: */-2, + /* 4: */Bytecode.CONST, + /* 5: */1, + /* 6: */Bytecode.ADD, + /* 7: */Bytecode.DUP, + /* 8: */Bytecode.CONST, + /* 9: */-2, + /* 10: */Bytecode.CONST, + /* 11: */1, + /* 12: */Bytecode.ADD, + /* 13: */Bytecode.DUP, + /* 14: */Bytecode.IFZERO, + /* 15: */18, + /* 16: */Bytecode.JMP, + /* 17: */10, + /* 18: */Bytecode.POP, + /* 19: */Bytecode.IFZERO, + /* 20: */23, + /* 21: */Bytecode.JMP, + /* 22: */4, + /* 23: */Bytecode.POP, + /* 24: */Bytecode.RETURN}; + assertPartialEvalEqualsAndRunsCorrect(new Program("nestedLoopsProgram", bytecodes, 0, 6)); } @Test(timeout = 1000) diff -r ac35617db239 -r 3ed1c541f420 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Sat Feb 28 09:32:36 2015 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java Sat Feb 28 12:50:25 2015 -0800 @@ -30,6 +30,7 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; import com.oracle.graal.java.*; import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin; import com.oracle.graal.java.InvocationPlugins.Registration; @@ -198,7 +199,18 @@ if (curValue.isConstant()) { return true; } else { - throw builder.bailout("Partial evaluation did not reduce value to a constant, is a regular compiler node: " + curValue); + StringBuilder sb = new StringBuilder(); + sb.append(curValue); + if (curValue instanceof ValuePhiNode) { + ValuePhiNode valuePhi = (ValuePhiNode) curValue; + sb.append(" ("); + for (Node n : valuePhi.inputs()) { + sb.append(n); + sb.append("; "); + } + sb.append(")"); + } + throw builder.bailout("Partial evaluation did not reduce value to a constant, is a regular compiler node: " + sb.toString()); } } });