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 }