Mercurial > hg > graal-jvmci-8
comparison 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 |
comparison
equal
deleted
inserted
replaced
2841:633e66de40fe | 2842:7596ae867a7b |
---|---|
20 * or visit www.oracle.com if you need additional information or have any | 20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. | 21 * questions. |
22 */ | 22 */ |
23 package com.sun.c1x.graph; | 23 package com.sun.c1x.graph; |
24 | 24 |
25 import java.lang.reflect.*; | |
25 import java.util.*; | 26 import java.util.*; |
26 | 27 |
27 import com.oracle.graal.graph.*; | 28 import com.oracle.graal.graph.*; |
28 import com.oracle.max.graal.schedule.*; | 29 import com.oracle.max.graal.schedule.*; |
29 import com.sun.c1x.*; | 30 import com.sun.c1x.*; |
31 import com.sun.c1x.gen.*; | 32 import com.sun.c1x.gen.*; |
32 import com.sun.c1x.ir.*; | 33 import com.sun.c1x.ir.*; |
33 import com.sun.c1x.lir.*; | 34 import com.sun.c1x.lir.*; |
34 import com.sun.c1x.observer.*; | 35 import com.sun.c1x.observer.*; |
35 import com.sun.c1x.value.*; | 36 import com.sun.c1x.value.*; |
37 import com.sun.cri.ci.*; | |
38 import com.sun.cri.ri.*; | |
36 | 39 |
37 /** | 40 /** |
38 * This class implements the overall container for the HIR (high-level IR) graph | 41 * This class implements the overall container for the HIR (high-level IR) graph |
39 * and directs its construction, optimization, and finalization. | 42 * and directs its construction, optimization, and finalization. |
40 */ | 43 */ |
159 } | 162 } |
160 } | 163 } |
161 | 164 |
162 private void buildGraph() { | 165 private void buildGraph() { |
163 // Graph builder must set the startBlock and the osrEntryBlock | 166 // Graph builder must set the startBlock and the osrEntryBlock |
164 new GraphBuilder(compilation, this, compilation.graph).build(); | 167 new GraphBuilder(compilation, compilation.method, compilation.graph).build(); |
165 | 168 |
166 verifyAndPrint("After graph building"); | 169 verifyAndPrint("After graph building"); |
167 | 170 |
171 List<Invoke> trivialInline = new ArrayList<Invoke>(); | |
172 List<Invoke> deoptInline = new ArrayList<Invoke>(); | |
173 List<RiMethod> deoptMethods = new ArrayList<RiMethod>(); | |
174 for (Node node : compilation.graph.getNodes()) { | |
175 if (node instanceof Invoke) { | |
176 Invoke invoke = (Invoke) node; | |
177 RiMethod target = invoke.target; | |
178 if (target.isResolved() && !Modifier.isNative(target.accessFlags())) { | |
179 if (target.canBeStaticallyBound()) { | |
180 trivialInline.add(invoke); | |
181 } else { | |
182 RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); | |
183 if (concrete != null) { | |
184 deoptInline.add(invoke); | |
185 deoptMethods.add(concrete); | |
186 } | |
187 } | |
188 } | |
189 } | |
190 } | |
191 | |
192 int allowedInlinings = 50; | |
193 for (Invoke invoke : trivialInline) { | |
194 if (inlineMethod(invoke, invoke.target)) { | |
195 if (--allowedInlinings <= 0) { | |
196 break; | |
197 } | |
198 } | |
199 } | |
200 | |
201 for (int i = 0; i < deoptInline.size(); i++) { | |
202 Invoke invoke = deoptInline.get(i); | |
203 RiMethod method = deoptMethods.get(i); | |
204 if (inlineMethod(invoke, method)) { | |
205 if (C1XOptions.TraceInlining) { | |
206 System.out.println("registering concrete method assumption..."); | |
207 } | |
208 compilation.assumptions.recordConcreteMethod(invoke.target, method); | |
209 if (--allowedInlinings <= 0) { | |
210 break; | |
211 } | |
212 } | |
213 } | |
214 | |
168 if (C1XOptions.PrintCompilation) { | 215 if (C1XOptions.PrintCompilation) { |
169 TTY.print(String.format("%3d blocks | ", this.numberOfBlocks())); | 216 TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount)); |
217 } | |
218 } | |
219 | |
220 private boolean inlineMethod(Invoke invoke, RiMethod method) { | |
221 String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; | |
222 | |
223 if (method.code().length > 50) { | |
224 if (C1XOptions.TraceInlining) { | |
225 System.out.println("not inlining " + name + " because of code size"); | |
226 } | |
227 return false; | |
228 } | |
229 | |
230 Instruction exceptionEdge = invoke.exceptionEdge(); | |
231 if (exceptionEdge != null) { | |
232 if (C1XOptions.TraceInlining) { | |
233 System.out.println("not inlining " + name + " because of exceptionEdge"); | |
234 } | |
235 return false; | |
236 } | |
237 if (!method.holder().isInitialized()) { | |
238 if (C1XOptions.TraceInlining) { | |
239 System.out.println("not inlining " + name + " because of non-initialized class"); | |
240 } | |
241 return false; | |
242 } | |
243 | |
244 if (C1XOptions.TraceInlining) { | |
245 System.out.println("building graph: " + name); | |
246 } | |
247 CompilerGraph graph = new CompilerGraph(); | |
248 new GraphBuilder(compilation, method, graph).build(); | |
249 | |
250 boolean withReceiver = !Modifier.isStatic(method.accessFlags()); | |
251 | |
252 int argumentCount = method.signature().argumentCount(false); | |
253 Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)]; | |
254 int slot = withReceiver ? 1 : 0; | |
255 int param = withReceiver ? 1 : 0; | |
256 for (int i = 0; i < argumentCount; i++) { | |
257 parameters[param++] = invoke.argument(slot); | |
258 slot += method.signature().argumentKindAt(i).sizeInSlots(); | |
259 } | |
260 if (withReceiver) { | |
261 parameters[0] = invoke.argument(0); | |
262 } | |
263 | |
264 HashMap<Node, Node> replacements = new HashMap<Node, Node>(); | |
265 ArrayList<Node> nodes = new ArrayList<Node>(); | |
266 ArrayList<Node> frameStates = new ArrayList<Node>(); | |
267 Return returnNode = null; | |
268 Unwind unwindNode = null; | |
269 StartNode startNode = null; | |
270 boolean invokes = false; | |
271 for (Node node : graph.getNodes()) { | |
272 if (node != null) { | |
273 if (node instanceof StartNode) { | |
274 startNode = (StartNode) node; | |
275 } else if (node instanceof Local) { | |
276 replacements.put(node, parameters[((Local) node).index()]); | |
277 } else { | |
278 nodes.add(node); | |
279 if (node instanceof Return) { | |
280 returnNode = (Return) node; | |
281 } else if (node instanceof Unwind) { | |
282 unwindNode = (Unwind) node; | |
283 } else if (node instanceof FrameState) { | |
284 frameStates.add(node); | |
285 } | |
286 } | |
287 } | |
288 } | |
289 if (unwindNode != null) { | |
290 if (C1XOptions.TraceInlining) { | |
291 System.out.println("not inlining " + name + " because of unwind node"); | |
292 } | |
293 return false; | |
294 } | |
295 if (invokes) { | |
296 if (C1XOptions.TraceInlining) { | |
297 System.out.println("not inlining " + name + " because of invokes"); | |
298 } | |
299 return false; | |
300 } | |
301 | |
302 if (C1XOptions.TraceInlining) { | |
303 System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); | |
304 } | |
305 | |
306 Instruction pred; | |
307 if (withReceiver) { | |
308 pred = new NullCheck(parameters[0], compilation.graph); | |
309 } else { | |
310 pred = new Merge(compilation.graph); | |
311 } | |
312 assert invoke.predecessors().size() == 1; | |
313 invoke.predecessors().get(0).successors().replace(invoke, pred); | |
314 replacements.put(startNode, pred); | |
315 | |
316 Map<Node, Node> duplicates = compilation.graph.addDuplicate(nodes, replacements); | |
317 | |
318 if (returnNode != null) { | |
319 List<Node> usages = new ArrayList<Node>(invoke.usages()); | |
320 for (Node usage : usages) { | |
321 if (returnNode.result() instanceof Local) { | |
322 usage.inputs().replace(invoke, replacements.get(returnNode.result())); | |
323 } else { | |
324 usage.inputs().replace(invoke, duplicates.get(returnNode.result())); | |
325 } | |
326 } | |
327 Node returnDuplicate = duplicates.get(returnNode); | |
328 returnDuplicate.inputs().clearAll(); | |
329 | |
330 assert returnDuplicate.predecessors().size() == 1; | |
331 Node returnPred = returnDuplicate.predecessors().get(0); | |
332 int index = returnDuplicate.predecessorsIndex().get(0); | |
333 returnPred.successors().setAndClear(index, invoke, 0); | |
334 | |
335 returnDuplicate.delete(); | |
336 } | |
337 FrameState stateAfter = invoke.stateAfter(); | |
338 if (frameStates.size() > 0) { | |
339 FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); | |
340 for (Node frameState : frameStates) { | |
341 ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); | |
342 } | |
343 } | |
344 | |
345 invoke.successors().clearAll(); | |
346 invoke.inputs().clearAll(); | |
347 invoke.delete(); | |
348 | |
349 stateAfter.delete(); | |
350 | |
351 deleteUnused(exceptionEdge); | |
352 | |
353 verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); | |
354 return true; | |
355 } | |
356 | |
357 private void deleteUnused(Node node) { | |
358 if (node != null && node.predecessors().size() == 0) { | |
359 if (node instanceof ExceptionObject) { | |
360 Node successor = node.successors().get(0); | |
361 node.successors().clearAll(); | |
362 if (successor instanceof ExceptionDispatch) { | |
363 ExceptionDispatch dispatch = (ExceptionDispatch) successor; | |
364 Node succ1 = dispatch.catchSuccessor(); | |
365 Node succ2 = dispatch.otherSuccessor(); | |
366 if (succ1 instanceof Merge) { | |
367 ((Merge) succ1).removePhiPredecessor(dispatch); | |
368 } | |
369 if (succ2 instanceof Merge) { | |
370 ((Merge) succ2).removePhiPredecessor(dispatch); | |
371 } | |
372 dispatch.successors().clearAll(); | |
373 deleteUnused(succ1); | |
374 deleteUnused(succ2); | |
375 dispatch.delete(); | |
376 } else { | |
377 assert successor instanceof Merge; | |
378 System.out.println("succ: " + successor.successors().get(0)); | |
379 Node next = successor.successors().get(0); | |
380 successor.successors().clearAll(); | |
381 deleteUnused(next); | |
382 successor.delete(); | |
383 } | |
384 node.delete(); | |
385 } else if (node instanceof Unwind) { | |
386 node.delete(); | |
387 } | |
170 } | 388 } |
171 } | 389 } |
172 | 390 |
173 /** | 391 /** |
174 * Gets the linear scan ordering of blocks as a list. | 392 * Gets the linear scan ordering of blocks as a list. |
198 } | 416 } |
199 | 417 |
200 if (compilation.compiler.isObserved()) { | 418 if (compilation.compiler.isObserved()) { |
201 compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, compilation.graph, true, false)); | 419 compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, phase, compilation.graph, true, false)); |
202 } | 420 } |
203 } | |
204 | |
205 | |
206 public int nextBlockNumber() { | |
207 return compilation.stats.blockCount++; | |
208 } | |
209 | |
210 public int numberOfBlocks() { | |
211 return compilation.stats.blockCount; | |
212 } | 421 } |
213 | 422 |
214 public int numLoops() { | 423 public int numLoops() { |
215 return compilation.stats.loopCount; | 424 return compilation.stats.loopCount; |
216 } | 425 } |