Mercurial > hg > graal-jvmci-8
comparison graal/GraalCompiler/src/com/sun/c1x/graph/IR.java @ 2868:6d24c27902a2
turned inlining into a phase, some node cloning fixes, added NodeWorklist
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Tue, 07 Jun 2011 19:19:14 +0200 |
parents | 5c545fef2c81 |
children | fc75fd3fa5e4 |
comparison
equal
deleted
inserted
replaced
2867:5c545fef2c81 | 2868:6d24c27902a2 |
---|---|
27 | 27 |
28 import com.oracle.graal.graph.*; | 28 import com.oracle.graal.graph.*; |
29 import com.oracle.max.graal.schedule.*; | 29 import com.oracle.max.graal.schedule.*; |
30 import com.sun.c1x.*; | 30 import com.sun.c1x.*; |
31 import com.sun.c1x.debug.*; | 31 import com.sun.c1x.debug.*; |
32 import com.sun.c1x.gen.*; | |
33 import com.sun.c1x.ir.*; | 32 import com.sun.c1x.ir.*; |
34 import com.sun.c1x.lir.*; | 33 import com.sun.c1x.lir.*; |
35 import com.sun.c1x.observer.*; | 34 import com.sun.c1x.observer.*; |
36 import com.sun.c1x.value.*; | 35 import com.sun.c1x.value.*; |
37 import com.sun.cri.ci.*; | 36 import com.sun.cri.ci.*; |
155 | 154 |
156 private void buildGraph() { | 155 private void buildGraph() { |
157 // Graph builder must set the startBlock and the osrEntryBlock | 156 // Graph builder must set the startBlock and the osrEntryBlock |
158 new GraphBuilder(compilation, compilation.method, compilation.graph).build(false); | 157 new GraphBuilder(compilation, compilation.method, compilation.graph).build(false); |
159 | 158 |
159 // CompilerGraph duplicate = new CompilerGraph(); | |
160 // Map<Node, Node> replacements = new HashMap<Node, Node>(); | |
161 // replacements.put(compilation.graph.start(), duplicate.start()); | |
162 // duplicate.addDuplicate(compilation.graph.getNodes(), replacements); | |
163 // compilation.graph = duplicate; | |
164 | |
160 verifyAndPrint("After graph building"); | 165 verifyAndPrint("After graph building"); |
161 | 166 |
162 DeadCodeElimination dce = new DeadCodeElimination(); | 167 DeadCodeElimination dce = new DeadCodeElimination(); |
163 dce.apply(compilation.graph); | 168 dce.apply(compilation.graph); |
164 if (dce.deletedNodeCount > 0) { | 169 if (dce.deletedNodeCount > 0) { |
165 verifyAndPrint("After dead code elimination"); | 170 verifyAndPrint("After dead code elimination"); |
166 } | 171 } |
167 | 172 |
168 if (C1XOptions.Inline) { | 173 if (C1XOptions.Inline) { |
169 inlineMethods(); | 174 new Inlining(compilation, this).apply(compilation.graph); |
170 } | 175 } |
171 | 176 |
172 if (C1XOptions.PrintCompilation) { | 177 if (C1XOptions.PrintCompilation) { |
173 TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount)); | 178 TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount)); |
174 } | 179 } |
175 } | |
176 | |
177 private void inlineMethods() { | |
178 int inliningSize = compilation.method.code().length; | |
179 boolean inlined; | |
180 int iterations = C1XOptions.MaximumRecursiveInlineLevel; | |
181 do { | |
182 inlined = false; | |
183 | |
184 List<Invoke> trivialInline = new ArrayList<Invoke>(); | |
185 List<Invoke> deoptInline = new ArrayList<Invoke>(); | |
186 List<RiMethod> deoptMethods = new ArrayList<RiMethod>(); | |
187 for (Node node : compilation.graph.getNodes()) { | |
188 if (node instanceof Invoke) { | |
189 Invoke invoke = (Invoke) node; | |
190 RiMethod target = invoke.target; | |
191 if (target.isResolved() && !Modifier.isNative(target.accessFlags())) { | |
192 if (target.canBeStaticallyBound()) { | |
193 trivialInline.add(invoke); | |
194 } else { | |
195 RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); | |
196 if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { | |
197 deoptInline.add(invoke); | |
198 deoptMethods.add(concrete); | |
199 } | |
200 } | |
201 } | |
202 } | |
203 } | |
204 | |
205 for (Invoke invoke : trivialInline) { | |
206 if (inlineMethod(invoke, invoke.target)) { | |
207 inlined = true; | |
208 inliningSize += invoke.target.code().length; | |
209 if (inliningSize > C1XOptions.MaximumInstructionCount) { | |
210 break; | |
211 } | |
212 } | |
213 } | |
214 | |
215 for (int i = 0; i < deoptInline.size(); i++) { | |
216 Invoke invoke = deoptInline.get(i); | |
217 RiMethod method = deoptMethods.get(i); | |
218 if (inlineMethod(invoke, method)) { | |
219 if (C1XOptions.TraceInlining) { | |
220 System.out.println("registering concrete method assumption..."); | |
221 } | |
222 compilation.assumptions.recordConcreteMethod(invoke.target, method); | |
223 inlined = true; | |
224 inliningSize += method.code().length; | |
225 if (inliningSize > C1XOptions.MaximumInstructionCount) { | |
226 break; | |
227 } | |
228 } | |
229 } | |
230 | |
231 if (inlined) { | |
232 DeadCodeElimination dce = new DeadCodeElimination(); | |
233 dce.apply(compilation.graph); | |
234 if (dce.deletedNodeCount > 0) { | |
235 verifyAndPrint("After dead code elimination"); | |
236 } | |
237 verifyAndPrint("After inlining iteration"); | |
238 } | |
239 | |
240 if (inliningSize > C1XOptions.MaximumInstructionCount) { | |
241 break; | |
242 } | |
243 } while(inlined && (--iterations > 0)); | |
244 } | |
245 | |
246 private boolean inlineMethod(Invoke invoke, RiMethod method) { | |
247 String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; | |
248 FrameState stateAfter = invoke.stateAfter(); | |
249 | |
250 if (method.code().length > C1XOptions.MaximumInlineSize) { | |
251 if (C1XOptions.TraceInlining) { | |
252 System.out.println("not inlining " + name + " because of code size"); | |
253 } | |
254 return false; | |
255 } | |
256 | |
257 if (invoke.predecessors().size() == 0) { | |
258 if (C1XOptions.TraceInlining) { | |
259 System.out.println("not inlining " + name + " because the invoke is dead code"); | |
260 } | |
261 return false; | |
262 } | |
263 | |
264 Instruction exceptionEdge = invoke.exceptionEdge(); | |
265 // if (exceptionEdge != null) { | |
266 // if (C1XOptions.TraceInlining) { | |
267 // System.out.println("not inlining " + name + " because of exceptionEdge"); | |
268 // } | |
269 // return false; | |
270 // } | |
271 if (!method.holder().isInitialized()) { | |
272 if (C1XOptions.TraceInlining) { | |
273 System.out.println("not inlining " + name + " because of non-initialized class"); | |
274 } | |
275 return false; | |
276 } | |
277 | |
278 if (C1XOptions.TraceInlining) { | |
279 System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); | |
280 } | |
281 | |
282 CompilerGraph graph = new CompilerGraph(); | |
283 new GraphBuilder(compilation, method, graph).build(true); | |
284 | |
285 boolean withReceiver = !Modifier.isStatic(method.accessFlags()); | |
286 | |
287 int argumentCount = method.signature().argumentCount(false); | |
288 Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)]; | |
289 int slot = withReceiver ? 1 : 0; | |
290 int param = withReceiver ? 1 : 0; | |
291 for (int i = 0; i < argumentCount; i++) { | |
292 parameters[param++] = invoke.argument(slot); | |
293 slot += method.signature().argumentKindAt(i).sizeInSlots(); | |
294 } | |
295 if (withReceiver) { | |
296 parameters[0] = invoke.argument(0); | |
297 } | |
298 | |
299 HashMap<Node, Node> replacements = new HashMap<Node, Node>(); | |
300 ArrayList<Node> nodes = new ArrayList<Node>(); | |
301 ArrayList<Node> frameStates = new ArrayList<Node>(); | |
302 Return returnNode = null; | |
303 Unwind unwindNode = null; | |
304 StartNode startNode = graph.start(); | |
305 for (Node node : graph.getNodes()) { | |
306 if (node != null) { | |
307 if (node instanceof StartNode) { | |
308 assert startNode == node; | |
309 } else if (node instanceof Local) { | |
310 replacements.put(node, parameters[((Local) node).index()]); | |
311 } else { | |
312 nodes.add(node); | |
313 if (node instanceof Return) { | |
314 returnNode = (Return) node; | |
315 } else if (node instanceof Unwind) { | |
316 unwindNode = (Unwind) node; | |
317 } else if (node instanceof FrameState) { | |
318 frameStates.add(node); | |
319 } | |
320 } | |
321 } | |
322 } | |
323 | |
324 if (C1XOptions.TraceInlining) { | |
325 printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); | |
326 System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); | |
327 } | |
328 | |
329 assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); | |
330 Instruction pred; | |
331 if (withReceiver) { | |
332 pred = new NullCheck(parameters[0], compilation.graph); | |
333 } else { | |
334 pred = new Merge(compilation.graph); | |
335 } | |
336 invoke.predecessors().get(0).successors().replace(invoke, pred); | |
337 replacements.put(startNode, pred); | |
338 | |
339 Map<Node, Node> duplicates = compilation.graph.addDuplicate(nodes, replacements); | |
340 | |
341 if (returnNode != null) { | |
342 List<Node> usages = new ArrayList<Node>(invoke.usages()); | |
343 for (Node usage : usages) { | |
344 if (returnNode.result() instanceof Local) { | |
345 usage.inputs().replace(invoke, replacements.get(returnNode.result())); | |
346 } else { | |
347 usage.inputs().replace(invoke, duplicates.get(returnNode.result())); | |
348 } | |
349 } | |
350 Node returnDuplicate = duplicates.get(returnNode); | |
351 returnDuplicate.inputs().clearAll(); | |
352 | |
353 assert returnDuplicate.predecessors().size() == 1; | |
354 Node returnPred = returnDuplicate.predecessors().get(0); | |
355 int index = returnDuplicate.predecessorsIndex().get(0); | |
356 returnPred.successors().setAndClear(index, invoke, 0); | |
357 returnDuplicate.delete(); | |
358 } | |
359 | |
360 // if (invoke.next() instanceof Merge) { | |
361 // ((Merge) invoke.next()).removePhiPredecessor(invoke); | |
362 // } | |
363 // invoke.successors().clearAll(); | |
364 invoke.inputs().clearAll(); | |
365 invoke.setExceptionEdge(null); | |
366 // invoke.delete(); | |
367 | |
368 | |
369 if (exceptionEdge != null) { | |
370 if (unwindNode != null) { | |
371 assert unwindNode.predecessors().size() == 1; | |
372 assert exceptionEdge.successors().size() == 1; | |
373 ExceptionObject obj = (ExceptionObject) exceptionEdge; | |
374 | |
375 List<Node> usages = new ArrayList<Node>(obj.usages()); | |
376 for (Node usage : usages) { | |
377 if (replacements.containsKey(unwindNode.exception())) { | |
378 usage.inputs().replace(obj, replacements.get(unwindNode.exception())); | |
379 } else { | |
380 usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); | |
381 } | |
382 } | |
383 Node unwindDuplicate = duplicates.get(unwindNode); | |
384 unwindDuplicate.inputs().clearAll(); | |
385 | |
386 assert unwindDuplicate.predecessors().size() == 1; | |
387 Node unwindPred = unwindDuplicate.predecessors().get(0); | |
388 int index = unwindDuplicate.predecessorsIndex().get(0); | |
389 unwindPred.successors().setAndClear(index, obj, 0); | |
390 | |
391 obj.inputs().clearAll(); | |
392 obj.delete(); | |
393 unwindDuplicate.delete(); | |
394 | |
395 } | |
396 } | |
397 | |
398 // adjust all frame states that were copied | |
399 if (frameStates.size() > 0) { | |
400 FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); | |
401 for (Node frameState : frameStates) { | |
402 ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); | |
403 } | |
404 } | |
405 | |
406 if (C1XOptions.TraceInlining) { | |
407 verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); | |
408 } | |
409 return true; | |
410 } | 180 } |
411 | 181 |
412 /** | 182 /** |
413 * Gets the linear scan ordering of blocks as a list. | 183 * Gets the linear scan ordering of blocks as a list. |
414 * @return the blocks in linear scan order | 184 * @return the blocks in linear scan order |