#include "gen/optimizer.h" #include "gen/cl_helpers.h" #include "gen/passes/Passes.h" #include "llvm/PassManager.h" #include "llvm/LinkAllPasses.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/PassNameParser.h" #include "root.h" // error() using namespace llvm; // Allow the user to specify specific optimizations to run. static cl::list passList( cl::desc("Running specific optimizations:"), cl::Hidden // to clean up --help output ); static cl::opt optimizeLevel( cl::desc("Setting the optimization level:"), cl::ZeroOrMore, cl::values( clEnumValN(2, "O", "Equivalent to -O2"), clEnumValN(0, "O0", "No optimizations (default)"), clEnumValN(1, "O1", "Simple optimizations"), clEnumValN(2, "O2", "Good optimizations"), clEnumValN(3, "O3", "Aggressive optimizations"), clEnumValN(4, "O4", "Link-time optimization"), // not implemented? clEnumValN(5, "O5", "Link-time optimization"), // not implemented? clEnumValEnd), cl::init(0)); static cl::opt verifyEach("verify-each", cl::desc("Run verifier after each optimization pass"), cl::Hidden, cl::ZeroOrMore); static cl::opt disableLangSpecificPasses("disable-d-passes", cl::desc("Disable D-specific passes in -O"), cl::ZeroOrMore); static cl::opt disableSimplifyRuntimeCalls("disable-simplify-drtcalls", cl::desc("Disable simplification of runtime calls in -O"), cl::ZeroOrMore); #ifdef USE_METADATA static cl::opt disableGCToStack("disable-gc2stack", cl::desc("Disable promotion of GC allocations to stack memory in -O"), cl::ZeroOrMore); // Not recommended; metadata currently triggers an assert in the backend... static cl::opt disableStripMetaData("disable-strip-metadata", cl::desc("Disable default metadata stripping (not recommended)"), cl::ZeroOrMore); #endif static cl::opt enableInlining("inlining", cl::desc("(*) Enable function inlining in -O"), cl::ZeroOrMore); // Determine whether or not to run the inliner as part of the default list of // optimization passes. // If not explicitly specified, treat as false for -O0-2, and true for -O3. bool doInline() { return enableInlining == cl::BOU_TRUE || (enableInlining == cl::BOU_UNSET && optimizeLevel >= 3); } // Some extra accessors for the linker: (llvm-ld version only, currently unused?) int optLevel() { return optimizeLevel; } bool optimize() { return optimizeLevel || doInline() || !passList.empty(); } static void addPass(PassManager& pm, Pass* pass) { pm.add(pass); if (verifyEach) pm.add(createVerifierPass()); } // this function inserts some or all of the std-compile-opts passes depending on the // optimization level given. static void addPassesForOptLevel(PassManager& pm) { // -O1 if (optimizeLevel >= 1) { //addPass(pm, createStripDeadPrototypesPass()); addPass(pm, createGlobalDCEPass()); addPass(pm, createRaiseAllocationsPass()); addPass(pm, createCFGSimplificationPass()); if (optimizeLevel == 1) addPass(pm, createPromoteMemoryToRegisterPass()); else addPass(pm, createScalarReplAggregatesPass()); addPass(pm, createGlobalOptimizerPass()); addPass(pm, createGlobalDCEPass()); } // -O2 if (optimizeLevel >= 2) { addPass(pm, createIPConstantPropagationPass()); addPass(pm, createDeadArgEliminationPass()); addPass(pm, createInstructionCombiningPass()); addPass(pm, createCFGSimplificationPass()); addPass(pm, createPruneEHPass()); addPass(pm, createFunctionAttrsPass()); #ifdef USE_METADATA if (!disableLangSpecificPasses && !disableGCToStack) addPass(pm, createGarbageCollect2Stack()); #endif } // -inline if (doInline()) { addPass(pm, createFunctionInliningPass()); if (optimizeLevel >= 2) { // Run some optimizations to clean up after inlining. addPass(pm, createScalarReplAggregatesPass()); addPass(pm, createInstructionCombiningPass()); #ifdef USE_METADATA if (!disableLangSpecificPasses && !disableGCToStack) addPass(pm, createGarbageCollect2Stack()); #endif // Inline again, to catch things like foreach delegates // passed to inlined opApply's where the function wasn't // known during the first inliner pass. addPass(pm, createFunctionInliningPass()); // Run clean-up again. addPass(pm, createScalarReplAggregatesPass()); addPass(pm, createInstructionCombiningPass()); #ifdef USE_METADATA if (!disableLangSpecificPasses && !disableGCToStack) addPass(pm, createGarbageCollect2Stack()); #endif } } if (optimizeLevel >= 2 && !disableLangSpecificPasses) { if (!disableSimplifyRuntimeCalls) addPass(pm, createSimplifyDRuntimeCalls()); #ifdef USE_METADATA if (!disableGCToStack) { // Run some clean-up after the last GC to stack promotion pass. addPass(pm, createScalarReplAggregatesPass()); addPass(pm, createInstructionCombiningPass()); addPass(pm, createCFGSimplificationPass()); } #endif } // -O3 if (optimizeLevel >= 3) { addPass(pm, createArgumentPromotionPass()); addPass(pm, createTailDuplicationPass()); addPass(pm, createInstructionCombiningPass()); addPass(pm, createCFGSimplificationPass()); addPass(pm, createScalarReplAggregatesPass()); addPass(pm, createInstructionCombiningPass()); addPass(pm, createCondPropagationPass()); addPass(pm, createTailCallEliminationPass()); addPass(pm, createCFGSimplificationPass()); addPass(pm, createReassociatePass()); addPass(pm, createLoopRotatePass()); addPass(pm, createLICMPass()); addPass(pm, createLoopUnswitchPass()); addPass(pm, createInstructionCombiningPass()); addPass(pm, createIndVarSimplifyPass()); addPass(pm, createLoopUnrollPass()); addPass(pm, createInstructionCombiningPass()); addPass(pm, createGVNPass()); addPass(pm, createSCCPPass()); addPass(pm, createInstructionCombiningPass()); addPass(pm, createCondPropagationPass()); addPass(pm, createDeadStoreEliminationPass()); addPass(pm, createAggressiveDCEPass()); addPass(pm, createCFGSimplificationPass()); addPass(pm, createSimplifyLibCallsPass()); addPass(pm, createDeadTypeEliminationPass()); addPass(pm, createConstantMergePass()); } // level -O4 and -O5 are linktime optimizations } ////////////////////////////////////////////////////////////////////////////////////////// // This function runs optimization passes based on command line arguments. // Returns true if any optimization passes were invoked. bool ldc_optimize_module(llvm::Module* m) { if (!optimize()) { #ifdef USE_METADATA if (!disableStripMetaData) { // This one always needs to run if metadata is generated, because // the code generator will assert if it's not used. ModulePass* stripMD = createStripMetaData(); stripMD->runOnModule(*m); delete stripMD; } #endif return false; } PassManager pm; if (verifyEach) pm.add(createVerifierPass()); addPass(pm, new TargetData(m)); bool optimize = optimizeLevel != 0 || doInline(); unsigned optPos = optimizeLevel != 0 ? optimizeLevel.getPosition() : enableInlining.getPosition(); for (size_t i = 0; i < passList.size(); i++) { // insert -O / -enable-inlining in right position if (optimize && optPos < passList.getPosition(i)) { addPassesForOptLevel(pm); optimize = false; } const PassInfo* pass = passList[i]; if (PassInfo::NormalCtor_t ctor = pass->getNormalCtor()) { addPass(pm, ctor()); } else { const char* arg = pass->getPassArgument(); // may return null if (arg) error("Can't create pass '-%s' (%s)", arg, pass->getPassName()); else error("Can't create pass (%s)", pass->getPassName()); assert(0); // Should be unreachable; root.h:error() calls exit() } } // insert -O / -enable-inlining if specified at the end, if (optimize) addPassesForOptLevel(pm); #ifdef USE_METADATA if (!disableStripMetaData) { // This one is purposely not disabled by disableLangSpecificPasses // because the code generator will assert if it's not used. addPass(pm, createStripMetaData()); } #endif pm.run(*m); return true; }