changeset 3014:681a227c332b

better inlining logic, DCE removes If with constant comparison
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 17 Jun 2011 17:30:35 +0200
parents 5ee0f57bb18c
children 02a3d70f6fc0 1745543369ae
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Condition.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethodResolvedImpl.java src/share/vm/graal/graalVMEntries.cpp
diffstat 5 files changed, 122 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Condition.java	Fri Jun 17 14:58:03 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Condition.java	Fri Jun 17 17:30:35 2011 +0200
@@ -162,6 +162,7 @@
      */
     public Boolean foldCondition(CiConstant lt, CiConstant rt, RiRuntime runtime) {
         switch (lt.kind) {
+            case Boolean:
             case Int: {
                 int x = lt.asInt();
                 int y = rt.asInt();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java	Fri Jun 17 14:58:03 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java	Fri Jun 17 17:30:35 2011 +0200
@@ -29,6 +29,7 @@
 import com.oracle.max.graal.compiler.gen.*;
 import com.oracle.max.graal.compiler.ir.*;
 import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
 
 
 public class DeadCodeEliminationPhase extends Phase {
@@ -46,8 +47,25 @@
         // remove chained Merges
         for (Merge merge : graph.getNodes(Merge.class)) {
             if (merge.endCount() == 1 && merge.usages().size() == 0 && !(merge instanceof LoopEnd) && !(merge instanceof LoopBegin)) {
-                merge.endAt(0).replace(merge.next());
+                FixedNode next = merge.next();
+                EndNode endNode = merge.endAt(0);
                 merge.delete();
+                endNode.replace(next);
+            }
+        }
+        // remove if nodes with constant-value comparison
+        for (If ifNode : graph.getNodes(If.class)) {
+            Compare compare = ifNode.compare();
+            if (compare.x().isConstant() && compare.y().isConstant()) {
+                CiConstant constX = compare.x().asConstant();
+                CiConstant constY = compare.y().asConstant();
+                Boolean result = compare.condition().foldCondition(constX, constY, GraalCompilation.compilation().runtime);
+                if (result != null) {
+                    Node actualSuccessor = result ? ifNode.trueSuccessor() : ifNode.falseSuccessor();
+                    ifNode.replace(actualSuccessor);
+                } else {
+                    TTY.println("if not removed %s %s %s (%s %s)", constX, compare.condition(), constY, constX.kind, constY.kind);
+                }
             }
         }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Fri Jun 17 14:58:03 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Fri Jun 17 17:30:35 2011 +0200
@@ -66,44 +66,47 @@
         inliningSize = compilation.method.codeSize();
         for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) {
             for (Invoke invoke : graph.getNodes(Invoke.class)) {
-                RiTypeProfile profile = compilation.method.typeProfile(invoke.bci);
-                if (!checkInliningConditions(invoke)) {
+                RiMethod parent = parentMethod.get(invoke);
+                if (parent == null) {
+                    parent = compilation.method;
+                }
+                RiTypeProfile profile = parent.typeProfile(invoke.bci);
+                if (!checkInvokeConditions(invoke)) {
                     continue;
                 }
                 if (invoke.target.canBeStaticallyBound()) {
-                    if (checkInliningConditions(invoke.target, iterations, invoke, profile, ratio)) {
+                    if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) {
                         addToQueue(invoke, invoke.target);
                     }
                 } else {
                     RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
-                    if (concrete != null && concrete.isResolved() && checkInliningConditions(concrete, iterations, invoke, profile, ratio)) {
-                        if (trace) {
-                            String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false);
-                            String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false);
-                            TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName);
-                        }
-                        compilation.assumptions.recordConcreteMethod(invoke.target, concrete);
-                        addToQueue(invoke, concrete);
-                    } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) {
-                        if (!GraalOptions.InlineWithTypeCheck) {
-                            continue;
+                    if (concrete != null) {
+                        if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
+                            if (trace) {
+                                String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false);
+                                String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false);
+                                TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName);
+                            }
+                            compilation.assumptions.recordConcreteMethod(invoke.target, concrete);
+                            addToQueue(invoke, concrete);
                         }
-                        // type check and inlining...
-                        concrete = profile.types[0].resolveMethodImpl(invoke.target);
-                        if (concrete != null && concrete.isResolved() && checkInliningConditions(concrete, iterations, invoke, profile, ratio)) {
-                            IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph);
-                            FixedGuard guard = new FixedGuard(graph);
-                            guard.setNode(isType);
-                            assert invoke.predecessors().size() == 1;
-                            invoke.predecessors().get(0).successors().replace(invoke, guard);
-                            guard.setNext(invoke);
+                    } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) {
+                        if (GraalOptions.InlineWithTypeCheck) {
+                            // type check and inlining...
+                            concrete = profile.types[0].resolveMethodImpl(invoke.target);
+                            if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
+                                IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph);
+                                FixedGuard guard = new FixedGuard(graph);
+                                guard.setNode(isType);
+                                assert invoke.predecessors().size() == 1;
+                                invoke.predecessors().get(0).successors().replace(invoke, guard);
+                                guard.setNext(invoke);
 
-                            if (trace) {
-                                TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]);
+                                if (trace) {
+                                    TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]);
+                                }
+                                addToQueue(invoke, concrete);
                             }
-                            addToQueue(invoke, concrete);
-//                            System.out.println("inlining with type check " + profile.probabilities[0] + " " + profile.morphism + " " + profile.count);
-//                            System.out.println(invoke.target + " -> " + concrete + " (" + profile.types[0] + ")");
                         }
                     }
                 }
@@ -153,67 +156,100 @@
         }
     }
 
-    private boolean checkInliningConditions(Invoke invoke) {
-        String name = !trace ? null : invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false);
+    private String methodName(RiMethod method) {
+        return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
+    }
 
+    private String methodName(RiMethod method, Invoke invoke) {
+        if (invoke != null) {
+            RiMethod parent = parentMethod.get(invoke);
+            if (parent == null) {
+                parent = compilation.method;
+            }
+            return parent.name() + "@" + invoke.bci + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
+        } else {
+            return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
+        }
+    }
+
+    private boolean checkInvokeConditions(Invoke invoke) {
         if (invoke.stateAfter() == null) {
             if (trace) {
-                TTY.println("not inlining %s because the invoke has no after state", name);
+                TTY.println("not inlining %s because the invoke has no after state", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (invoke.stateAfter().locksSize() > 0) {
             if (trace) {
-                TTY.println("not inlining %s because of locks", name);
+                TTY.println("not inlining %s because of locks", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (!invoke.target.isResolved()) {
             if (trace) {
-                TTY.println("not inlining %s because the invoke target is unresolved", name);
+                TTY.println("not inlining %s because the invoke target is unresolved", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (invoke.predecessors().size() == 0) {
             if (trace) {
-                TTY.println("not inlining %s because the invoke is dead code", name);
+                TTY.println("not inlining %s because the invoke is dead code", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (invoke.stateAfter() == null) {
             if (trace) {
-                TTY.println("not inlining %s because of missing frame state", name);
+                TTY.println("not inlining %s because of missing frame state", methodName(invoke.target, invoke));
             }
         }
         return true;
     }
 
-    private boolean checkInliningConditions(RiMethod method, int iterations, Invoke invoke, RiTypeProfile profile, float adjustedRatio) {
-        String name = !trace ? null : CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
+    private boolean checkTargetConditions(RiMethod method, int iterations) {
+        if (!method.isResolved()) {
+            if (trace) {
+                TTY.println("not inlining %s because it is unresolved", methodName(method));
+            }
+            return false;
+        }
         if (Modifier.isNative(method.accessFlags())) {
             if (trace) {
-                TTY.println("not inlining %s because it is a native method", name);
+                TTY.println("not inlining %s because it is a native method", methodName(method));
             }
             return false;
         }
         if (Modifier.isAbstract(method.accessFlags())) {
             if (trace) {
-                TTY.println("not inlining %s because it is an abstract method", name);
+                TTY.println("not inlining %s because it is an abstract method", methodName(method));
             }
             return false;
         }
         if (!method.holder().isInitialized()) {
             if (trace) {
-                TTY.println("not inlining %s because of non-initialized class", name);
+                TTY.println("not inlining %s because of non-initialized class", methodName(method));
             }
             return false;
         }
         if (method == compilation.method && iterations > GraalOptions.MaximumRecursiveInlineLevel) {
             if (trace) {
-                TTY.println("not inlining %s because of recursive inlining limit", name);
+                TTY.println("not inlining %s because of recursive inlining limit", methodName(method));
             }
             return false;
         }
+        return true;
+    }
+
+    private boolean checkStaticSizeConditions(RiMethod method, Invoke invoke) {
+        if (method.codeSize() > GraalOptions.MaximumInlineSize) {
+            if (trace) {
+                TTY.println("not inlining %s because of code size (size: %d, max size: %d)", methodName(method, invoke), method.codeSize(), GraalOptions.MaximumInlineSize);
+            }
+            return false;
+        }
+        return true;
+    }
+
+    private boolean checkSizeConditions(RiMethod method, Invoke invoke, RiTypeProfile profile, float adjustedRatio) {
         int maximumSize = GraalOptions.MaximumTrivialSize;
         float ratio = 0;
         if (profile != null && profile.count > 0) {
@@ -230,15 +266,17 @@
         }
         if (method.codeSize() > maximumSize) {
             if (trace) {
-                TTY.println("not inlining %s because of code size (size: %d, max size: %d, ratio %5.3f)", name, method.codeSize(), maximumSize, ratio);
+                TTY.println("not inlining %s because of code size (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile);
             }
             return false;
         }
+        if (trace) {
+            TTY.println("inlining %s (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile);
+        }
         return true;
     }
 
     private void inlineMethod(Invoke invoke, RiMethod method) {
-        String name = !trace ? null : invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
         FrameState stateAfter = invoke.stateAfter();
         Instruction exceptionEdge = invoke.exceptionEdge();
 
@@ -246,12 +284,12 @@
         Object stored = GraphBuilderPhase.cachedGraphs.get(method);
         if (stored != null) {
             if (trace) {
-                TTY.println("Reusing graph for %s, locals: %d, stack: %d", name, method.maxLocals(), method.maxStackSize());
+                TTY.println("Reusing graph for %s, locals: %d, stack: %d", methodName(method, invoke), method.maxLocals(), method.maxStackSize());
             }
             graph = (CompilerGraph) stored;
         } else {
             if (trace) {
-                TTY.println("Building graph for %s, locals: %d, stack: %d", name, method.maxLocals(), method.maxStackSize());
+                TTY.println("Building graph for %s, locals: %d, stack: %d", methodName(method, invoke), method.maxLocals(), method.maxStackSize());
             }
             graph = new CompilerGraph(null);
             new GraphBuilderPhase(compilation, method, true, true).apply(graph);
@@ -299,7 +337,7 @@
         }
 
         if (trace) {
-            TTY.println("inlining %s: %d frame states, %d nodes", name, frameStates.size(), nodes.size());
+            TTY.println("inlining %s: %d frame states, %d nodes", methodName(method), frameStates.size(), nodes.size());
         }
 
         assert invoke.successors().get(0) != null : invoke;
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethodResolvedImpl.java	Fri Jun 17 14:58:03 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotMethodResolvedImpl.java	Fri Jun 17 17:30:35 2011 +0200
@@ -24,6 +24,7 @@
 
 import java.lang.reflect.*;
 
+import com.oracle.max.graal.compiler.debug.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
 
@@ -202,4 +203,19 @@
     public int branchProbability(int bci) {
         return compiler.getVMEntries().RiMethod_branchProbability(this, bci);
     }
+
+    public void dumpProfile() {
+        TTY.println("profile info for %s", this);
+        TTY.println("canBeStaticallyBound: " + canBeStaticallyBound());
+        TTY.println("invocationCount: " + invocationCount());
+        for (int i = 0; i < codeSize(); i++) {
+            if (branchProbability(i) != -1) {
+                TTY.println("branchProbability@%d: %d", i, branchProbability(i));
+            }
+            RiTypeProfile profile = typeProfile(i);
+            if (profile != null && profile.count > 0) {
+                TTY.println("profile@%d: count: %d, morphism: %d", i, profile.count, profile.morphism);
+            }
+        }
+    }
 }
--- a/src/share/vm/graal/graalVMEntries.cpp	Fri Jun 17 14:58:03 2011 +0200
+++ b/src/share/vm/graal/graalVMEntries.cpp	Fri Jun 17 17:30:35 2011 +0200
@@ -235,10 +235,10 @@
 
   jfloat probability = -1;
 
-  if (!method_data->is_mature()) return -1;
+  if (method_data == NULL || !method_data->is_mature()) return -1;
 
   ciProfileData* data = method_data->bci_to_data(bci);
-  if (!data->is_JumpData())  return -1;
+  if (data == NULL || !data->is_JumpData())  return -1;
 
   // get taken and not taken values
   int     taken = data->as_JumpData()->taken();