/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt;
import java.util.ArrayList;
import org.jikesrvm.ArchitectureSpecific.OPT_MIROptimizationPlanner;
import org.jikesrvm.VM;
import org.jikesrvm.adaptive.recompilation.instrumentation.OPT_InsertInstructionCounters;
import org.jikesrvm.adaptive.recompilation.instrumentation.OPT_InsertMethodInvocationCounter;
import org.jikesrvm.adaptive.recompilation.instrumentation.OPT_InsertYieldpointCounters;
import org.jikesrvm.adaptive.recompilation.instrumentation.OPT_InstrumentationSamplingFramework;
import org.jikesrvm.adaptive.recompilation.instrumentation.OPT_LowerInstrumentation;
import org.jikesrvm.compilers.opt.ir.OPT_ConvertBCtoHIR;
import org.jikesrvm.osr.OSR_AdjustBCIndexes;
/**
* This class specifies the order in which OPT_CompilerPhases are
* executed during the HIR and LIR phase of the opt compilation of a method.
*
* @see OPT_MIROptimizationPlanner
*/
public class OPT_OptimizationPlanner {
/**
* The master optimization plan.
* All plans that are actually executed should be subsets of this plan
* constructed by calling createOptimizationPlan.
*/
private static OPT_OptimizationPlanElement[] masterPlan;
/**
* Generate a report of time spent in various phases of the opt compiler.
* <p> NB: This method may be called in a context where classloading and/or
* GC cannot be allowed.
* Therefore we must use primitive sysWrites for output and avoid string
* appends and other allocations.
*
* @param explain Should an explanation of the metrics be generated?
*/
public static void generateOptimizingCompilerSubsystemReport(boolean explain) {
if (!VM.MeasureCompilationPhases) {
return;
}
VM.sysWrite("\t\tOptimizing Compiler SubSystem\n");
VM.sysWrite("\tPhase\t\t\t\t\tTime\n");
VM.sysWrite("\t\t\t\t\t (ms) (%ofTotal)\n");
double total = 0.0;
for (OPT_OptimizationPlanElement element : masterPlan) {
total += element.elapsedTime();
}
for (OPT_OptimizationPlanElement element : masterPlan) {
element.reportStats(8, 40, total);
}
VM.sysWrite("\n\tTOTAL COMPILATION TIME\t\t");
int t = (int) total, places = t;
if (places == 0) {
places = 1;
}
while (places < 1000000) { // Right-align 't'
VM.sysWrite(" ");
places *= 10;
}
VM.sysWrite(t);
VM.sysWrite("\n");
}
/**
* Using the passed options create an optimization plan
* by selecting a subset of the elements in the masterPlan.
*
* @param options the OPT_Options to use
* @return an OPT_OptimizationPlanElement[] selected from
* the masterPlan based on options.
*/
public static OPT_OptimizationPlanElement[] createOptimizationPlan(OPT_Options options) {
if (masterPlan == null) {
initializeMasterPlan();
}
ArrayList<OPT_OptimizationPlanElement> temp = new ArrayList<OPT_OptimizationPlanElement>();
for (OPT_OptimizationPlanElement element : masterPlan) {
if (element.shouldPerform(options)) {
temp.add(element);
}
}
if (VM.writingBootImage) {
masterPlan = null; // avoid problems with classes not being in bootimage.
}
return toArray(temp);
}
/**
* This method is called to initialize all phases to support
* measuring compilation.
*/
public static void initializeMeasureCompilation() {
for (OPT_OptimizationPlanElement element : masterPlan) {
element.initializeForMeasureCompilation();
}
}
/**
* Initialize the "master plan", which holds all optimization elements
* that will normally execute.
*/
private static void initializeMasterPlan() {
ArrayList<OPT_OptimizationPlanElement> temp = new ArrayList<OPT_OptimizationPlanElement>();
BC2HIR(temp);
HIROptimizations(temp);
HIR2LIR(temp);
LIROptimizations(temp);
OPT_MIROptimizationPlanner.intializeMasterPlan(temp);
masterPlan = toArray(temp);
}
/**
* Convert the ArrayList to an array of elements.
* TODO: this is a bad name (finalize), isn't it?
*/
private static OPT_OptimizationPlanElement[] toArray(ArrayList<OPT_OptimizationPlanElement> planElementList) {
OPT_OptimizationPlanElement[] p = new OPT_OptimizationPlanElement[planElementList.size()];
planElementList.toArray(p);
return p;
}
/**
* This method defines the optimization plan elements required to
* generate HIR from bytecodes.
*
* @param p the plan under construction
*/
private static void BC2HIR(ArrayList<OPT_OptimizationPlanElement> p) {
composeComponents(p, "Convert Bytecodes to HIR", new Object[]{
// Generate HIR from bytecodes
new OPT_ConvertBCtoHIR(),
new OSR_AdjustBCIndexes(), new OSR_OsrPointConstructor(),
// Always do initial wave of peephole branch optimizations
new OPT_BranchOptimizations(0, true, false),
// Adjust static branch probabilities to account for infrequent blocks
new OPT_AdjustBranchProbabilities(),
// Optional printing of initial HIR
// Do this after branch optimization, since without merging
// FallThroughOuts, the IR is quite ugly.
new OPT_IRPrinter("Initial HIR") {
public boolean shouldPerform(OPT_Options options) {
return options.PRINT_HIGH;
}
}});
}
/**
* This method defines the optimization plan elements that
* are to be performed on the HIR.
*
* @param p the plan under construction
*/
private static void HIROptimizations(ArrayList<OPT_OptimizationPlanElement> p) {
// Various large-scale CFG transformations.
// Do these very early in the pipe so that all HIR opts can benefit.
composeComponents(p, "CFG Transformations", new Object[]{
// tail recursion elimination
new OPT_TailRecursionElimination(),
// Estimate block frequencies if doing any of
// static splitting, cfg transformations, or loop unrolling.
// Assumption: none of these are active at O0.
new OPT_OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
new Object[]{new OPT_BuildLST(), new OPT_EstimateBlockFrequencies()}) {
public boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= 1;
}
},
// CFG splitting
new OPT_StaticSplitting(),
// restructure loops
new OPT_CFGTransformations(),
// Loop unrolling
new OPT_LoopUnrolling(), new OPT_BranchOptimizations(1, true, true),});
// Use the LST to insert yieldpoints and estimate
// basic block frequency from branch probabilities
composeComponents(p,
"CFG Structural Analysis",
new Object[]{new OPT_BuildLST(), new OPT_YieldPoints(), new OPT_EstimateBlockFrequencies()});
// Simple flow-insensitive optimizations
addComponent(p, new OPT_Simple(1, true, true));
// Simple escape analysis and related transformations
addComponent(p, new OPT_EscapeTransformations());
// Perform peephole branch optimizations to clean-up before SSA stuff
addComponent(p, new OPT_BranchOptimizations(1, true, true));
// SSA meta-phase
SSAinHIR(p);
// Perform local copy propagation for a factored basic block.
addComponent(p, new OPT_LocalCopyProp());
// Perform local constant propagation for a factored basic block.
addComponent(p, new OPT_LocalConstantProp());
// Perform local common-subexpression elimination for a
// factored basic block.
addComponent(p, new OPT_LocalCSE(true));
// Flow-insensitive field analysis
addComponent(p, new OPT_FieldAnalysis());
if (VM.BuildForAdaptiveSystem) {
// Insert counter on each method prologue
// Insert yieldpoint counters
addComponent(p, new OPT_InsertYieldpointCounters());
// Insert counter on each HIR instruction
addComponent(p, new OPT_InsertInstructionCounters());
// Insert method invocation counters
addComponent(p, new OPT_InsertMethodInvocationCounter());
}
}
/**
* This method defines the optimization plan elements that
* are to be performed with SSA form on HIR.
*
* @param p the plan under construction
*/
private static void SSAinHIR(ArrayList<OPT_OptimizationPlanElement> p) {
composeComponents(p, "SSA", new Object[]{
// Use the LST to estimate basic block frequency from branch probabilities
new OPT_OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
new Object[]{new OPT_BuildLST(), new OPT_EstimateBlockFrequencies()}) {
public boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= 3;
}
},
new OPT_OptimizationPlanCompositeElement("HIR SSA transformations", new Object[]{
// Local copy propagation
new OPT_LocalCopyProp(),
// Local constant propagation
new OPT_LocalConstantProp(),
// Insert PI Nodes
new OPT_PiNodes(true),
// branch optimization
new OPT_BranchOptimizations(3, true, true),
// Compute dominators
new OPT_DominatorsPhase(true),
// compute dominance frontier
new OPT_DominanceFrontier(),
// load elimination
new OPT_LoadElimination(1),
// load elimination
new OPT_LoadElimination(2),
// load elimination
new OPT_LoadElimination(3),
// load elimination
new OPT_LoadElimination(4),
// load elimination
new OPT_LoadElimination(5),
// eliminate redundant conditional branches
new OPT_RedundantBranchElimination(),
// path sensitive constant propagation
new OPT_SSATuneUp(),
// clean up Pi Nodes
new OPT_PiNodes(false),
// Simple SSA optimizations,
new OPT_SSATuneUp(),
// Global Code Placement,
new OPT_GCP(),
// Loop versioning
new OPT_LoopVersioning(),
// Leave SSA
new OPT_LeaveSSA()}) {
public boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= 3;
}
},
// Coalesce moves
new OPT_CoalesceMoves(),
// SSA reveals new opportunites for the following
new OPT_OptimizationPlanCompositeElement("Post SSA cleanup",
new Object[]{new OPT_LocalCopyProp(),
new OPT_LocalConstantProp(),
new OPT_Simple(3, true, true),
new OPT_EscapeTransformations(),
new OPT_BranchOptimizations(3, true, true)}) {
public boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= 3;
}
}});
}
/**
* This method defines the optimization plan elements that
* are to be performed with SSA form on LIR.
*
* @param p the plan under construction
*/
private static void SSAinLIR(ArrayList<OPT_OptimizationPlanElement> p) {
composeComponents(p, "SSA", new Object[]{
// Use the LST to estimate basic block frequency from branch probabilities
new OPT_OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
new Object[]{new OPT_BuildLST(), new OPT_EstimateBlockFrequencies()}) {
public boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= 3;
}
},
new OPT_OptimizationPlanCompositeElement("LIR SSA transformations", new Object[]{
// restructure loops
new OPT_CFGTransformations(),
// Compute dominators
new OPT_DominatorsPhase(true),
// compute dominance frontier
new OPT_DominanceFrontier(),
// Global Code Placement,
new OPT_GCP(),
// Leave SSA
new OPT_LeaveSSA()}) {
public boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= 3;
}
},
// Live range splitting
new OPT_LiveRangeSplitting(),
// Coalesce moves
new OPT_CoalesceMoves(),
// SSA reveals new opportunites for the following
new OPT_OptimizationPlanCompositeElement("Post SSA cleanup",
new Object[]{new OPT_LocalCopyProp(),
new OPT_LocalConstantProp(),
new OPT_Simple(3, true, true),
new OPT_BranchOptimizations(3, true, true)}) {
public boolean shouldPerform(OPT_Options options) {
return options.getOptLevel() >= 3;
}
}});
}
/**
* This method defines the optimization plan elements that
* are to be performed to lower HIR to LIR.
*
* @param p the plan under construction
*/
private static void HIR2LIR(ArrayList<OPT_OptimizationPlanElement> p) {
composeComponents(p, "Convert HIR to LIR", new Object[]{
// Optional printing of final HIR
new OPT_IRPrinter("Final HIR") {
public boolean shouldPerform(OPT_Options options) {
return options.PRINT_FINAL_HIR;
}
},
// Inlining "runtime service" methods
new OPT_ExpandRuntimeServices(),
// Peephole branch optimizations
new OPT_BranchOptimizations(1, true, true),
// Local optimizations of checkcasts
new OPT_LocalCastOptimization(),
// Massive operator expansion
new OPT_ConvertHIRtoLIR(),
// Peephole branch optimizations
new OPT_BranchOptimizations(0, true, true),
// Adjust static branch probabilites to account for infrequent blocks
// introduced by the inlining of runtime services.
new OPT_AdjustBranchProbabilities(),
// Optional printing of initial LIR
new OPT_IRPrinter("Initial LIR") {
public boolean shouldPerform(OPT_Options options) {
return options.PRINT_LOW;
}
}});
}
/**
* This method defines the optimization plan elements that
* are to be performed on the LIR.
*
* @param p the plan under construction
*/
private static void LIROptimizations(ArrayList<OPT_OptimizationPlanElement> p) {
// SSA meta-phase
SSAinLIR(p);
// Perform local copy propagation for a factored basic block.
addComponent(p, new OPT_LocalCopyProp());
// Perform local constant propagation for a factored basic block.
addComponent(p, new OPT_LocalConstantProp());
// Perform local common-subexpression elimination for a factored basic block.
addComponent(p, new OPT_LocalCSE(false));
// Simple flow-insensitive optimizations
addComponent(p, new OPT_Simple(0, false, false));
// Use the LST to estimate basic block frequency
addComponent(p,
new OPT_OptimizationPlanCompositeElement("Basic Block Frequency Estimation",
new Object[]{new OPT_BuildLST(),
new OPT_EstimateBlockFrequencies()}));
// Perform basic block reordering
addComponent(p, new OPT_ReorderingPhase());
// Perform peephole branch optimizations
addComponent(p, new OPT_BranchOptimizations(1, false, true));
if (VM.BuildForAdaptiveSystem) {
// Arnold & Ryder instrumentation sampling framework
addComponent(p, new OPT_InstrumentationSamplingFramework());
// Convert high level place holder instructions into actual instrumenation
addComponent(p, new OPT_LowerInstrumentation());
}
}
// Helper functions for constructing the masterPlan.
protected static void addComponent(ArrayList<OPT_OptimizationPlanElement> p, OPT_CompilerPhase e) {
addComponent(p, new OPT_OptimizationPlanAtomicElement(e));
}
/**
* Add an optimization plan element to a vector.
*/
protected static void addComponent(ArrayList<OPT_OptimizationPlanElement> p, OPT_OptimizationPlanElement e) {
p.add(e);
}
/**
* Add a set of optimization plan elements to a vector.
* @param p the vector to add to
* @param name the name for this composition
* @param es the array of composed elements
*/
protected static void composeComponents(ArrayList<OPT_OptimizationPlanElement> p, String name, Object[] es) {
p.add(OPT_OptimizationPlanCompositeElement.compose(name, es));
}
}