changeset 19619:711f46f691cf

New bytecode interpreter partial evaluation test including an IFZERO bytecode. Make graph builder loop explosion support multiple loop back edges from one peeling iteration.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 27 Feb 2015 13:54:30 +0100
parents 98d7ecef3657
children d4c47c9d8ae4
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java
diffstat 6 files changed, 114 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- 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<Integer> canonicalId = graph.createNodeMap();
--- 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;
--- 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);
 
--- 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));
+    }
 }
--- 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) {
--- 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);