Index: lld/trunk/ELF/CMakeLists.txt =================================================================== --- lld/trunk/ELF/CMakeLists.txt +++ lld/trunk/ELF/CMakeLists.txt @@ -31,6 +31,7 @@ Linker Object Option + Passes MC Support Target Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -44,6 +44,7 @@ llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; + llvm::StringRef LtoNewPmPasses; llvm::StringRef OutputFile; llvm::StringRef SoName; llvm::StringRef Sysroot; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -337,6 +337,7 @@ Config->Entry = getString(Args, OPT_entry); Config->Fini = getString(Args, OPT_fini, "_fini"); Config->Init = getString(Args, OPT_init, "_init"); + Config->LtoNewPmPasses = getString(Args, OPT_lto_newpm_passes); Config->OutputFile = getString(Args, OPT_o); Config->SoName = getString(Args, OPT_soname); Config->Sysroot = getString(Args, OPT_sysroot); @@ -495,6 +496,8 @@ Symtab.scanVersionScript(); Symtab.addCombinedLtoObject(); + if (HasError) + return; for (auto *Arg : Args.filtered(OPT_wrap)) Symtab.wrap(Arg->getValue()); Index: lld/trunk/ELF/LTO.cpp =================================================================== --- lld/trunk/ELF/LTO.cpp +++ lld/trunk/ELF/LTO.cpp @@ -13,6 +13,9 @@ #include "Error.h" #include "InputFiles.h" #include "Symbols.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" @@ -20,13 +23,16 @@ #include "llvm/CodeGen/ParallelCG.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/PassManager.h" #include "llvm/Linker/IRMover.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include using namespace llvm; using namespace llvm::object; @@ -56,10 +62,44 @@ WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true); } -// Run LTO passes. -// Note that the gold plugin has a similar piece of code, so -// it is probably better to move this code to a common place. -static void runLTOPasses(Module &M, TargetMachine &TM) { +static void runNewCustomLtoPasses(Module &M, TargetMachine &TM) { + 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; + if (!Config->DisableVerify) + MPM.addPass(VerifierPass()); + + // Now, add all the passes we've been requested to. + if (!PB.parsePassPipeline(MPM, Config->LtoNewPmPasses)) { + error("unable to parse pass pipeline description: " + + Config->LtoNewPmPasses); + return; + } + + if (!Config->DisableVerify) + MPM.addPass(VerifierPass()); + MPM.run(M, MAM); +} + +static void runOldLtoPasses(Module &M, TargetMachine &TM) { + // Note that the gold plugin has a similar piece of code, so + // it is probably better to move this code to a common place. legacy::PassManager LtoPasses; LtoPasses.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis())); PassManagerBuilder PMB; @@ -71,6 +111,21 @@ PMB.OptLevel = Config->LtoO; PMB.populateLTOPassManager(LtoPasses); LtoPasses.run(M); +} + +static void runLTOPasses(Module &M, TargetMachine &TM) { + if (!Config->LtoNewPmPasses.empty()) { + // The user explicitly asked for a set of passes to be run. + // This needs the new PM to work as there's no clean way to + // pass a set of passes to run in the legacy PM. + runNewCustomLtoPasses(M, TM); + if (HasError) + return; + } else { + // Run the 'default' set of LTO passes. This code still uses + // the legacy PM as the new one is not the default. + runOldLtoPasses(M, TM); + } if (Config->SaveTemps) saveBCFile(M, ".lto.opt.bc"); @@ -226,6 +281,8 @@ std::unique_ptr TM = CreateTargetMachine(); runLTOPasses(*Combined, *TM); + if (HasError) + return {}; return runSplitCodegen(CreateTargetMachine); } Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -255,6 +255,8 @@ // LTO-related options. def lto_jobs : Joined<["--"], "lto-jobs=">, HelpText<"Number of threads to run codegen">; +def lto_newpm_passes : Joined<["--"], "lto-newpm-passes=">, + HelpText<"Passes to run during LTO">; def disable_verify : Flag<["-"], "disable-verify">; def mllvm : Separate<["-"], "mllvm">; def save_temps : Flag<["-"], "save-temps">; Index: lld/trunk/test/ELF/lto/ltopasses-custom.ll =================================================================== --- lld/trunk/test/ELF/lto/ltopasses-custom.ll +++ lld/trunk/test/ELF/lto/ltopasses-custom.ll @@ -0,0 +1,29 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps --lto-newpm-passes=ipsccp -shared +; RUN: ld.lld -m elf_x86_64 %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared +; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s +; RUN: llvm-dis %t2.so.lto.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @barrier() { + fence seq_cst + ret void +} + +; IPSCCP won't remove the fence. +; CHECK: define void @barrier() { +; CHECK-NEXT: fence seq_cst +; CHECK-NEXT: ret void + +; LowerAtomic will remove the fence. +; ATOMIC: define void @barrier() { +; ATOMIC-NEXT: ret void + +; Check that invalid passes are rejected gracefully. +; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2.so \ +; RUN: --lto-newpm-passes=iamnotapass -shared 2>&1 | \ +; RUN: FileCheck %s --check-prefix=INVALID +; INVALID: unable to parse pass pipeline description: iamnotapass