diff gen/optimizer.cpp @ 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 6aaa3d3c1183
children 461a85f0db31
line wrap: on
line diff
--- 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
-// optimization level given.
+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));
 
-void ldc_optimize_module(Module* m, char lvl, bool doinline)
-{
-    if (!doinline && lvl < 0)
-        return;
+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;
+}
 
-    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<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;
 }