changeset 1170:e40c65bd8c5d

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<N> 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<N>. (ldmd has been updated to translate -inline to -enable-inlining)
author Frits van Bommel <fvbommel wxs.nl>
date Sun, 29 Mar 2009 15:46:55 +0200
parents 2bff538fa3b9
children 461a85f0db31
files bin/ldmd dmd/mars.h dmd2/mars.h gen/cl_options.cpp gen/linker.cpp gen/main.cpp gen/optimizer.cpp gen/toobj.cpp
diffstat 8 files changed, 115 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- 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"
         ;;
--- 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;
 
--- 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;
 
--- 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<bool, true> doInline("inline",
-    cl::desc("Do function inlining"),
-    cl::location(global.params.llvmInline),
-    cl::ZeroOrMore,
-    cl::init(false));
-
-
-
 static cl::opt<bool, true> useDeprecated("d",
     cl::desc("Allow deprecated language features"),
     cl::ZeroOrMore,
@@ -59,22 +49,6 @@
     cl::ZeroOrMore,
     cl::location(global.params.warnings));
 
-
-static cl::opt<char, true> 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<char, true> debugInfo(
     cl::desc("Generating debug information:"),
     cl::ZeroOrMore,
--- 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");
     }
--- 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;
--- 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<const PassInfo*, bool, PassNameParser>
+    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
+static cl::opt<char> 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));
+
+static cl::opt<bool> enableInlining("enable-inlining",
+    cl::desc("Enable function inlining (in -O<N>, if given)"),
+    cl::ZeroOrMore,
+    cl::init(false));
+
+// Some accessors for the linker: (llvm-ld version only, currently unused?)
+bool doInline() {
+    return enableInlining;
+}
+
+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.
-
-void ldc_optimize_module(Module* m, char lvl, bool doinline)
-{
-    if (!doinline && lvl < 0)
-        return;
-
-    PassManager pm;
-    pm.add(new TargetData(m));
-
+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<N> / -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<N> / -enable-inlining if specified at the end,
+    if (optimize)
+        addPassesForOptLevel(pm);
 
     pm.run(*m);
+    return true;
 }
--- 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;