# HG changeset patch # User Frits van Bommel # Date 1238334415 -7200 # Node ID e40c65bd8c5d7616aeb4a451c3e5d845440dbfff # Parent 2bff538fa3b932b093d2e93dfa8c4ac67eade8a8 Allow specific optimization passes to be requested from the command line. Now you can run "`ldc test.d -c -mem2reg -simplifycfg`" if you feel the urge. The -O options are still supported, and are inserted in the passes list in the position where they appear on the command line. (so -simplifycfg -O1 -instcombine does the "right thing") One small change: -inline is renamed to -enable-inlining due to a naming conflict with the option to add the -inline pass. -inline now inserts the inlining pass in the position specified, not in the middle of -O. (ldmd has been updated to translate -inline to -enable-inlining) diff -r 2bff538fa3b9 -r e40c65bd8c5d bin/ldmd --- a/bin/ldmd Sun Mar 29 11:44:32 2009 +0200 +++ b/bin/ldmd Sun Mar 29 15:46:55 2009 +0200 @@ -17,9 +17,17 @@ IDX=0 for arg; do case "$arg" in + -C*) + # turn -Cfoo into -foo. + # Useful for passing -inline to ldc, for instance. + arg="-${arg:2}" + ;; -debug|-debug=*|-version=*) arg="-d$arg" ;; + -inline) + arg="-enable-inlining" + ;; -fPIC) arg="-relocation-model=pic" ;; diff -r 2bff538fa3b9 -r e40c65bd8c5d dmd/mars.h --- a/dmd/mars.h Sun Mar 29 11:44:32 2009 +0200 +++ b/dmd/mars.h Sun Mar 29 15:46:55 2009 +0200 @@ -138,8 +138,11 @@ bool link; // perform link bool verbose; // verbose compile char symdebug; // insert debug symbolic information +#if !IN_LLVM + // LDC uses a different mechanism bool optimize; // run optimizer char optimizeLevel; // optimization level +#endif ARCH cpu; // target CPU OS os; // target OS bool is64bit; // generate 64 bit code @@ -210,7 +213,6 @@ OUTPUTFLAG output_bc; OUTPUTFLAG output_s; OUTPUTFLAG output_o; - bool llvmInline; bool llvmAnnotate; bool useInlineAsm; diff -r 2bff538fa3b9 -r e40c65bd8c5d dmd2/mars.h --- a/dmd2/mars.h Sun Mar 29 11:44:32 2009 +0200 +++ b/dmd2/mars.h Sun Mar 29 15:46:55 2009 +0200 @@ -73,8 +73,11 @@ bool link; // perform link bool verbose; // verbose compile char symdebug; // insert debug symbolic information +#if !IN_LLVM + // LDC uses a different mechanism bool optimize; // run optimizer char optimizeLevel; // optimization level +#endif ARCH cpu; // target CPU OS os; // target OS bool is64bit; // generate 64 bit code @@ -145,7 +148,6 @@ OUTPUTFLAG output_bc; OUTPUTFLAG output_s; OUTPUTFLAG output_o; - bool llvmInline; bool llvmAnnotate; bool useInlineAsm; diff -r 2bff538fa3b9 -r e40c65bd8c5d gen/cl_options.cpp --- a/gen/cl_options.cpp Sun Mar 29 11:44:32 2009 +0200 +++ b/gen/cl_options.cpp Sun Mar 29 15:46:55 2009 +0200 @@ -20,16 +20,6 @@ cl::PositionalEatsArgs); - -// TODO: Replace this with a proper PassNameParser-based solution -static cl::opt doInline("inline", - cl::desc("Do function inlining"), - cl::location(global.params.llvmInline), - cl::ZeroOrMore, - cl::init(false)); - - - static cl::opt useDeprecated("d", cl::desc("Allow deprecated language features"), cl::ZeroOrMore, @@ -59,22 +49,6 @@ cl::ZeroOrMore, cl::location(global.params.warnings)); - -static cl::opt optimizeLevel( - cl::desc("Setting the optimization level:"), - cl::ZeroOrMore, - cl::values( - clEnumValN(2, "O", "Equivalent to -O2"), - clEnumValN(0, "O0", "Trivial optimizations only"), - 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::location(global.params.optimizeLevel), - cl::init(-1)); - static cl::opt debugInfo( cl::desc("Generating debug information:"), cl::ZeroOrMore, diff -r 2bff538fa3b9 -r e40c65bd8c5d gen/linker.cpp --- a/gen/linker.cpp Sun Mar 29 11:44:32 2009 +0200 +++ b/gen/linker.cpp Sun Mar 29 15:46:55 2009 +0200 @@ -13,6 +13,7 @@ #define NO_COUT_LOGGER #include "gen/logger.h" #include "gen/cl_options.h" +#include "gen/optimizer.h" ////////////////////////////////////////////////////////////////////////////// @@ -111,12 +112,12 @@ args.push_back("-strip-debug"); // optimization level - if (!global.params.optimize) + if (!optimize()) args.push_back("-disable-opt"); else { const char* s = 0; - switch(global.params.optimizeLevel) + switch(optLevel()) { case 0: args.push_back("-disable-opt"); @@ -138,7 +139,7 @@ } // inlining - if (!(global.params.useInline || global.params.llvmInline)) + if (!(global.params.useInline || doInline())) { args.push_back("-disable-inlining"); } diff -r 2bff538fa3b9 -r e40c65bd8c5d gen/main.cpp --- a/gen/main.cpp Sun Mar 29 11:44:32 2009 +0200 +++ b/gen/main.cpp Sun Mar 29 15:46:55 2009 +0200 @@ -192,8 +192,6 @@ cl::SetVersionPrinter(&printVersion); cl::ParseCommandLineOptions(final_args.size(), (char**)&final_args[0], "LLVM-based D Compiler\n", true); - global.params.optimize = (global.params.optimizeLevel >= 0); - // Negated options global.params.link = !compileOnly; global.params.obj = !dontWriteObj; diff -r 2bff538fa3b9 -r e40c65bd8c5d gen/optimizer.cpp --- a/gen/optimizer.cpp Sun Mar 29 11:44:32 2009 +0200 +++ b/gen/optimizer.cpp Sun Mar 29 15:46:55 2009 +0200 @@ -1,32 +1,68 @@ +#include "gen/optimizer.h" + #include "llvm/PassManager.h" #include "llvm/LinkAllPasses.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Target/TargetData.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/PassNameParser.h" + +#include "root.h" // error() & fatal() +#include "mars.h" // global flags 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 + ); -// this function runs some or all of the std-compile-opts passes depending on the -// optimization level given. +static cl::opt optimizeLevel( + cl::desc("Setting the optimization level:"), + cl::ZeroOrMore, + cl::values( + clEnumValN(2, "O", "Equivalent to -O2"), + clEnumValN(0, "O0", "Trivial optimizations only"), + 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(-1)); -void ldc_optimize_module(Module* m, char lvl, bool doinline) -{ - if (!doinline && lvl < 0) - return; +static cl::opt enableInlining("enable-inlining", + cl::desc("Enable function inlining (in -O, if given)"), + cl::ZeroOrMore, + cl::init(false)); + +// Some accessors for the linker: (llvm-ld version only, currently unused?) +bool doInline() { + return enableInlining; +} - PassManager pm; - pm.add(new TargetData(m)); +int optLevel() { + return optimizeLevel; +} +bool optimize() { + return (optimizeLevel != -1) || enableInlining || passList.empty(); +} + +// this function inserts some or all of the std-compile-opts passes depending on the +// optimization level given. +static void addPassesForOptLevel(PassManager& pm) { // -O0 - if (lvl >= 0) + if (optimizeLevel >= 0) { //pm.add(createStripDeadPrototypesPass()); pm.add(createGlobalDCEPass()); } // -O1 - if (lvl >= 1) + if (optimizeLevel >= 1) { pm.add(createRaiseAllocationsPass()); pm.add(createCFGSimplificationPass()); @@ -36,7 +72,7 @@ } // -O2 - if (lvl >= 2) + if (optimizeLevel >= 2) { pm.add(createIPConstantPropagationPass()); pm.add(createDeadArgEliminationPass()); @@ -46,12 +82,12 @@ } // -inline - if (doinline) { + if (enableInlining) { pm.add(createFunctionInliningPass()); } // -O3 - if (lvl >= 3) + if (optimizeLevel >= 3) { pm.add(createArgumentPromotionPass()); pm.add(createTailDuplicationPass()); @@ -86,6 +122,48 @@ } // 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 (!enableInlining && optimizeLevel == -1 && passList.empty()) + return false; + + PassManager pm; + pm.add(new TargetData(m)); + + bool optimize = (optimizeLevel != -1) || enableInlining; + + unsigned optPos = optimizeLevel != -1 + ? 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()) { + pm.add(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()); + fatal(); + } + } + // insert -O / -enable-inlining if specified at the end, + if (optimize) + addPassesForOptLevel(pm); pm.run(*m); + return true; } diff -r 2bff538fa3b9 -r e40c65bd8c5d gen/toobj.cpp --- a/gen/toobj.cpp Sun Mar 29 11:44:32 2009 +0200 +++ b/gen/toobj.cpp Sun Mar 29 15:46:55 2009 +0200 @@ -49,6 +49,7 @@ #include "gen/runtime.h" #include "gen/abi.h" #include "gen/cl_options.h" +#include "gen/optimizer.h" #include "ir/irvar.h" #include "ir/irmodule.h" @@ -61,9 +62,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -// in gen/optimize.cpp -void ldc_optimize_module(llvm::Module* m, char lvl, bool doinline); - // fwd decl void write_asm_to_file(llvm::TargetMachine &Target, llvm::Module& m, llvm::raw_fd_ostream& Out); void assemble(const llvm::sys::Path& asmpath, const llvm::sys::Path& objpath); @@ -189,10 +187,10 @@ void writeModule(llvm::Module* m, std::string filename) { // run optimizer - ldc_optimize_module(m, global.params.optimizeLevel, global.params.llvmInline); + bool reverify = ldc_optimize_module(m); // verify the llvm - if (!noVerify && (global.params.optimizeLevel >= 0 || global.params.llvmInline)) { + if (!noVerify && reverify) { std::string verifyErr; Logger::println("Verifying module... again..."); LOG_SCOPE;