diff graal/GraalCompiler/src/com/sun/c1x/graph/IR.java @ 2842:7596ae867a7b

basic inlining passes all tests, including optimistic inlining
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 01 Jun 2011 16:26:17 +0200
parents 633e66de40fe
children a97605b0489b 7f14e6b48a9c
line wrap: on
line diff
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Wed Jun 01 16:26:17 2011 +0200
@@ -22,6 +22,7 @@
  */
 package com.sun.c1x.graph;
 
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.graph.*;
@@ -33,6 +34,8 @@
 import com.sun.c1x.lir.*;
 import com.sun.c1x.observer.*;
 import com.sun.c1x.value.*;
+import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
 
 /**
  * This class implements the overall container for the HIR (high-level IR) graph
@@ -161,12 +164,227 @@
 
     private void buildGraph() {
         // Graph builder must set the startBlock and the osrEntryBlock
-        new GraphBuilder(compilation, this, compilation.graph).build();
+        new GraphBuilder(compilation, compilation.method, compilation.graph).build();
 
         verifyAndPrint("After graph building");
 
+        List<Invoke> trivialInline = new ArrayList<Invoke>();
+        List<Invoke> deoptInline = new ArrayList<Invoke>();
+        List<RiMethod> deoptMethods = new ArrayList<RiMethod>();
+        for (Node node : compilation.graph.getNodes()) {
+            if (node instanceof Invoke) {
+                Invoke invoke = (Invoke) node;
+                RiMethod target = invoke.target;
+                if (target.isResolved() && !Modifier.isNative(target.accessFlags())) {
+                    if (target.canBeStaticallyBound()) {
+                        trivialInline.add(invoke);
+                    } else {
+                        RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
+                        if (concrete != null) {
+                            deoptInline.add(invoke);
+                            deoptMethods.add(concrete);
+                        }
+                    }
+                }
+            }
+        }
+
+        int allowedInlinings = 50;
+        for (Invoke invoke : trivialInline) {
+            if (inlineMethod(invoke, invoke.target)) {
+                if (--allowedInlinings <= 0) {
+                    break;
+                }
+            }
+        }
+
+        for (int i = 0; i < deoptInline.size(); i++) {
+            Invoke invoke = deoptInline.get(i);
+            RiMethod method = deoptMethods.get(i);
+            if (inlineMethod(invoke, method)) {
+                if (C1XOptions.TraceInlining) {
+                    System.out.println("registering concrete method assumption...");
+                }
+                compilation.assumptions.recordConcreteMethod(invoke.target, method);
+                if (--allowedInlinings <= 0) {
+                    break;
+                }
+            }
+        }
+
         if (C1XOptions.PrintCompilation) {
-            TTY.print(String.format("%3d blocks | ", this.numberOfBlocks()));
+            TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount));
+        }
+    }
+
+    private boolean inlineMethod(Invoke invoke, RiMethod method) {
+        String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)";
+
+        if (method.code().length > 50) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of code size");
+            }
+            return false;
+        }
+
+        Instruction exceptionEdge = invoke.exceptionEdge();
+        if (exceptionEdge != null) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of exceptionEdge");
+            }
+            return false;
+        }
+        if (!method.holder().isInitialized()) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of non-initialized class");
+            }
+            return false;
+        }
+
+        if (C1XOptions.TraceInlining) {
+            System.out.println("building graph: " + name);
+        }
+        CompilerGraph graph = new CompilerGraph();
+        new GraphBuilder(compilation, method, graph).build();
+
+        boolean withReceiver = !Modifier.isStatic(method.accessFlags());
+
+        int argumentCount = method.signature().argumentCount(false);
+        Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)];
+        int slot = withReceiver ? 1 : 0;
+        int param = withReceiver ? 1 : 0;
+        for (int i = 0; i < argumentCount; i++) {
+            parameters[param++] = invoke.argument(slot);
+            slot += method.signature().argumentKindAt(i).sizeInSlots();
+        }
+        if (withReceiver) {
+            parameters[0] = invoke.argument(0);
+        }
+
+        HashMap<Node, Node> replacements = new HashMap<Node, Node>();
+        ArrayList<Node> nodes = new ArrayList<Node>();
+        ArrayList<Node> frameStates = new ArrayList<Node>();
+        Return returnNode = null;
+        Unwind unwindNode = null;
+        StartNode startNode = null;
+        boolean invokes = false;
+        for (Node node : graph.getNodes()) {
+            if (node != null) {
+                if (node instanceof StartNode) {
+                    startNode = (StartNode) node;
+                } else if (node instanceof Local) {
+                    replacements.put(node, parameters[((Local) node).index()]);
+                } else {
+                    nodes.add(node);
+                    if (node instanceof Return) {
+                        returnNode = (Return) node;
+                    } else if (node instanceof Unwind) {
+                        unwindNode = (Unwind) node;
+                    } else if (node instanceof FrameState) {
+                        frameStates.add(node);
+                    }
+                }
+            }
+        }
+        if (unwindNode != null) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of unwind node");
+            }
+            return false;
+        }
+        if (invokes) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of invokes");
+            }
+            return false;
+        }
+
+        if (C1XOptions.TraceInlining) {
+            System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes");
+        }
+
+        Instruction pred;
+        if (withReceiver) {
+            pred = new NullCheck(parameters[0], compilation.graph);
+        } else {
+            pred = new Merge(compilation.graph);
+        }
+        assert invoke.predecessors().size() == 1;
+        invoke.predecessors().get(0).successors().replace(invoke, pred);
+        replacements.put(startNode, pred);
+
+        Map<Node, Node> duplicates = compilation.graph.addDuplicate(nodes, replacements);
+
+        if (returnNode != null) {
+            List<Node> usages = new ArrayList<Node>(invoke.usages());
+            for (Node usage : usages) {
+                if (returnNode.result() instanceof Local) {
+                    usage.inputs().replace(invoke, replacements.get(returnNode.result()));
+                } else {
+                    usage.inputs().replace(invoke, duplicates.get(returnNode.result()));
+                }
+            }
+            Node returnDuplicate = duplicates.get(returnNode);
+            returnDuplicate.inputs().clearAll();
+
+            assert returnDuplicate.predecessors().size() == 1;
+            Node returnPred = returnDuplicate.predecessors().get(0);
+            int index = returnDuplicate.predecessorsIndex().get(0);
+            returnPred.successors().setAndClear(index, invoke, 0);
+
+            returnDuplicate.delete();
+        }
+        FrameState stateAfter = invoke.stateAfter();
+        if (frameStates.size() > 0) {
+            FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind);
+            for (Node frameState : frameStates) {
+                ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState);
+            }
+        }
+
+        invoke.successors().clearAll();
+        invoke.inputs().clearAll();
+        invoke.delete();
+
+        stateAfter.delete();
+
+        deleteUnused(exceptionEdge);
+
+        verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false));
+        return true;
+    }
+
+    private void deleteUnused(Node node) {
+        if (node != null && node.predecessors().size() == 0) {
+            if (node instanceof ExceptionObject) {
+                Node successor = node.successors().get(0);
+                node.successors().clearAll();
+                if (successor instanceof ExceptionDispatch) {
+                    ExceptionDispatch dispatch = (ExceptionDispatch) successor;
+                    Node succ1 = dispatch.catchSuccessor();
+                    Node succ2 = dispatch.otherSuccessor();
+                    if (succ1 instanceof Merge) {
+                        ((Merge) succ1).removePhiPredecessor(dispatch);
+                    }
+                    if (succ2 instanceof Merge) {
+                        ((Merge) succ2).removePhiPredecessor(dispatch);
+                    }
+                    dispatch.successors().clearAll();
+                    deleteUnused(succ1);
+                    deleteUnused(succ2);
+                    dispatch.delete();
+                } else {
+                    assert successor instanceof Merge;
+                    System.out.println("succ: " + successor.successors().get(0));
+                    Node next = successor.successors().get(0);
+                    successor.successors().clearAll();
+                    deleteUnused(next);
+                    successor.delete();
+                }
+                node.delete();
+            } else if (node instanceof Unwind) {
+                node.delete();
+            }
         }
     }
 
@@ -202,15 +420,6 @@
         }
     }
 
-
-    public int nextBlockNumber() {
-        return compilation.stats.blockCount++;
-    }
-
-    public int numberOfBlocks() {
-        return compilation.stats.blockCount;
-    }
-
     public int numLoops() {
         return compilation.stats.loopCount;
     }