changeset 13348:b1712d10c8ef

moved loads of constants out of loops
author Doug Simon <doug.simon@oracle.com>
date Mon, 16 Dec 2013 13:23:33 +0100
parents e3b0608d6ab8
children 3ce69f7364a7
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CommonedConstantsTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java
diffstat 2 files changed, 94 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CommonedConstantsTest.java	Mon Dec 16 10:44:34 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CommonedConstantsTest.java	Mon Dec 16 13:23:33 2013 +0100
@@ -27,6 +27,7 @@
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * Tests any optimization that commons loads of non-inlineable constants.
@@ -37,7 +38,7 @@
 
     // A method where a constant is used on the normal and exception edge of a non-inlined call.
     // The dominating block of both usages is the block containing the call.
-    public static Object testSnippet(String[] arr, int i) {
+    public static Object test0Snippet(String[] arr, int i) {
         Object result = null;
         try {
             result = Array.get(arr, i);
@@ -53,13 +54,70 @@
     @Test
     public void test0() {
         // Ensure the exception path is profiled
-        ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(getMethod("testSnippet"));
+        ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(getMethod("test0Snippet"));
         javaMethod.reprofile();
-        testSnippet(array, array.length);
+        test0Snippet(array, array.length);
+
+        test("test0Snippet", array, 0);
+        test("test0Snippet", array, 2);
+        test("test0Snippet", array, 3);
+        test("test0Snippet", array, 1);
+    }
+
+    public static final char[] alphabet = "abcdefghijklmnopqrstuvwxyz".toCharArray();
+
+    static int noninlineLength(char[] s) {
+        return s.length;
+    }
+
+    /**
+     * A constant with usages before and after a non-inlined call.
+     */
+    public static int test1Snippet(String s) {
+        if (s == null) {
+            return noninlineLength(alphabet) + 1;
+        }
+        char[] sChars = s.toCharArray();
+        int count = 0;
+        for (int i = 0; i < alphabet.length && i < sChars.length; i++) {
+            if (alphabet[i] == sChars[i]) {
+                count++;
+            }
+        }
+        return count;
+    }
 
-        test("testSnippet", array, 0);
-        test("testSnippet", array, 2);
-        test("testSnippet", array, 3);
-        test("testSnippet", array, 1);
+    @Test
+    public void test1() {
+        getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
+        test1Snippet(new String(alphabet));
+
+        test("test1Snippet", (Object) null);
+        test("test1Snippet", "test1Snippet");
+        test("test1Snippet", "");
+    }
+
+    /**
+     * A constant with only usage in a loop.
+     */
+    public static int test2Snippet(String s) {
+        char[] sChars = s.toCharArray();
+        int count = 0;
+        for (int i = 0; i < alphabet.length && i < sChars.length; i++) {
+            if (alphabet[i] == sChars[i]) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    @Test
+    public void test2() {
+        assert getSuites().getHighTier().findPhase(AbstractInliningPhase.class).hasNext();
+        test2Snippet(new String(alphabet));
+
+        test("test2Snippet", (Object) null);
+        test("test2Snippet", "test1Snippet");
+        test("test2Snippet", "");
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Dec 16 10:44:34 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Dec 16 13:23:33 2013 +0100
@@ -28,6 +28,7 @@
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
+import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
 import java.util.Map.Entry;
@@ -39,10 +40,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.JumpOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
@@ -136,6 +134,19 @@
         public String toString() {
             return block + "#" + op;
         }
+
+        /**
+         * Removes the {@link #op} from its original location if it is still at that location.
+         */
+        public void unpin(LIR lir) {
+            if (index >= 0) {
+                // Replace the move with a filler op so that the operation
+                // list does not need to be adjusted.
+                List<LIRInstruction> instructions = lir.lir(block);
+                instructions.set(index, new NoOp(null, -1));
+                index = -1;
+            }
+        }
     }
 
     private Map<Constant, LoadConstant> constantLoads;
@@ -261,7 +272,6 @@
                     LoadConstant load = constantLoads.get(value);
                     if (load == null) {
                         int index = lir.lir(currentBlock).size();
-                        // loadedValue = newVariable(value.getPlatformKind());
                         loadedValue = emitMove(value);
                         LIRInstruction op = lir.lir(currentBlock).get(index);
                         constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op));
@@ -269,13 +279,7 @@
                         Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock);
                         loadedValue = load.variable;
                         if (dominator != load.block) {
-                            if (load.index >= 0) {
-                                // Replace the move with a filler op so that the operation
-                                // list does not need to be adjusted.
-                                List<LIRInstruction> instructions = lir.lir(load.block);
-                                instructions.set(load.index, new NoOp(null, -1));
-                                load.index = -1;
-                            }
+                            load.unpin(lir);
                         } else {
                             assert load.block != currentBlock || load.index < lir.lir(currentBlock).size();
                         }
@@ -883,6 +887,19 @@
             // Remove loads where all usages are in the same block.
             for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) {
                 LoadConstant lc = iter.next().getValue();
+
+                // Move loads of constant outside of loops
+                if (OptScheduleOutOfLoops.getValue()) {
+                    Block outOfLoopDominator = lc.block;
+                    while (outOfLoopDominator.getLoop() != null) {
+                        outOfLoopDominator = outOfLoopDominator.getDominator();
+                    }
+                    if (outOfLoopDominator != lc.block) {
+                        lc.unpin(lir);
+                        lc.block = outOfLoopDominator;
+                    }
+                }
+
                 if (lc.index != -1) {
                     assert lir.lir(lc.block).get(lc.index) == lc.op;
                     iter.remove();