Mercurial > hg > truffle
comparison graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java @ 2919:5429750cb94c
Merge
author | Gilles Duboscq <gilles.duboscq@oracle.com> |
---|---|
date | Thu, 09 Jun 2011 11:30:58 +0200 |
parents | e7ba2bad98fb 35fb2fef44f1 |
children | a6d0743f3380 |
comparison
equal
deleted
inserted
replaced
2918:e7ba2bad98fb | 2919:5429750cb94c |
---|---|
40 private final IR ir; | 40 private final IR ir; |
41 | 41 |
42 private final Queue<Invoke> invokes = new ArrayDeque<Invoke>(); | 42 private final Queue<Invoke> invokes = new ArrayDeque<Invoke>(); |
43 private final Queue<RiMethod> methods = new ArrayDeque<RiMethod>(); | 43 private final Queue<RiMethod> methods = new ArrayDeque<RiMethod>(); |
44 private int inliningSize; | 44 private int inliningSize; |
45 | 45 private final boolean trace; |
46 public InliningPhase(GraalCompilation compilation, IR ir) { | 46 |
47 public InliningPhase(GraalCompilation compilation, IR ir, boolean trace) { | |
47 this.compilation = compilation; | 48 this.compilation = compilation; |
48 this.ir = ir; | 49 this.ir = ir; |
50 this.trace = trace; | |
49 } | 51 } |
50 | 52 |
51 private void addToQueue(Invoke invoke, RiMethod method) { | 53 private void addToQueue(Invoke invoke, RiMethod method) { |
52 invokes.add(invoke); | 54 invokes.add(invoke); |
53 methods.add(method); | 55 methods.add(method); |
54 inliningSize += method.code().length; | 56 inliningSize += method.code().length; |
55 } | 57 } |
56 | 58 |
59 static HashMap<RiMethod, Integer> methodCount = new HashMap<RiMethod, Integer>(); | |
57 @Override | 60 @Override |
58 protected void run(Graph graph) { | 61 protected void run(Graph graph) { |
59 inliningSize = compilation.method.code().length; | 62 inliningSize = compilation.method.code().length; |
60 int iterations = GraalOptions.MaximumRecursiveInlineLevel; | 63 for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) { |
61 do { | 64 for (Invoke invoke : graph.getNodes(Invoke.class)) { |
62 for (Node node : graph.getNodes()) { | 65 RiMethod target = invoke.target; |
63 if (node instanceof Invoke) { | 66 if (invoke.stateAfter() == null || invoke.stateAfter().locksSize() > 0) { |
64 Invoke invoke = (Invoke) node; | 67 if (trace) { |
65 RiMethod target = invoke.target; | 68 System.out.println("lock..."); |
66 if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { | |
67 continue; | |
68 } | 69 } |
69 if (target.canBeStaticallyBound()) { | 70 continue; |
70 if (checkInliningConditions(invoke.target)) { | 71 } |
71 addToQueue(invoke, invoke.target); | 72 if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { |
72 } | 73 continue; |
73 } else { | 74 } |
74 RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); | 75 if (target.canBeStaticallyBound()) { |
75 if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { | 76 if (checkInliningConditions(invoke.target, iterations)) { |
76 if (checkInliningConditions(concrete)) { | 77 addToQueue(invoke, invoke.target); |
77 if (GraalOptions.TraceInlining) { | 78 } |
78 System.out.println("registering concrete method assumption..."); | 79 } else { |
79 } | 80 RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); |
80 compilation.assumptions.recordConcreteMethod(invoke.target, concrete); | 81 if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { |
81 addToQueue(invoke, concrete); | 82 if (checkInliningConditions(concrete, iterations)) { |
83 if (trace) { | |
84 System.out.println("recording concrete method assumption..."); | |
82 } | 85 } |
86 compilation.assumptions.recordConcreteMethod(invoke.target, concrete); | |
87 addToQueue(invoke, concrete); | |
83 } | 88 } |
84 } | 89 } |
85 if (inliningSize > GraalOptions.MaximumInstructionCount) { | 90 } |
86 break; | 91 if (inliningSize > GraalOptions.MaximumInstructionCount) { |
87 } | 92 break; |
88 } | 93 } |
89 } | 94 } |
90 | 95 |
91 assert invokes.size() == methods.size(); | 96 assert invokes.size() == methods.size(); |
92 if (invokes.isEmpty()) { | 97 if (invokes.isEmpty()) { |
95 | 100 |
96 Invoke invoke; | 101 Invoke invoke; |
97 while ((invoke = invokes.poll()) != null) { | 102 while ((invoke = invokes.poll()) != null) { |
98 RiMethod method = methods.remove(); | 103 RiMethod method = methods.remove(); |
99 inlineMethod(invoke, method); | 104 inlineMethod(invoke, method); |
105 | |
106 if (methodCount.get(method) == null) { | |
107 methodCount.put(method, 1); | |
108 } else { | |
109 methodCount.put(method, methodCount.get(method) + 1); | |
110 } | |
100 } | 111 } |
101 DeadCodeEliminationPhase dce = new DeadCodeEliminationPhase(); | 112 DeadCodeEliminationPhase dce = new DeadCodeEliminationPhase(); |
102 dce.apply(graph); | 113 dce.apply(graph); |
103 | 114 |
104 if (inliningSize > GraalOptions.MaximumInstructionCount) { | 115 if (inliningSize > GraalOptions.MaximumInstructionCount) { |
105 if (GraalOptions.TraceInlining) { | 116 if (trace) { |
106 System.out.println("inlining stopped: MaximumInstructionCount reached"); | 117 System.out.println("inlining stopped: MaximumInstructionCount reached"); |
107 } | 118 } |
108 break; | 119 break; |
109 } | 120 } |
110 } while(--iterations > 0); | 121 } |
122 | |
123 if (trace) { | |
124 int inlined = 0; | |
125 int duplicate = 0; | |
126 for (Map.Entry<RiMethod, Integer> entry : methodCount.entrySet()) { | |
127 inlined += entry.getValue(); | |
128 duplicate += entry.getValue() - 1; | |
129 } | |
130 if (inlined > 0) { | |
131 System.out.printf("overhead_: %d (%5.3f %%)\n", duplicate, duplicate * 100.0 / inlined); | |
132 } | |
133 } | |
111 } | 134 } |
112 | 135 |
113 private boolean checkInliningConditions(Invoke invoke) { | 136 private boolean checkInliningConditions(Invoke invoke) { |
114 String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); | 137 String name = !trace ? null : invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); |
115 if (invoke.predecessors().size() == 0) { | 138 if (invoke.predecessors().size() == 0) { |
116 if (GraalOptions.TraceInlining) { | 139 if (trace) { |
117 System.out.println("not inlining " + name + " because the invoke is dead code"); | 140 System.out.println("not inlining " + name + " because the invoke is dead code"); |
118 } | 141 } |
119 return false; | 142 return false; |
120 } | 143 } |
144 if (invoke.stateAfter() == null) { | |
145 if (trace) { | |
146 System.out.println("not inlining " + name + " because of missing frame state"); | |
147 } | |
148 } | |
121 return true; | 149 return true; |
122 } | 150 } |
123 | 151 |
124 private boolean checkInliningConditions(RiMethod method) { | 152 private boolean checkInliningConditions(RiMethod method, int iterations) { |
125 String name = null; | 153 String name = !trace ? null : CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; |
126 if (GraalOptions.TraceInlining) { | |
127 name = CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; | |
128 } | |
129 if (method.code().length > GraalOptions.MaximumInlineSize) { | 154 if (method.code().length > GraalOptions.MaximumInlineSize) { |
130 if (GraalOptions.TraceInlining) { | 155 if (trace) { |
131 System.out.println("not inlining " + name + " because of code size"); | 156 System.out.println("not inlining " + name + " because of code size"); |
132 } | 157 } |
133 return false; | 158 return false; |
134 } | 159 } |
135 if (!method.holder().isInitialized()) { | 160 if (!method.holder().isInitialized()) { |
136 if (GraalOptions.TraceInlining) { | 161 if (trace) { |
137 System.out.println("not inlining " + name + " because of non-initialized class"); | 162 System.out.println("not inlining " + name + " because of non-initialized class"); |
138 } | 163 } |
139 return false; | 164 return false; |
140 } | 165 } |
166 if (method == compilation.method && iterations > GraalOptions.MaximumRecursiveInlineLevel) { | |
167 if (trace) { | |
168 System.out.println("not inlining " + name + " because of recursive inlining limit"); | |
169 } | |
170 return false; | |
171 } | |
141 return true; | 172 return true; |
142 } | 173 } |
143 | 174 |
144 private void inlineMethod(Invoke invoke, RiMethod method) { | 175 private void inlineMethod(Invoke invoke, RiMethod method) { |
145 String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; | 176 String name = !trace ? null : invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; |
146 FrameState stateAfter = invoke.stateAfter(); | 177 FrameState stateAfter = invoke.stateAfter(); |
147 Instruction exceptionEdge = invoke.exceptionEdge(); | 178 Instruction exceptionEdge = invoke.exceptionEdge(); |
148 | 179 |
149 if (GraalOptions.TraceInlining) { | 180 if (trace) { |
150 System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); | 181 System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); |
151 } | 182 } |
152 | 183 |
153 CompilerGraph graph = new CompilerGraph(compilation); | 184 CompilerGraph graph = new CompilerGraph(compilation); |
154 new GraphBuilderPhase(compilation, method, true, true).apply(graph); | 185 new GraphBuilderPhase(compilation, method, true, true).apply(graph); |
164 slot += method.signature().argumentKindAt(i).sizeInSlots(); | 195 slot += method.signature().argumentKindAt(i).sizeInSlots(); |
165 } | 196 } |
166 if (withReceiver) { | 197 if (withReceiver) { |
167 parameters[0] = invoke.argument(0); | 198 parameters[0] = invoke.argument(0); |
168 } | 199 } |
200 | |
201 invoke.inputs().clearAll(); | |
169 | 202 |
170 HashMap<Node, Node> replacements = new HashMap<Node, Node>(); | 203 HashMap<Node, Node> replacements = new HashMap<Node, Node>(); |
171 ArrayList<Node> nodes = new ArrayList<Node>(); | 204 ArrayList<Node> nodes = new ArrayList<Node>(); |
172 ArrayList<Node> frameStates = new ArrayList<Node>(); | 205 ArrayList<Node> frameStates = new ArrayList<Node>(); |
173 Return returnNode = null; | 206 Return returnNode = null; |
190 } | 223 } |
191 } | 224 } |
192 } | 225 } |
193 } | 226 } |
194 | 227 |
195 if (GraalOptions.TraceInlining) { | 228 if (trace) { |
196 ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); | 229 ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); |
197 System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); | 230 System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); |
198 } | 231 } |
199 | 232 |
200 assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); | 233 assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); |
206 } | 239 } |
207 invoke.predecessors().get(0).successors().replace(invoke, pred); | 240 invoke.predecessors().get(0).successors().replace(invoke, pred); |
208 replacements.put(startNode, pred); | 241 replacements.put(startNode, pred); |
209 | 242 |
210 Map<Node, Node> duplicates = compilation.graph.addDuplicate(nodes, replacements); | 243 Map<Node, Node> duplicates = compilation.graph.addDuplicate(nodes, replacements); |
244 | |
245 int monitorIndexDelta = stateAfter.locksSize(); | |
246 if (monitorIndexDelta > 0) { | |
247 for (Map.Entry<Node, Node> entry : duplicates.entrySet()) { | |
248 if (entry.getValue() instanceof MonitorAddress) { | |
249 System.out.println("Adjusting monitor index"); | |
250 MonitorAddress address = (MonitorAddress) entry.getValue(); | |
251 address.setMonitorIndex(address.monitorIndex() + monitorIndexDelta); | |
252 } | |
253 } | |
254 } | |
211 | 255 |
212 if (returnNode != null) { | 256 if (returnNode != null) { |
213 List<Node> usages = new ArrayList<Node>(invoke.usages()); | 257 List<Node> usages = new ArrayList<Node>(invoke.usages()); |
214 for (Node usage : usages) { | 258 for (Node usage : usages) { |
215 if (returnNode.result() instanceof Local) { | 259 if (returnNode.result() instanceof Local) { |
226 int index = returnDuplicate.predecessorsIndex().get(0); | 270 int index = returnDuplicate.predecessorsIndex().get(0); |
227 returnPred.successors().setAndClear(index, invoke, 0); | 271 returnPred.successors().setAndClear(index, invoke, 0); |
228 returnDuplicate.delete(); | 272 returnDuplicate.delete(); |
229 } | 273 } |
230 | 274 |
231 // if (invoke.next() instanceof Merge) { | |
232 // ((Merge) invoke.next()).removePhiPredecessor(invoke); | |
233 // } | |
234 // invoke.successors().clearAll(); | |
235 invoke.inputs().clearAll(); | |
236 invoke.setExceptionEdge(null); | |
237 // invoke.delete(); | |
238 | |
239 | |
240 if (exceptionEdge != null) { | 275 if (exceptionEdge != null) { |
241 if (unwindNode != null) { | 276 if (unwindNode != null) { |
242 assert unwindNode.predecessors().size() == 1; | 277 assert unwindNode.predecessors().size() == 1; |
243 assert exceptionEdge.successors().size() == 1; | 278 assert exceptionEdge.successors().size() == 1; |
244 ExceptionObject obj = (ExceptionObject) exceptionEdge; | 279 ExceptionObject obj = (ExceptionObject) exceptionEdge; |
245 | 280 |
281 Unwind unwindDuplicate = (Unwind) duplicates.get(unwindNode); | |
246 List<Node> usages = new ArrayList<Node>(obj.usages()); | 282 List<Node> usages = new ArrayList<Node>(obj.usages()); |
247 for (Node usage : usages) { | 283 for (Node usage : usages) { |
248 if (replacements.containsKey(unwindNode.exception())) { | 284 usage.inputs().replace(obj, unwindDuplicate.exception()); |
249 usage.inputs().replace(obj, replacements.get(unwindNode.exception())); | 285 } |
250 } else { | |
251 usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); | |
252 } | |
253 } | |
254 Node unwindDuplicate = duplicates.get(unwindNode); | |
255 unwindDuplicate.inputs().clearAll(); | 286 unwindDuplicate.inputs().clearAll(); |
256 | 287 |
257 assert unwindDuplicate.predecessors().size() == 1; | 288 assert unwindDuplicate.predecessors().size() == 1; |
258 Node unwindPred = unwindDuplicate.predecessors().get(0); | 289 Node unwindPred = unwindDuplicate.predecessors().get(0); |
259 int index = unwindDuplicate.predecessorsIndex().get(0); | 290 int index = unwindDuplicate.predecessorsIndex().get(0); |
260 unwindPred.successors().setAndClear(index, obj, 0); | 291 unwindPred.successors().setAndClear(index, obj, 0); |
261 | 292 |
262 obj.inputs().clearAll(); | 293 obj.inputs().clearAll(); |
263 obj.delete(); | |
264 unwindDuplicate.delete(); | 294 unwindDuplicate.delete(); |
265 | |
266 } | 295 } |
267 } | 296 } |
268 | 297 |
269 // adjust all frame states that were copied | 298 // adjust all frame states that were copied |
270 if (frameStates.size() > 0) { | 299 if (frameStates.size() > 0) { |
272 for (Node frameState : frameStates) { | 301 for (Node frameState : frameStates) { |
273 ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); | 302 ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); |
274 } | 303 } |
275 } | 304 } |
276 | 305 |
277 if (GraalOptions.TraceInlining) { | 306 if (trace) { |
278 ir.printGraph("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false), compilation.graph); | 307 ir.printGraph("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false), compilation.graph); |
279 } | 308 } |
280 } | 309 } |
281 } | 310 } |