diff --git a/include/llvm/LTO/Config.h b/include/llvm/LTO/Config.h index bb6c145bc12..3d19ab60497 100644 --- a/include/llvm/LTO/Config.h +++ b/include/llvm/LTO/Config.h @@ -78,6 +78,11 @@ struct Config { /// Disable entirely the optimizer, including importing for ThinLTO bool CodeGenOnly = false; + /// If this field is set, the set of passes run in the middle-end optimizer + /// will be the one specified by the string. Only works with the new pass + /// manager as the old one doesn't have this ability. + std::string OptPipeline; + /// Setting this field will replace target triples in input files with this /// triple. std::string OverrideTriple; @@ -164,6 +169,7 @@ struct Config { RelocModel(std::move(X.RelocModel)), CodeModel(std::move(X.CodeModel)), CGOptLevel(std::move(X.CGOptLevel)), OptLevel(std::move(X.OptLevel)), DisableVerify(std::move(X.DisableVerify)), + OptPipeline(std::move(X.OptPipeline)), OverrideTriple(std::move(X.OverrideTriple)), DefaultTriple(std::move(X.DefaultTriple)), ShouldDiscardValueNames(std::move(X.ShouldDiscardValueNames)), @@ -187,6 +193,7 @@ struct Config { CGOptLevel = std::move(X.CGOptLevel); OptLevel = std::move(X.OptLevel); DisableVerify = std::move(X.DisableVerify); + OptPipeline = std::move(X.OptPipeline); OverrideTriple = std::move(X.OverrideTriple); DefaultTriple = std::move(X.DefaultTriple); ShouldDiscardValueNames = std::move(X.ShouldDiscardValueNames); diff --git a/lib/LTO/LLVMBuild.txt b/lib/LTO/LLVMBuild.txt index f6bcaf558bc..b940362e523 100644 --- a/lib/LTO/LLVMBuild.txt +++ b/lib/LTO/LLVMBuild.txt @@ -31,6 +31,7 @@ required_libraries = MC ObjCARC Object + Passes Scalar Support Target diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp index 3ed52ba575d..75f3182ee1d 100644 --- a/lib/LTO/LTOBackend.cpp +++ b/lib/LTO/LTOBackend.cpp @@ -15,12 +15,18 @@ //===----------------------------------------------------------------------===// #include "llvm/LTO/LTOBackend.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Analysis/LoopPassManager.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Verifier.h" #include "llvm/LTO/LTO.h" #include "llvm/MC/SubtargetFeature.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/TargetRegistry.h" @@ -115,6 +121,41 @@ createTargetMachine(Config &Conf, StringRef TheTriple, Conf.CodeModel, Conf.CGOptLevel)); } +static void runNewPMCustomPasses(Module &Mod, TargetMachine *TM, + std::string PipelineDesc, + bool DisableVerify) { + PassBuilder PB(TM); + AAManager AA; + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + // Register the AA manager first so that our version is the one used. + FAM.registerPass([&] { return std::move(AA); }); + + // Register all the basic analyses with the managers. + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM; + + // Always verify the input. + MPM.addPass(VerifierPass()); + + // Now, add all the passes we've been requested to. + if (!PB.parsePassPipeline(MPM, PipelineDesc)) + report_fatal_error("unable to parse pass pipeline description: " + + PipelineDesc); + + if (!DisableVerify) + MPM.addPass(VerifierPass()); + MPM.run(Mod, MAM); +} + static void runOldPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, bool IsThinLto) { legacy::PassManager passes; @@ -140,7 +181,10 @@ static void runOldPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, bool opt(Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, bool IsThinLto) { Mod.setDataLayout(TM->createDataLayout()); - runOldPMPasses(Conf, Mod, TM, IsThinLto); + if (Conf.OptPipeline.empty()) + runOldPMPasses(Conf, Mod, TM, IsThinLto); + else + runNewPMCustomPasses(Mod, TM, Conf.OptPipeline, Conf.DisableVerify); return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } diff --git a/test/tools/llvm-lto2/X86/pipeline.ll b/test/tools/llvm-lto2/X86/pipeline.ll new file mode 100644 index 00000000000..3cdf64e8999 --- /dev/null +++ b/test/tools/llvm-lto2/X86/pipeline.ll @@ -0,0 +1,24 @@ +; RUN: llvm-as < %s > %t1.bc + +; Try a custom pipeline +; RUN: llvm-lto2 %t1.bc -o %t.o -save-temps \ +; RUN: -r %t1.bc,patatino,px -opt-pipeline loweratomic +; RUN: llvm-dis < %t.o.0.4.opt.bc | FileCheck %s --check-prefix=CUSTOM + +target triple = "x86_64-unknown-linux-gnu" + +define void @patatino() { + fence seq_cst + ret void +} + +; CUSTOM: define void @patatino() { +; CUSTOM-NEXT: ret void +; CUSTOM-NEXT: } + +; Check that invalid pipeline are caught as errors. +; RUN: not llvm-lto2 %t1.bc -o %t.o -save-temps \ +; RUN: -r %t1.bc,patatino,px -opt-pipeline foogoo 2>&1 | \ +; RUN: FileCheck %s --check-prefix=ERR + +; ERR: LLVM ERROR: unable to parse pass pipeline description: foogoo diff --git a/tools/llvm-lto2/llvm-lto2.cpp b/tools/llvm-lto2/llvm-lto2.cpp index 06c3d0406cf..a2cc54ad7da 100644 --- a/tools/llvm-lto2/llvm-lto2.cpp +++ b/tools/llvm-lto2/llvm-lto2.cpp @@ -35,6 +35,10 @@ static cl::opt OutputFilename("o", cl::Required, static cl::opt CacheDir("cache-dir", cl::desc("Cache Directory"), cl::value_desc("directory")); +static cl::opt OptPipeline("opt-pipeline", + cl::desc("Optimizer Pipeline"), + cl::value_desc("pipeline")); + static cl::opt SaveTemps("save-temps", cl::desc("Save temporary files")); static cl::opt @@ -148,6 +152,9 @@ int main(int argc, char **argv) { check(Conf.addSaveTemps(OutputFilename + "."), "Config::addSaveTemps failed"); + // Run a custom pipeline, if asked for. + Conf.OptPipeline = OptPipeline; + ThinBackend Backend; if (ThinLTODistributedIndexes) Backend = createWriteIndexesThinBackend("", "", true, "");