changeset 17257:f735aa886cf6

Truffle: add new inlining tests; adapt tests for context sensitive inlining.
author Christian Humer <christian.humer@gmail.com>
date Mon, 29 Sep 2014 18:46:40 +0200
parents 88d5fd9e1a6c
children f1f7b796874f
files graal/com.oracle.graal.truffle.test/sl/TestInlining.sl graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive1.sl graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive2.sl graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLIsInlinedBuiltin.java
diffstat 5 files changed, 129 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInlining.sl	Mon Sep 29 18:46:40 2014 +0200
@@ -0,0 +1,20 @@
+/* 
+ * This tests that simple arithmetic gets inlined.
+ */
+function add(a, b) { 
+    return a + b;
+}
+
+
+function test() {
+    i = 0;
+    while (i < 100) {
+        i = add(i, 1);
+    }
+    return i;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test));
+    assertTrue(isInlined(test, test, add), "add is not inlined");
+}  
--- a/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl	Mon Sep 29 18:46:38 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl	Mon Sep 29 18:46:40 2014 +0200
@@ -19,8 +19,8 @@
 
 function main() {
     waitForOptimization(callUntilOptimized(test1));
-    assertTrue(isInlined(test1, inlinableFunction), "inlinableFunction is not inlined");
+    assertTrue(isInlined(test1, test1, inlinableFunction), "inlinableFunction is not inlined");
     
     waitForOptimization(callUntilOptimized(test2));
-    assertFalse(isInlined(test2, notInlinableFunction), "notInlinableFunction is inlined");
+    assertFalse(isInlined(test2, test2, notInlinableFunction), "notInlinableFunction is inlined");
 }  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive1.sl	Mon Sep 29 18:46:40 2014 +0200
@@ -0,0 +1,25 @@
+/* 
+ * Test recursive calls do not get inlined and do not crash.
+ */
+function fib(a) { 
+    if (a == 2 || a == 1) {
+        return 1;
+    }
+    return fib(a-1) + fib(a-2);
+}
+
+function test() {
+    i = 0;
+    sum = 0;
+    while (i < 100) {
+        sum = sum + fib(7);
+        i = i + 1;
+    }
+    return sum;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test));
+    assertTrue(isInlined(test, test, fib), "fib is not inlined");
+    assertFalse(isInlined(test, fib, fib), "fib -> fib is not inlined");
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningRecursive2.sl	Mon Sep 29 18:46:40 2014 +0200
@@ -0,0 +1,37 @@
+/* 
+ * Tests that indirect recursions are not inlined.
+ */
+function fib(a) { 
+    if (a == 2 || a == 1) {
+        return 1;
+    }
+    return call(fib, a-1) + call(fib, a-2) + call(void, 0);
+}
+
+function call(f, a) {
+    return f(a);
+}
+
+function void(a) {
+    return a;
+}
+
+function test() {
+    i = 0;
+    sum = 0;
+    while (i < 100) {
+        sum = sum + fib(7);
+        i = i + 1;
+    }
+    return sum;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test));
+    assertTrue(isInlined(test, test, fib), "not inlined: test -> fib");
+    if (getOption("TruffleContextSensitiveInlining")) {
+      assertTrue(isInlined(test, fib, call), "not inlined: fib -> call");
+      assertFalse(isInlined(test, call, fib), "inlined: call -> fib"); 
+      assertTrue(isInlined(test, call, void), "inlined: call -> void");
+    }
+}  
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLIsInlinedBuiltin.java	Mon Sep 29 18:46:38 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLIsInlinedBuiltin.java	Mon Sep 29 18:46:40 2014 +0200
@@ -40,28 +40,57 @@
 
     @Specialization
     @SlowPath
-    public Object isInlined(SLFunction parent, SLFunction inlinedFunction) {
-        boolean allFalse = true;
-        boolean allTrue = true;
-        for (OptimizedCallTarget parentTarget : findDuplicateCallTargets((OptimizedCallTarget) parent.getCallTarget())) {
-            Set<DirectCallNode> callNodes = findCallsTo(parentTarget.getRootNode(), (OptimizedCallTarget) inlinedFunction.getCallTarget());
-            for (DirectCallNode directCall : callNodes) {
-                if (directCall.isInlined()) {
-                    allFalse = false;
-                } else {
-                    allTrue = false;
-                }
+    public Object isInlined(SLFunction rootFunction, SLFunction parentFunction, SLFunction inlinedFunction) {
+        InliningTrace trace = new InliningTrace();
+
+        for (OptimizedCallTarget target : findDuplicateCallTargets((OptimizedCallTarget) rootFunction.getCallTarget())) {
+            if (target.isValid()) {
+                searchInlined(trace, target, new ArrayList<>(), parentFunction, inlinedFunction);
             }
         }
-        if (allFalse && allTrue) {
-            throw new AssertionError(String.format("No calls found from %s to %s .", parent, inlinedFunction));
-        } else if (!allFalse && !allTrue) {
-            throw new AssertionError(String.format("Some calls from %s to %s are inlined and some are not.", parent, inlinedFunction));
+
+        if (trace.allFalse && trace.allTrue) {
+            throw new AssertionError(String.format("No optimized calls found from %s to %s .", parentFunction, inlinedFunction));
+        } else if (!trace.allFalse && !trace.allTrue) {
+            throw new AssertionError(String.format("Some optimized calls from %s to %s are inlined and some are not.", parentFunction, inlinedFunction));
         }
-        if (allTrue) {
+        if (trace.allTrue) {
             return true;
         } else {
             return false;
         }
     }
+
+    private void searchInlined(InliningTrace trace, OptimizedCallTarget rootTarget, List<OptimizedDirectCallNode> stack, SLFunction parent, SLFunction inlinedFunction) {
+        OptimizedCallTarget root;
+        if (stack.isEmpty()) {
+            root = rootTarget;
+        } else {
+            root = stack.get(stack.size() - 1).getCurrentCallTarget();
+        }
+
+        for (OptimizedDirectCallNode callNode : root.getCallNodes()) {
+            stack.add(callNode);
+
+            boolean inlined = rootTarget.isInlined(stack);
+            if (callNode.getRootNode().getCallTarget() == parent.getCallTarget() && callNode.getCallTarget() == inlinedFunction.getCallTarget()) {
+                if (inlined) {
+                    trace.allFalse = false;
+                } else {
+                    trace.allTrue = false;
+                }
+            }
+
+            if (inlined) {
+                searchInlined(trace, rootTarget, stack, parent, inlinedFunction);
+            }
+
+            stack.remove(stack.size() - 1);
+        }
+    }
+
+    private static final class InliningTrace {
+        boolean allFalse = true;
+        boolean allTrue = true;
+    }
 }