diff --git a/include/llvm/LTO/LTOCodeGenerator.h b/include/llvm/LTO/LTOCodeGenerator.h index 56d27ca9a77..820d6d5d938 100644 --- a/include/llvm/LTO/LTOCodeGenerator.h +++ b/include/llvm/LTO/LTOCodeGenerator.h @@ -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; diff --git a/include/llvm/Transforms/IPO/PassManagerBuilder.h b/include/llvm/Transforms/IPO/PassManagerBuilder.h index a34b6644ec6..5d574ae0bf0 100644 --- a/include/llvm/Transforms/IPO/PassManagerBuilder.h +++ b/include/llvm/Transforms/IPO/PassManagerBuilder.h @@ -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, diff --git a/lib/LTO/LTOCodeGenerator.cpp b/lib/LTO/LTOCodeGenerator.cpp index 990b578acde..797c64941ef 100644 --- a/lib/LTO/LTOCodeGenerator.cpp +++ b/lib/LTO/LTOCodeGenerator.cpp @@ -71,7 +71,7 @@ LTOCodeGenerator::LTOCodeGenerator() LTOCodeGenerator::LTOCodeGenerator(std::unique_ptr 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; diff --git a/lib/Transforms/IPO/PassManagerBuilder.cpp b/lib/Transforms/IPO/PassManagerBuilder.cpp index 8c1e039484b..46e221037ca 100644 --- a/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -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()); diff --git a/test/LTO/X86/cfi_endproc.ll b/test/LTO/X86/cfi_endproc.ll index 10aedadf15c..57d822b047e 100644 --- a/test/LTO/X86/cfi_endproc.ll +++ b/test/LTO/X86/cfi_endproc.ll @@ -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 diff --git a/test/LTO/X86/linkonce_odr_func.ll b/test/LTO/X86/linkonce_odr_func.ll index 241bc612fe7..7fa6527f47c 100644 --- a/test/LTO/X86/linkonce_odr_func.ll +++ b/test/LTO/X86/linkonce_odr_func.ll @@ -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 index 00000000000..3deb0af37a7 --- /dev/null +++ b/test/tools/gold/opt-level.ll @@ -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 } diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 8decc8ea6d5..93ce3bc0f44 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -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 TM(TheTarget->createTargetMachine( TripleStr, options::mcpu, Features.getString(), Options, RelocationModel, - CodeModel::Default, CodeGenOpt::Aggressive)); + CodeModel::Default, CGOptLevel)); runLTOPasses(M, *TM); diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp index 74d74d5e88b..9cd6587c262 100644 --- a/tools/llvm-lto/llvm-lto.cpp +++ b/tools/llvm-lto/llvm-lto.cpp @@ -26,9 +26,13 @@ using namespace llvm; -static cl::opt -DisableOpt("disable-opt", cl::init(false), - cl::desc("Do not run any optimization passes")); +static cl::opt +OptLevel("O", + cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " + "(default = '-O2')"), + cl::Prefix, + cl::ZeroOrMore, + cl::init('2')); static cl::opt 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] diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index ecafb03b714..142e4307260 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -23,9 +23,13 @@ #include "llvm/Support/TargetSelect.h" // extra command-line flags needed for LTOCodeGenerator -static cl::opt -DisableOpt("disable-opt", cl::init(false), - cl::desc("Do not run any optimization passes")); +static cl::opt +OptLevel("O", + cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " + "(default = '-O2')"), + cl::Prefix, + cl::ZeroOrMore, + cl::init('2')); static cl::opt 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); }