001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.driver;
014    
015    import java.util.ArrayList;
016    
017    import org.jikesrvm.VM;
018    import org.jikesrvm.ArchitectureSpecificOpt.MIROptimizationPlanner;
019    import org.jikesrvm.adaptive.recompilation.instrumentation.InsertInstructionCounters;
020    import org.jikesrvm.adaptive.recompilation.instrumentation.InsertMethodInvocationCounter;
021    import org.jikesrvm.adaptive.recompilation.instrumentation.InsertYieldpointCounters;
022    import org.jikesrvm.adaptive.recompilation.instrumentation.InstrumentationSamplingFramework;
023    import org.jikesrvm.adaptive.recompilation.instrumentation.LowerInstrumentation;
024    import org.jikesrvm.compilers.opt.AdjustBranchProbabilities;
025    import org.jikesrvm.compilers.opt.FieldAnalysis;
026    import org.jikesrvm.compilers.opt.LocalCSE;
027    import org.jikesrvm.compilers.opt.LocalCastOptimization;
028    import org.jikesrvm.compilers.opt.LocalConstantProp;
029    import org.jikesrvm.compilers.opt.LocalCopyProp;
030    import org.jikesrvm.compilers.opt.OptOptions;
031    import org.jikesrvm.compilers.opt.Simple;
032    import org.jikesrvm.compilers.opt.bc2ir.ConvertBCtoHIR;
033    import org.jikesrvm.compilers.opt.bc2ir.OsrPointConstructor;
034    import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations;
035    import org.jikesrvm.compilers.opt.controlflow.BuildLST;
036    import org.jikesrvm.compilers.opt.controlflow.CFGTransformations;
037    import org.jikesrvm.compilers.opt.controlflow.DominanceFrontier;
038    import org.jikesrvm.compilers.opt.controlflow.DominatorsPhase;
039    import org.jikesrvm.compilers.opt.controlflow.EstimateBlockFrequencies;
040    import org.jikesrvm.compilers.opt.controlflow.LoopUnrolling;
041    import org.jikesrvm.compilers.opt.controlflow.ReorderingPhase;
042    import org.jikesrvm.compilers.opt.controlflow.StaticSplitting;
043    import org.jikesrvm.compilers.opt.controlflow.TailRecursionElimination;
044    import org.jikesrvm.compilers.opt.controlflow.YieldPoints;
045    import org.jikesrvm.compilers.opt.escape.EscapeTransformations;
046    import org.jikesrvm.compilers.opt.hir2lir.ConvertHIRtoLIR;
047    import org.jikesrvm.compilers.opt.hir2lir.ExpandRuntimeServices;
048    import org.jikesrvm.compilers.opt.ir.IR;
049    import org.jikesrvm.compilers.opt.regalloc.CoalesceMoves;
050    import org.jikesrvm.compilers.opt.ssa.GCP;
051    import org.jikesrvm.compilers.opt.ssa.LeaveSSA;
052    import org.jikesrvm.compilers.opt.ssa.LiveRangeSplitting;
053    import org.jikesrvm.compilers.opt.ssa.LoadElimination;
054    import org.jikesrvm.compilers.opt.ssa.LoopVersioning;
055    import org.jikesrvm.compilers.opt.ssa.PiNodes;
056    import org.jikesrvm.compilers.opt.ssa.RedundantBranchElimination;
057    import org.jikesrvm.compilers.opt.ssa.SSATuneUp;
058    import org.jikesrvm.osr.AdjustBCIndexes;
059    
060    /**
061     * This class specifies the order in which CompilerPhases are
062     * executed during the HIR and LIR phase of the opt compilation of a method.
063     *
064     * @see MIROptimizationPlanner
065     */
066    public class OptimizationPlanner {
067    
068      /**
069       * The master optimization plan.
070       * All plans that are actually executed should be subsets of this plan
071       * constructed by calling createOptimizationPlan.
072       */
073      private static OptimizationPlanElement[] masterPlan;
074    
075      /**
076       * Generate a report of time spent in various phases of the opt compiler.
077       * <p> NB: This method may be called in a context where classloading and/or
078       * GC cannot be allowed.
079       * Therefore we must use primitive sysWrites for output and avoid string
080       * appends and other allocations.
081       *
082       * @param explain Should an explanation of the metrics be generated?
083       */
084      public static void generateOptimizingCompilerSubsystemReport(boolean explain) {
085        if (!VM.MeasureCompilationPhases) {
086          return;
087        }
088    
089        VM.sysWrite("\t\tOptimizing Compiler SubSystem\n");
090        VM.sysWrite("\tPhase\t\t\t\t\tTime\n");
091        VM.sysWrite("\t\t\t\t\t   (ms)    (%ofTotal)\n");
092        double total = 0.0;
093    
094        for (OptimizationPlanElement element : masterPlan) {
095          total += element.elapsedTime();
096        }
097    
098        for (OptimizationPlanElement element : masterPlan) {
099          element.reportStats(8, 40, total);
100        }
101    
102        VM.sysWrite("\n\tTOTAL COMPILATION TIME\t\t");
103        int t = (int) total, places = t;
104        if (places == 0) {
105          places = 1;
106        }
107        while (places < 1000000) { // Right-align 't'
108          VM.sysWrite(" ");
109          places *= 10;
110        }
111        VM.sysWrite(t);
112        VM.sysWrite("\n");
113      }
114    
115      /**
116       * Using the passed options create an optimization plan
117       * by selecting a subset of the elements in the masterPlan.
118       *
119       * @param options the Options to use
120       * @return an OptimizationPlanElement[] selected from
121       * the masterPlan based on options.
122       */
123      public static OptimizationPlanElement[] createOptimizationPlan(OptOptions options) {
124        if (masterPlan == null) {
125          initializeMasterPlan();
126        }
127    
128        ArrayList<OptimizationPlanElement> temp = new ArrayList<OptimizationPlanElement>();
129        for (OptimizationPlanElement element : masterPlan) {
130          if (element.shouldPerform(options)) {
131            temp.add(element);
132          }
133        }
134        if (VM.writingBootImage) {
135          masterPlan = null;  // avoid problems with classes not being in bootimage.
136        }
137        return toArray(temp);
138      }
139    
140      /**
141       * This method is called to initialize all phases to support
142       *  measuring compilation.
143       */
144      public static void initializeMeasureCompilation() {
145        for (OptimizationPlanElement element : masterPlan) {
146          element.initializeForMeasureCompilation();
147        }
148      }
149    
150      /**
151       * Initialize the "master plan", which holds all optimization elements
152       * that will normally execute.
153       */
154      private static void initializeMasterPlan() {
155        ArrayList<OptimizationPlanElement> temp = new ArrayList<OptimizationPlanElement>();
156        BC2HIR(temp);
157        HIROptimizations(temp);
158        HIR2LIR(temp);
159        LIROptimizations(temp);
160        MIROptimizationPlanner.intializeMasterPlan(temp);
161        masterPlan = toArray(temp);
162      }
163    
164      /**
165       * Convert the ArrayList to an array of elements.
166       * @param planElementList the array list to convert, must be non-{@code null}
167       * @return list as array
168       */
169      private static OptimizationPlanElement[] toArray(ArrayList<OptimizationPlanElement> planElementList) {
170        OptimizationPlanElement[] p = new OptimizationPlanElement[planElementList.size()];
171        planElementList.toArray(p);
172        return p;
173      }
174    
175      /**
176       * This method defines the optimization plan elements required to
177       * generate HIR from bytecodes.
178       *
179       * @param p the plan under construction
180       */
181      private static void BC2HIR(ArrayList<OptimizationPlanElement> p) {
182        composeComponents(p, "Convert Bytecodes to HIR", new Object[]{
183            // Generate HIR from bytecodes
184            new ConvertBCtoHIR(),
185    
186            new AdjustBCIndexes(), new OsrPointConstructor(),
187    
188            // Always do initial wave of peephole branch optimizations
189            new BranchOptimizations(0, true, false),
190    
191            // ir now contains well formed HIR. Optionally do a verification pass.
192            new CompilerPhase() {
193              @Override
194              public String getName() {
195                return "HIR Verification";
196              }
197              @Override
198              public void perform(IR ir) {
199                if (IR.SANITY_CHECK) {
200                  ir.verify("Initial HIR", true);
201                }
202              }
203              @Override
204              public CompilerPhase newExecution(IR ir) {
205                return this;
206              }
207            },
208    
209            // Adjust static branch probabilities to account for infrequent blocks
210            new AdjustBranchProbabilities(),
211    
212            // Optional printing of initial HIR
213            // Do this after branch optimization, since without merging
214            // FallThroughOuts, the IR is quite ugly.
215            new IRPrinter("Initial HIR") {
216              @Override
217              public boolean shouldPerform(OptOptions options) {
218                return options.PRINT_HIGH;
219              }
220            }});
221      }
222    
223      /**
224       * This method defines the optimization plan elements that
225       * are to be performed on the HIR.
226       *
227       * @param p the plan under construction
228       */
229      private static void HIROptimizations(ArrayList<OptimizationPlanElement> p) {
230        // Various large-scale CFG transformations.
231        // Do these very early in the pipe so that all HIR opts can benefit.
232        composeComponents(p, "CFG Transformations", new Object[]{
233            // tail recursion elimination
234            new TailRecursionElimination(),
235            // Estimate block frequencies if doing any of
236            // static splitting, cfg transformations, or loop unrolling.
237            // Assumption: none of these are active at O0.
238            new OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
239                                                     new Object[]{new BuildLST(), new EstimateBlockFrequencies()}) {
240              @Override
241              public boolean shouldPerform(OptOptions options) {
242                return options.getOptLevel() >= 1;
243              }
244            },
245            // CFG splitting
246            new StaticSplitting(),
247            // restructure loops
248            new CFGTransformations(),
249            // Loop unrolling
250            new LoopUnrolling(), new BranchOptimizations(1, true, true),});
251    
252        // Use the LST to insert yieldpoints and estimate
253        // basic block frequency from branch probabilities
254        composeComponents(p,
255                          "CFG Structural Analysis",
256                          new Object[]{new BuildLST(), new YieldPoints(), new EstimateBlockFrequencies()});
257    
258        // Simple flow-insensitive optimizations
259        addComponent(p, new Simple(1, true, true, false, false));
260    
261        // Simple escape analysis and related transformations
262        addComponent(p, new EscapeTransformations());
263    
264        // Perform peephole branch optimizations to clean-up before SSA stuff
265        addComponent(p, new BranchOptimizations(1, true, true));
266    
267        // SSA meta-phase
268        SSAinHIR(p);
269    
270        // Perform local copy propagation for a factored basic block.
271        addComponent(p, new LocalCopyProp());
272        // Perform local constant propagation for a factored basic block.
273        addComponent(p, new LocalConstantProp());
274        // Perform local common-subexpression elimination for a
275        // factored basic block.
276        addComponent(p, new LocalCSE(true));
277        // Flow-insensitive field analysis
278        addComponent(p, new FieldAnalysis());
279        if (VM.BuildForAdaptiveSystem) {
280          // Insert counter on each method prologue
281          // Insert yieldpoint counters
282          addComponent(p, new InsertYieldpointCounters());
283          // Insert counter on each HIR instruction
284          addComponent(p, new InsertInstructionCounters());
285          // Insert method invocation counters
286          addComponent(p, new InsertMethodInvocationCounter());
287        }
288      }
289    
290      /**
291       * This method defines the optimization plan elements that
292       * are to be performed with SSA form on HIR.
293       *
294       * @param p the plan under construction
295       */
296      private static void SSAinHIR(ArrayList<OptimizationPlanElement> p) {
297        composeComponents(p, "SSA", new Object[]{
298            // Use the LST to estimate basic block frequency from branch probabilities
299            new OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
300                                                     new Object[]{new BuildLST(), new EstimateBlockFrequencies()}) {
301              @Override
302              public boolean shouldPerform(OptOptions options) {
303                return options.getOptLevel() >= 3;
304              }
305            },
306    
307            new OptimizationPlanCompositeElement("HIR SSA transformations", new Object[]{
308                // Local copy propagation
309                new LocalCopyProp(),
310                // Local constant propagation
311                new LocalConstantProp(),
312                // Insert PI Nodes
313                new PiNodes(true),
314                // branch optimization
315                new BranchOptimizations(3, true, true),
316                // Compute dominators
317                new DominatorsPhase(true),
318                // compute dominance frontier
319                new DominanceFrontier(),
320                // load elimination
321                new LoadElimination(1),
322                // load elimination
323                new LoadElimination(2),
324                // load elimination
325                new LoadElimination(3),
326                // load elimination
327                new LoadElimination(4),
328                // load elimination
329                new LoadElimination(5),
330                // eliminate redundant conditional branches
331                new RedundantBranchElimination(),
332                // path sensitive constant propagation
333                new SSATuneUp(),
334                // clean up Pi Nodes
335                new PiNodes(false),
336                // Simple SSA optimizations,
337                new SSATuneUp(),
338                // Global Code Placement,
339                new GCP(),
340                // Loop versioning
341                new LoopVersioning(),
342                // Leave SSA
343                new LeaveSSA()}) {
344              @Override
345              public boolean shouldPerform(OptOptions options) {
346                return options.getOptLevel() >= 3;
347              }
348            },
349            // Coalesce moves
350            new CoalesceMoves(),
351    
352            // SSA reveals new opportunites for the following
353            new OptimizationPlanCompositeElement("Post SSA cleanup",
354                                                     new Object[]{new LocalCopyProp(),
355                                                                  new LocalConstantProp(),
356                                                                  new Simple(3, true, true, false, false),
357                                                                  new EscapeTransformations(),
358                                                                  new BranchOptimizations(3, true, true)}) {
359              @Override
360              public boolean shouldPerform(OptOptions options) {
361                return options.getOptLevel() >= 3;
362              }
363            }});
364      }
365    
366      /**
367       * This method defines the optimization plan elements that
368       * are to be performed with SSA form on LIR.
369       *
370       * @param p the plan under construction
371       */
372      private static void SSAinLIR(ArrayList<OptimizationPlanElement> p) {
373        composeComponents(p, "SSA", new Object[]{
374            // Use the LST to estimate basic block frequency from branch probabilities
375            new OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
376                                                     new Object[]{new BuildLST(), new EstimateBlockFrequencies()}) {
377              @Override
378              public boolean shouldPerform(OptOptions options) {
379                return options.getOptLevel() >= 3;
380              }
381            },
382    
383            new OptimizationPlanCompositeElement("LIR SSA transformations", new Object[]{
384                // restructure loops
385                new CFGTransformations(),
386                // Compute dominators
387                new DominatorsPhase(true),
388                // compute dominance frontier
389                new DominanceFrontier(),
390                // Global Code Placement,
391                new GCP(),
392                // Leave SSA
393                new LeaveSSA()}) {
394              @Override
395              public boolean shouldPerform(OptOptions options) {
396                return options.getOptLevel() >= 3;
397              }
398            },
399            // Live range splitting
400            new LiveRangeSplitting(),
401    
402            // Coalesce moves
403            new CoalesceMoves(),
404    
405            // SSA reveals new opportunites for the following
406            new OptimizationPlanCompositeElement("Post SSA cleanup",
407                                                     new Object[]{new LocalCopyProp(),
408                                                                  new LocalConstantProp(),
409                                                                  new Simple(3, true, true, false, false),
410                                                                  new BranchOptimizations(3, true, true)}) {
411              @Override
412              public boolean shouldPerform(OptOptions options) {
413                return options.getOptLevel() >= 3;
414              }
415            }});
416      }
417    
418      /**
419       * This method defines the optimization plan elements that
420       * are to be performed to lower HIR to LIR.
421       *
422       * @param p the plan under construction
423       */
424      private static void HIR2LIR(ArrayList<OptimizationPlanElement> p) {
425        composeComponents(p, "Convert HIR to LIR", new Object[]{
426            // Optional printing of final HIR
427            new IRPrinter("Final HIR") {
428              @Override
429              public boolean shouldPerform(OptOptions options) {
430                return options.PRINT_FINAL_HIR;
431              }
432            },
433    
434            // Inlining "runtime service" methods
435            new ExpandRuntimeServices(),
436            // Peephole branch optimizations
437            new BranchOptimizations(1, true, true),
438            // Local optimizations of checkcasts
439            new LocalCastOptimization(),
440            // Massive operator expansion
441            new ConvertHIRtoLIR(),
442            // Peephole branch optimizations
443            new BranchOptimizations(0, true, true),
444            // Adjust static branch probabilites to account for infrequent blocks
445            // introduced by the inlining of runtime services.
446            new AdjustBranchProbabilities(),
447            // Optional printing of initial LIR
448            new IRPrinter("Initial LIR") {
449              @Override
450              public boolean shouldPerform(OptOptions options) {
451                return options.PRINT_LOW;
452              }
453            }});
454      }
455    
456      /**
457       * This method defines the optimization plan elements that
458       * are to be performed on the LIR.
459       *
460       * @param p the plan under construction
461       */
462      private static void LIROptimizations(ArrayList<OptimizationPlanElement> p) {
463        // SSA meta-phase
464        SSAinLIR(p);
465        // Perform local copy propagation for a factored basic block.
466        addComponent(p, new LocalCopyProp());
467        // Perform local constant propagation for a factored basic block.
468        addComponent(p, new LocalConstantProp());
469        // Perform local common-subexpression elimination for a factored basic block.
470        addComponent(p, new LocalCSE(false));
471        // Simple flow-insensitive optimizations
472        addComponent(p, new Simple(0, false, false, false, VM.BuildForIA32));
473    
474        // Use the LST to estimate basic block frequency
475        addComponent(p,
476                     new OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
477                                                              new Object[]{new BuildLST(),
478                                                                           new EstimateBlockFrequencies()}));
479    
480        // Perform basic block reordering
481        addComponent(p, new ReorderingPhase());
482        // Perform peephole branch optimizations
483        addComponent(p, new BranchOptimizations(0, false, true));
484    
485        if (VM.BuildForAdaptiveSystem) {
486          // Arnold & Ryder instrumentation sampling framework
487          addComponent(p, new InstrumentationSamplingFramework());
488    
489          // Convert high level place holder instructions into actual instrumentation
490          addComponent(p, new LowerInstrumentation());
491        }
492      }
493    
494      // Helper functions for constructing the masterPlan.
495      protected static void addComponent(ArrayList<OptimizationPlanElement> p, CompilerPhase e) {
496        addComponent(p, new OptimizationPlanAtomicElement(e));
497      }
498    
499      /**
500       * Add an optimization plan element to a vector.
501       */
502      protected static void addComponent(ArrayList<OptimizationPlanElement> p, OptimizationPlanElement e) {
503        p.add(e);
504      }
505    
506      /**
507       * Add a set of optimization plan elements to a vector.
508       * @param p    the vector to add to
509       * @param name the name for this composition
510       * @param es   the array of composed elements
511       */
512      protected static void composeComponents(ArrayList<OptimizationPlanElement> p, String name, Object[] es) {
513        p.add(OptimizationPlanCompositeElement.compose(name, es));
514      }
515    }