# HG changeset patch # User Thomas Wuerthinger # Date 1425041670 -3600 # Node ID 711f46f691cfe6b2691a3b7e36d4f107fb891519 # Parent 98d7ecef365751a14ad7d05490a2e498d554308b New bytecode interpreter partial evaluation test including an IFZERO bytecode. Make graph builder loop explosion support multiple loop back edges from one peeling iteration. diff -r 98d7ecef3657 -r 711f46f691cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Fri Feb 27 13:54:05 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Fri Feb 27 13:54:30 2015 +0100 @@ -303,6 +303,7 @@ protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { SchedulePhase schedule = new SchedulePhase(); + schedule.setScheduleConstants(true); schedule.apply(graph); NodeMap canonicalId = graph.createNodeMap(); diff -r 98d7ecef3657 -r 711f46f691cf 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 Fri Feb 27 13:54:05 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Feb 27 13:54:30 2015 +0100 @@ -179,7 +179,7 @@ private static class ExplodedLoopContext { private BciBlock header; - private int targetPeelIteration; + private int[] targetPeelIteration; private int peelIteration; } @@ -342,12 +342,17 @@ ExplodedLoopContext context = new ExplodedLoopContext(); context.header = header; context.peelIteration = this.getCurrentDimension(); - context.targetPeelIteration = -1; explodeLoopsContext.push(context); if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) { Debug.dump(currentGraph, "before loop explosion dimension " + context.peelIteration); } + peelIteration(blocks, header, context); + explodeLoopsContext.pop(); + return header.loopEnd + 1; + } + + private void peelIteration(BciBlock[] blocks, BciBlock header, ExplodedLoopContext context) { while (true) { processBlock(this, header); @@ -356,20 +361,24 @@ iterateBlock(blocks, block); } - if (context.targetPeelIteration != -1) { + int[] targets = context.targetPeelIteration; + if (targets != null) { // We were reaching the backedge during explosion. Explode further. - context.peelIteration = context.targetPeelIteration; - context.targetPeelIteration = -1; - if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) { - Debug.dump(currentGraph, "next loop explosion iteration " + context.peelIteration); + for (int i = 0; i < targets.length; ++i) { + context.peelIteration = targets[i]; + context.targetPeelIteration = null; + if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) { + Debug.dump(currentGraph, "next loop explosion iteration " + context.peelIteration); + } + if (i < targets.length - 1) { + peelIteration(blocks, header, context); + } } } else { // We did not reach the backedge. Exit. break; } } - explodeLoopsContext.pop(); - return header.loopEnd + 1; } /** @@ -1457,23 +1466,27 @@ if (context.header == block) { // We have a hit on our current explosion context loop begin. - if (context.targetPeelIteration == -1) { - // This is the first hit => allocate a new dimension and at the same - // time mark the context loop begin as hit during the current - // iteration. - context.targetPeelIteration = nextPeelIteration++; - if (nextPeelIteration > MaximumLoopExplosionCount.getValue()) { - String message = "too many loop explosion interations - does the explosion not terminate for method " + method + "?"; - if (FailedLoopExplosionIsFatal.getValue()) { - throw new RuntimeException(message); - } else { - throw bailout(message); - } + if (context.targetPeelIteration == null) { + context.targetPeelIteration = new int[1]; + } else { + context.targetPeelIteration = Arrays.copyOf(context.targetPeelIteration, context.targetPeelIteration.length + 1); + } + + // This is the first hit => allocate a new dimension and at the same + // time mark the context loop begin as hit during the current + // iteration. + context.targetPeelIteration[context.targetPeelIteration.length - 1] = nextPeelIteration++; + if (nextPeelIteration > MaximumLoopExplosionCount.getValue()) { + String message = "too many loop explosion interations - does the explosion not terminate for method " + method + "?"; + if (FailedLoopExplosionIsFatal.getValue()) { + throw new RuntimeException(message); + } else { + throw bailout(message); } } // Operate on the target dimension. - return context.targetPeelIteration; + return context.targetPeelIteration[context.targetPeelIteration.length - 1]; } else if (block.getId() > context.header.getId() && block.getId() <= context.header.loopEnd) { // We hit the range of this context. return context.peelIteration; diff -r 98d7ecef3657 -r 711f46f691cf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Fri Feb 27 13:54:05 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Fri Feb 27 13:54:30 2015 +0100 @@ -211,7 +211,7 @@ if (context.getGraphBuilderSuite() != null) { context.getGraphBuilderSuite().apply(newGraph, context); } - assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite"; + assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite " + method + ", " + method.canBeInlined(); new DeadCodeEliminationPhase(Optional).apply(newGraph); diff -r 98d7ecef3657 -r 711f46f691cf 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 Fri Feb 27 13:54:05 2015 +0100 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java Fri Feb 27 13:54:30 2015 +0100 @@ -24,8 +24,9 @@ import org.junit.*; -import com.oracle.graal.truffle.test.nodes.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -35,6 +36,7 @@ public static final byte CONST = 0; public static final byte RETURN = 1; public static final byte ADD = 2; + public static final byte IFZERO = 3; } public static class Program extends RootNode { @@ -60,32 +62,54 @@ } } + protected void setInt(VirtualFrame frame, int stackIndex, int value) { + frame.setInt(stack[stackIndex], value); + } + + protected int getInt(VirtualFrame frame, int stackIndex) { + try { + return frame.getInt(stack[stackIndex]); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException("Error accessing stack slot " + stackIndex); + } + } + + @TruffleBoundary + public void print(String name, int value) { + System.out.println(name + "=" + value); + } + @Override @ExplodeLoop public Object execute(VirtualFrame frame) { int topOfStack = -1; int bci = 0; - try { - while (true) { - byte bc = bytecodes[bci]; - byte value = 0; - switch (bc) { - case Bytecode.CONST: - value = bytecodes[bci + 1]; - topOfStack = topOfStack + 1; - frame.setInt(stack[topOfStack], value); + while (true) { + CompilerAsserts.partialEvaluationConstant(bci); + byte bc = bytecodes[bci]; + byte value = 0; + switch (bc) { + case Bytecode.CONST: + value = bytecodes[bci + 1]; + setInt(frame, ++topOfStack, value); + bci = bci + 2; + break; + case Bytecode.RETURN: + return getInt(frame, topOfStack); + case Bytecode.ADD: + setInt(frame, topOfStack - 1, getInt(frame, topOfStack) + getInt(frame, topOfStack - 1)); + topOfStack--; + bci = bci + 1; + break; + case Bytecode.IFZERO: + if (getInt(frame, topOfStack--) == 0) { + bci = bytecodes[bci + 1]; + continue; + } else { bci = bci + 2; - break; - case Bytecode.RETURN: - return frame.getInt(stack[topOfStack]); - case Bytecode.ADD: - frame.setInt(stack[topOfStack - 1], frame.getInt(stack[topOfStack]) + frame.getInt(stack[topOfStack - 1])); - bci = bci + 1; - break; - } + continue; + } } - } catch (FrameSlotTypeException e) { - throw new IllegalStateException("Program is invalid at bytecode index " + bci); } } } @@ -96,13 +120,37 @@ @Test public void simpleProgram() { - byte[] bytecodes = new byte[]{Bytecode.CONST, 42, Bytecode.RETURN}; + byte[] bytecodes = new byte[]{ + /* 0: */Bytecode.CONST, + /* 1: */42, + /* 2: */Bytecode.RETURN}; assertPartialEvalEquals("constant42", new Program(bytecodes, 0, 2)); } @Test public void simpleProgramWithAdd() { - byte[] bytecodes = new byte[]{Bytecode.CONST, 40, Bytecode.CONST, 2, Bytecode.ADD, Bytecode.RETURN}; + byte[] bytecodes = new byte[]{ + /* 0: */Bytecode.CONST, + /* 1: */40, + /* 2: */Bytecode.CONST, + /* 3: */2, + /* 4: */Bytecode.ADD, + /* 5: */Bytecode.RETURN}; assertPartialEvalEquals("constant42", new Program(bytecodes, 0, 2)); } + + @Test + public void simpleProgramWithIf() { + byte[] bytecodes = new byte[]{ + /* 0: */Bytecode.CONST, + /* 1: */40, + /* 2: */Bytecode.CONST, + /* 3: */1, + /* 4: */Bytecode.IFZERO, + /* 5: */8, + /* 6: */Bytecode.CONST, + /* 7: */42, + /* 8: */Bytecode.RETURN}; + assertPartialEvalEquals("constant42", new Program(bytecodes, 0, 3)); + } } diff -r 98d7ecef3657 -r 711f46f691cf graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Feb 27 13:54:05 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Feb 27 13:54:30 2015 +0100 @@ -351,6 +351,13 @@ } } } + + if (!TruffleCompilerOptions.TruffleInlineAcrossTruffleBoundary.getValue()) { + // Do not inline across Truffle boundaries. + for (MethodCallTargetNode mct : graph.getNodes(MethodCallTargetNode.TYPE)) { + mct.invoke().setUseForInlining(false); + } + } } private void injectConstantCallTarget(final StructuredGraph graph, final OptimizedCallTarget constantCallTarget, PhaseContext baseContext) { diff -r 98d7ecef3657 -r 711f46f691cf graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Feb 27 13:54:05 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Feb 27 13:54:30 2015 +0100 @@ -140,13 +140,6 @@ return; } - if (!TruffleCompilerOptions.TruffleInlineAcrossTruffleBoundary.getValue()) { - // Do not inline across Truffle boundaries. - for (MethodCallTargetNode mct : graph.getNodes(MethodCallTargetNode.TYPE)) { - mct.invoke().setUseForInlining(false); - } - } - compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph); CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable); compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);