libLTO, llvm-lto, gold: Introduce flag for controlling optimization level.
authorPeter Collingbourne <peter@pcc.me.uk>
Thu, 19 Mar 2015 22:01:00 +0000 (22:01 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Thu, 19 Mar 2015 22:01:00 +0000 (22:01 +0000)
This change also introduces a link-time optimization level of 1. This
optimization level runs only the globaldce pass as well as cleanup passes for
passes that run at -O0, specifically simplifycfg which cleans up lowerbitsets.

http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20150316/266951.html

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@232769 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/LTO/LTOCodeGenerator.h
include/llvm/Transforms/IPO/PassManagerBuilder.h
lib/LTO/LTOCodeGenerator.cpp
lib/Transforms/IPO/PassManagerBuilder.cpp
test/LTO/X86/cfi_endproc.ll
test/LTO/X86/linkonce_odr_func.ll
test/tools/gold/opt-level.ll [new file with mode: 0644]
tools/gold/gold-plugin.cpp
tools/llvm-lto/llvm-lto.cpp
tools/lto/lto.cpp

index 56d27ca9a77ae3bfb0f376e17649a4e2d2a12717..820d6d5d9384e9f62ffe5e8723d431129af164b4 100644 (file)
@@ -76,6 +76,7 @@ struct LTOCodeGenerator {
 
   void setCpu(const char *mCpu) { MCpu = mCpu; }
   void setAttr(const char *mAttr) { MAttr = mAttr; }
+  void setOptLevel(unsigned optLevel) { OptLevel = optLevel; }
 
   void addMustPreserveSymbol(const char *sym) { MustPreserveSymbols[sym] = 1; }
 
@@ -102,7 +103,6 @@ struct LTOCodeGenerator {
   //  Do not try to remove the object file in LTOCodeGenerator's destructor
   //  as we don't who (LTOCodeGenerator or the obj file) will last longer.
   bool compile_to_file(const char **name,
-                       bool disableOpt,
                        bool disableInline,
                        bool disableGVNLoadPRE,
                        bool disableVectorization,
@@ -114,15 +114,13 @@ struct LTOCodeGenerator {
   // caller. This function should delete intermediate object file once its content
   // is brought to memory. Return NULL if the compilation was not successful.
   const void *compile(size_t *length,
-                      bool disableOpt,
                       bool disableInline,
                       bool disableGVNLoadPRE,
                       bool disableVectorization,
                       std::string &errMsg);
 
   // Optimizes the merged module. Returns true on success.
-  bool optimize(bool disableOpt,
-                bool disableInline,
+  bool optimize(bool disableInline,
                 bool disableGVNLoadPRE,
                 bool disableVectorization,
                 std::string &errMsg);
@@ -171,6 +169,7 @@ private:
   std::string MAttr;
   std::string NativeObjectPath;
   TargetOptions Options;
+  unsigned OptLevel;
   lto_diagnostic_handler_t DiagHandler;
   void *DiagContext;
   LTOModule *OwnedModule;
index a34b6644ec63a843d983779711b5d6aa104f1d0b..5d574ae0bf0f298b7b975dd563960cee3bad1243 100644 (file)
@@ -140,6 +140,7 @@ private:
                          legacy::PassManagerBase &PM) const;
   void addInitialAliasAnalysisPasses(legacy::PassManagerBase &PM) const;
   void addLTOOptimizationPasses(legacy::PassManagerBase &PM);
+  void addLateLTOOptimizationPasses(legacy::PassManagerBase &PM);
 
 public:
   /// populateFunctionPassManager - This fills in the function pass manager,
index 990b578acde39883ef4a46b4182218f182e0b6ca..797c64941efb02b40e7d6a85dd5439221d42d054 100644 (file)
@@ -71,7 +71,7 @@ LTOCodeGenerator::LTOCodeGenerator()
 
 LTOCodeGenerator::LTOCodeGenerator(std::unique_ptr<LLVMContext> Context)
     : OwnedContext(std::move(Context)), Context(*OwnedContext),
-      IRLinker(new Module("ld-temp.o", *OwnedContext)) {
+      IRLinker(new Module("ld-temp.o", *OwnedContext)), OptLevel(2) {
   initialize();
 }
 
@@ -291,12 +291,11 @@ const void *LTOCodeGenerator::compileOptimized(size_t *length,
 
 
 bool LTOCodeGenerator::compile_to_file(const char **name,
-                                       bool disableOpt,
                                        bool disableInline,
                                        bool disableGVNLoadPRE,
                                        bool disableVectorization,
                                        std::string &errMsg) {
-  if (!optimize(disableOpt, disableInline, disableGVNLoadPRE,
+  if (!optimize(disableInline, disableGVNLoadPRE,
                 disableVectorization, errMsg))
     return false;
 
@@ -304,12 +303,11 @@ bool LTOCodeGenerator::compile_to_file(const char **name,
 }
 
 const void* LTOCodeGenerator::compile(size_t *length,
-                                      bool disableOpt,
                                       bool disableInline,
                                       bool disableGVNLoadPRE,
                                       bool disableVectorization,
                                       std::string &errMsg) {
-  if (!optimize(disableOpt, disableInline, disableGVNLoadPRE,
+  if (!optimize(disableInline, disableGVNLoadPRE,
                 disableVectorization, errMsg))
     return nullptr;
 
@@ -363,9 +361,25 @@ bool LTOCodeGenerator::determineTarget(std::string &errMsg) {
       MCpu = "cyclone";
   }
 
+  CodeGenOpt::Level CGOptLevel;
+  switch (OptLevel) {
+  case 0:
+    CGOptLevel = CodeGenOpt::None;
+    break;
+  case 1:
+    CGOptLevel = CodeGenOpt::Less;
+    break;
+  case 2:
+    CGOptLevel = CodeGenOpt::Default;
+    break;
+  case 3:
+    CGOptLevel = CodeGenOpt::Aggressive;
+    break;
+  }
+
   TargetMach = march->createTargetMachine(TripleStr, MCpu, FeatureStr, Options,
                                           RelocModel, CodeModel::Default,
-                                          CodeGenOpt::Aggressive);
+                                          CGOptLevel);
   return true;
 }
 
@@ -512,8 +526,7 @@ void LTOCodeGenerator::applyScopeRestrictions() {
 }
 
 /// Optimize merged modules using various IPO passes
-bool LTOCodeGenerator::optimize(bool DisableOpt,
-                                bool DisableInline,
+bool LTOCodeGenerator::optimize(bool DisableInline,
                                 bool DisableGVNLoadPRE,
                                 bool DisableVectorization,
                                 std::string &errMsg) {
@@ -542,8 +555,7 @@ bool LTOCodeGenerator::optimize(bool DisableOpt,
   if (!DisableInline)
     PMB.Inliner = createFunctionInliningPass();
   PMB.LibraryInfo = new TargetLibraryInfoImpl(TargetTriple);
-  if (DisableOpt)
-    PMB.OptLevel = 0;
+  PMB.OptLevel = OptLevel;
   PMB.VerifyInput = true;
   PMB.VerifyOutput = true;
 
index 8c1e039484b2b16bc135ceb919dc396d092f5b71..46e221037ca90a12526318fb173e55c260212c3b 100644 (file)
@@ -491,10 +491,10 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) {
   addExtensionsToPM(EP_Peephole, PM);
 
   PM.add(createJumpThreadingPass());
+}
 
-  // Lower bitset metadata to bitsets.
-  PM.add(createLowerBitSetsPass());
-
+void PassManagerBuilder::addLateLTOOptimizationPasses(
+    legacy::PassManagerBase &PM) {
   // Delete basic blocks, which optimization passes may have killed.
   PM.add(createCFGSimplificationPass());
 
@@ -516,9 +516,17 @@ void PassManagerBuilder::populateLTOPassManager(legacy::PassManagerBase &PM) {
     PM.add(createDebugInfoVerifierPass());
   }
 
-  if (OptLevel != 0)
+  if (OptLevel > 1)
     addLTOOptimizationPasses(PM);
 
+  // Lower bit sets to globals. This pass supports Clang's control flow
+  // integrity mechanisms (-fsanitize=cfi*) and needs to run at link time if CFI
+  // is enabled. The pass does nothing if CFI is disabled.
+  PM.add(createLowerBitSetsPass());
+
+  if (OptLevel != 0)
+    addLateLTOOptimizationPasses(PM);
+
   if (VerifyOutput) {
     PM.add(createVerifierPass());
     PM.add(createDebugInfoVerifierPass());
index 10aedadf15caadc73167cafc5e39fe8eb2f79d03..57d822b047e33ee024845eac2700088a545a9a7c 100644 (file)
@@ -25,7 +25,7 @@ define i32 @main(i32 %argc, i8** %argv) {
   ret i32 0
 }
 
-; RUN: llvm-lto -o %t -dso-symbol=zed1 -dso-symbol=zed2 %t1 -disable-opt
+; RUN: llvm-lto -o %t -dso-symbol=zed1 -dso-symbol=zed2 %t1 -O0
 ; RUN: llvm-nm %t | FileCheck %s -check-prefix=ZED1_AND_ZED2
 ; ZED1_AND_ZED2: V zed1
 @zed1 = linkonce_odr global i32 42
index 241bc612fe7ec88756b62d364fb408c6a6cef403..7fa6527f47c70a2cf0e679f43e926b1f07cc6f6d 100644 (file)
@@ -1,6 +1,6 @@
 ; RUN: llvm-as < %s >%t1
 ; RUN: llvm-lto -o %t2 -dso-symbol=foo1 -dso-symbol=foo2 -dso-symbol=foo3 \
-; RUN:     -dso-symbol=foo4 -dso-symbol=v1 -dso-symbol=v2 %t1 -disable-opt
+; RUN:     -dso-symbol=foo4 -dso-symbol=v1 -dso-symbol=v2 %t1 -O0
 ; RUN: llvm-nm %t2 | FileCheck %s
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
diff --git a/test/tools/gold/opt-level.ll b/test/tools/gold/opt-level.ll
new file mode 100644 (file)
index 0000000..3deb0af
--- /dev/null
@@ -0,0 +1,50 @@
+; RUN: llvm-as -o %t.bc %s
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
+; RUN:    -plugin-opt=O0 -r -o %t.o %t.bc
+; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
+; RUN:    -plugin-opt=O1 -r -o %t.o %t.bc
+; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O1 %s
+; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
+; RUN:    -plugin-opt=O2 -r -o %t.o %t.bc
+; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O2 %s
+
+; CHECK-O0: define internal void @foo(
+; CHECK-O1: define internal void @foo(
+; CHECK-O2-NOT: define internal void @foo(
+define internal void @foo() {
+  ret void
+}
+
+; CHECK-O0: define internal i32 @bar(
+; CHECK-O1: define internal i32 @bar(
+define internal i32 @bar(i1 %p) {
+  br i1 %p, label %t, label %f
+
+t:
+  br label %end
+
+f:
+  br label %end
+
+end:
+  ; CHECK-O0: phi
+  ; CHECK-O1: select
+  %r = phi i32 [ 1, %t ], [ 2, %f ]
+  ret i32 %r
+}
+
+define void @baz() {
+  call void @foo()
+  %c = call i32 @bar(i1 true)
+  ret void
+}
+
+@a = constant i32 1
+
+!0 = !{!"bitset1", i32* @a, i32 0}
+
+; CHECK-O0-NOT: llvm.bitsets
+; CHECK-O1-NOT: llvm.bitsets
+; CHECK-O2-NOT: llvm.bitsets
+!llvm.bitsets = !{ !0 }
index 8decc8ea6d549832cbd048ba7478844d4eac305e..93ce3bc0f446b2fbd1223dd3055b9f6252007fd0 100644 (file)
@@ -91,6 +91,7 @@ namespace options {
   };
   static bool generate_api_file = false;
   static OutputType TheOutputType = OT_NORMAL;
+  static unsigned OptLevel = 2;
   static std::string obj_path;
   static std::string extra_library_path;
   static std::string triple;
@@ -124,6 +125,10 @@ namespace options {
       TheOutputType = OT_SAVE_TEMPS;
     } else if (opt == "disable-output") {
       TheOutputType = OT_DISABLE;
+    } else if (opt.size() == 2 && opt[0] == 'O') {
+      if (opt[1] < '0' || opt[1] > '3')
+        report_fatal_error("Optimization level must be between 0 and 3");
+      OptLevel = opt[1] - '0';
     } else {
       // Save this option to pass to the code generator.
       // ParseCommandLineOptions() expects argv[0] to be program name. Lazily
@@ -724,6 +729,7 @@ static void runLTOPasses(Module &M, TargetMachine &TM) {
   PMB.VerifyOutput = true;
   PMB.LoopVectorize = true;
   PMB.SLPVectorize = true;
+  PMB.OptLevel = options::OptLevel;
   PMB.populateLTOPassManager(passes);
   passes.run(M);
 }
@@ -754,9 +760,24 @@ static void codegen(Module &M) {
     Features.AddFeature(A);
 
   TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+  CodeGenOpt::Level CGOptLevel;
+  switch (options::OptLevel) {
+  case 0:
+    CGOptLevel = CodeGenOpt::None;
+    break;
+  case 1:
+    CGOptLevel = CodeGenOpt::Less;
+    break;
+  case 2:
+    CGOptLevel = CodeGenOpt::Default;
+    break;
+  case 3:
+    CGOptLevel = CodeGenOpt::Aggressive;
+    break;
+  }
   std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
       TripleStr, options::mcpu, Features.getString(), Options, RelocationModel,
-      CodeModel::Default, CodeGenOpt::Aggressive));
+      CodeModel::Default, CGOptLevel));
 
   runLTOPasses(M, *TM);
 
index 74d74d5e88b8f4eeba3c062f9c68bed4ee545d91..9cd6587c26223a8c4176e8b3532a64b8e3b3c69e 100644 (file)
 
 using namespace llvm;
 
-static cl::opt<bool>
-DisableOpt("disable-opt", cl::init(false),
-  cl::desc("Do not run any optimization passes"));
+static cl::opt<char>
+OptLevel("O",
+         cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+                  "(default = '-O2')"),
+         cl::Prefix,
+         cl::ZeroOrMore,
+         cl::init('2'));
 
 static cl::opt<bool>
 DisableInline("disable-inlining", cl::init(false),
@@ -146,6 +150,11 @@ int main(int argc, char **argv) {
   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
   cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");
 
+  if (OptLevel < '0' || OptLevel > '3') {
+    errs() << argv[0] << ": optimization level must be between 0 and 3\n";
+    return 1;
+  }
+
   // Initialize the configured targets.
   InitializeAllTargets();
   InitializeAllTargetMCs();
@@ -231,6 +240,8 @@ int main(int argc, char **argv) {
   // Set cpu and attrs strings for the default target/subtarget.
   CodeGen.setCpu(MCPU.c_str());
 
+  CodeGen.setOptLevel(OptLevel - '0');
+
   std::string attrs;
   for (unsigned i = 0; i < MAttrs.size(); ++i) {
     if (i > 0)
@@ -245,7 +256,7 @@ int main(int argc, char **argv) {
     size_t len = 0;
     std::string ErrorInfo;
     const void *Code =
-        CodeGen.compile(&len, DisableOpt, DisableInline, DisableGVNLoadPRE,
+        CodeGen.compile(&len, DisableInline, DisableGVNLoadPRE,
                         DisableLTOVectorization, ErrorInfo);
     if (!Code) {
       errs() << argv[0]
@@ -265,7 +276,7 @@ int main(int argc, char **argv) {
   } else {
     std::string ErrorInfo;
     const char *OutputName = nullptr;
-    if (!CodeGen.compile_to_file(&OutputName, DisableOpt, DisableInline,
+    if (!CodeGen.compile_to_file(&OutputName, DisableInline,
                                  DisableGVNLoadPRE, DisableLTOVectorization,
                                  ErrorInfo)) {
       errs() << argv[0]
index ecafb03b714fcbb491e3aa3a726a5aa642481371..142e4307260434f5ecebd6c0e261461e92732899 100644 (file)
 #include "llvm/Support/TargetSelect.h"
 
 // extra command-line flags needed for LTOCodeGenerator
-static cl::opt<bool>
-DisableOpt("disable-opt", cl::init(false),
-  cl::desc("Do not run any optimization passes"));
+static cl::opt<char>
+OptLevel("O",
+         cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+                  "(default = '-O2')"),
+         cl::Prefix,
+         cl::ZeroOrMore,
+         cl::init('2'));
 
 static cl::opt<bool>
 DisableInline("disable-inlining", cl::init(false),
@@ -85,6 +89,10 @@ static void lto_add_attrs(lto_code_gen_t cg) {
 
     CG->setAttr(attrs.c_str());
   }
+
+  if (OptLevel < '0' || OptLevel > '3')
+    report_fatal_error("Optimization level must be between 0 and 3");
+  CG->setOptLevel(OptLevel - '0');
 }
 
 extern const char* lto_get_version() {
@@ -281,54 +289,42 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg,
   unwrap(cg)->addMustPreserveSymbol(symbol);
 }
 
-bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) {
+static void maybeParseOptions() {
   if (!parsedOptions) {
     unwrap(cg)->parseCodeGenDebugOptions();
     lto_add_attrs(cg);
     parsedOptions = true;
   }
+}
+
+bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) {
+  maybeParseOptions();
   return !unwrap(cg)->writeMergedModules(path, sLastErrorString);
 }
 
 const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) {
-  if (!parsedOptions) {
-    unwrap(cg)->parseCodeGenDebugOptions();
-    lto_add_attrs(cg);
-    parsedOptions = true;
-  }
-  return unwrap(cg)->compile(length, DisableOpt, DisableInline,
+  maybeParseOptions();
+  return unwrap(cg)->compile(length, DisableInline,
                              DisableGVNLoadPRE, DisableLTOVectorization,
                              sLastErrorString);
 }
 
 bool lto_codegen_optimize(lto_code_gen_t cg) {
-  if (!parsedOptions) {
-    unwrap(cg)->parseCodeGenDebugOptions();
-    lto_add_attrs(cg);
-    parsedOptions = true;
-  }
-  return !unwrap(cg)->optimize(DisableOpt, DisableInline,
+  maybeParseOptions();
+  return !unwrap(cg)->optimize(DisableInline,
                                DisableGVNLoadPRE, DisableLTOVectorization,
                                sLastErrorString);
 }
 
 const void *lto_codegen_compile_optimized(lto_code_gen_t cg, size_t *length) {
-  if (!parsedOptions) {
-    unwrap(cg)->parseCodeGenDebugOptions();
-    lto_add_attrs(cg);
-    parsedOptions = true;
-  }
+  maybeParseOptions();
   return unwrap(cg)->compileOptimized(length, sLastErrorString);
 }
 
 bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) {
-  if (!parsedOptions) {
-    unwrap(cg)->parseCodeGenDebugOptions();
-    lto_add_attrs(cg);
-    parsedOptions = true;
-  }
+  maybeParseOptions();
   return !unwrap(cg)->compile_to_file(
-      name, DisableOpt, DisableInline, DisableGVNLoadPRE,
+      name, DisableInline, DisableGVNLoadPRE,
       DisableLTOVectorization, sLastErrorString);
 }