diff options
Diffstat (limited to 'llvm/lib/LTO/LTOBackend.cpp')
| -rw-r--r-- | llvm/lib/LTO/LTOBackend.cpp | 240 |
1 files changed, 189 insertions, 51 deletions
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 0c395f9bbf28..1796d6ba60cc 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -50,6 +50,30 @@ using namespace llvm; using namespace lto; +#define DEBUG_TYPE "lto-backend" + +enum class LTOBitcodeEmbedding { + DoNotEmbed = 0, + EmbedOptimized = 1, + EmbedPostMergePreOptimized = 2 +}; + +static cl::opt<LTOBitcodeEmbedding> EmbedBitcode( + "lto-embed-bitcode", cl::init(LTOBitcodeEmbedding::DoNotEmbed), + cl::values(clEnumValN(LTOBitcodeEmbedding::DoNotEmbed, "none", + "Do not embed"), + clEnumValN(LTOBitcodeEmbedding::EmbedOptimized, "optimized", + "Embed after all optimization passes"), + clEnumValN(LTOBitcodeEmbedding::EmbedPostMergePreOptimized, + "post-merge-pre-opt", + "Embed post merge, but before optimizations")), + cl::desc("Embed LLVM bitcode in object files produced by LTO")); + +static cl::opt<bool> ThinLTOAssumeMerged( + "thinlto-assume-merged", cl::init(false), + cl::desc("Assume the input has already undergone ThinLTO function " + "importing and the other pre-optimization pipeline changes.")); + LLVM_ATTRIBUTE_NORETURN static void reportOpenError(StringRef Path, Twine Msg) { errs() << "failed to open " << Path << ": " << Msg << '\n'; errs().flush(); @@ -152,9 +176,7 @@ static void RegisterPassPlugins(ArrayRef<std::string> PassPlugins, } } -namespace { - -std::unique_ptr<TargetMachine> +static std::unique_ptr<TargetMachine> createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { StringRef TheTriple = M.getTargetTriple(); SubtargetFeatures Features; @@ -175,9 +197,11 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { else CodeModel = M.getCodeModel(); - return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine( + std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine( TheTriple, Conf.CPU, Features.getString(), Conf.Options, RelocModel, CodeModel, Conf.CGOptLevel)); + assert(TM && "Failed to create target machine"); + return TM; } static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, @@ -197,9 +221,9 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, } PassInstrumentationCallbacks PIC; - StandardInstrumentations SI; + StandardInstrumentations SI(Conf.DebugPassManager); SI.registerCallbacks(PIC); - PassBuilder PB(TM, Conf.PTO, PGOOpt, &PIC); + PassBuilder PB(Conf.DebugPassManager, TM, Conf.PTO, PGOOpt, &PIC); AAManager AA; // Parse a custom AA pipeline if asked to. @@ -213,6 +237,12 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, CGSCCAnalysisManager CGAM(Conf.DebugPassManager); ModuleAnalysisManager MAM(Conf.DebugPassManager); + std::unique_ptr<TargetLibraryInfoImpl> TLII( + new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()))); + if (Conf.Freestanding) + TLII->disableAllFunctions(); + FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); + // Register the AA manager first so that our version is the one used. FAM.registerPass([&] { return std::move(AA); }); @@ -224,7 +254,9 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); ModulePassManager MPM(Conf.DebugPassManager); - // FIXME (davide): verify the input. + + if (!Conf.DisableVerify) + MPM.addPass(VerifierPass()); PassBuilder::OptimizationLevel OL; @@ -246,20 +278,21 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, } if (IsThinLTO) - MPM = PB.buildThinLTODefaultPipeline(OL, Conf.DebugPassManager, - ImportSummary); + MPM.addPass(PB.buildThinLTODefaultPipeline(OL, ImportSummary)); else - MPM = PB.buildLTODefaultPipeline(OL, Conf.DebugPassManager, ExportSummary); - MPM.run(Mod, MAM); + MPM.addPass(PB.buildLTODefaultPipeline(OL, ExportSummary)); + + if (!Conf.DisableVerify) + MPM.addPass(VerifierPass()); - // FIXME (davide): verify the output. + MPM.run(Mod, MAM); } static void runNewPMCustomPasses(const Config &Conf, Module &Mod, TargetMachine *TM, std::string PipelineDesc, std::string AAPipelineDesc, bool DisableVerify) { - PassBuilder PB(TM); + PassBuilder PB(Conf.DebugPassManager, TM); AAManager AA; // Parse a custom AA pipeline if asked to. @@ -275,6 +308,12 @@ static void runNewPMCustomPasses(const Config &Conf, Module &Mod, CGSCCAnalysisManager CGAM; ModuleAnalysisManager MAM; + std::unique_ptr<TargetLibraryInfoImpl> TLII( + new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()))); + if (Conf.Freestanding) + TLII->disableAllFunctions(); + FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); + // Register the AA manager first so that our version is the one used. FAM.registerPass([&] { return std::move(AA); }); @@ -308,6 +347,8 @@ static void runOldPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, PassManagerBuilder PMB; PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple())); + if (Conf.Freestanding) + PMB.LibraryInfo->disableAllFunctions(); PMB.Inliner = createFunctionInliningPass(); PMB.ExportSummary = ExportSummary; PMB.ImportSummary = ImportSummary; @@ -331,9 +372,27 @@ static void runOldPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, passes.run(Mod); } -bool opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, - bool IsThinLTO, ModuleSummaryIndex *ExportSummary, - const ModuleSummaryIndex *ImportSummary) { +bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, + bool IsThinLTO, ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary, + const std::vector<uint8_t> &CmdArgs) { + if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) { + // FIXME: the motivation for capturing post-merge bitcode and command line + // is replicating the compilation environment from bitcode, without needing + // to understand the dependencies (the functions to be imported). This + // assumes a clang - based invocation, case in which we have the command + // line. + // It's not very clear how the above motivation would map in the + // linker-based case, so we currently don't plumb the command line args in + // that case. + if (CmdArgs.empty()) + LLVM_DEBUG( + dbgs() << "Post-(Thin)LTO merge bitcode embedding was requested, but " + "command line arguments are not available"); + llvm::EmbedBitcodeInModule(Mod, llvm::MemoryBufferRef(), + /*EmbedBitcode*/ true, /*EmbedCmdline*/ true, + /*Cmdline*/ CmdArgs); + } // FIXME: Plumb the combined index into the new pass manager. if (!Conf.OptPipeline.empty()) runNewPMCustomPasses(Conf, Mod, TM, Conf.OptPipeline, Conf.AAPipeline, @@ -346,30 +405,17 @@ bool opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } -static cl::opt<bool> EmbedBitcode( - "lto-embed-bitcode", cl::init(false), - cl::desc("Embed LLVM bitcode in object files produced by LTO")); - -static void EmitBitcodeSection(Module &M, const Config &Conf) { - if (!EmbedBitcode) - return; - SmallVector<char, 0> Buffer; - raw_svector_ostream OS(Buffer); - WriteBitcodeToFile(M, OS); - - std::unique_ptr<MemoryBuffer> Buf( - new SmallVectorMemoryBuffer(std::move(Buffer))); - llvm::EmbedBitcodeInModule(M, Buf->getMemBufferRef(), /*EmbedBitcode*/ true, - /*EmbedMarker*/ false, /*CmdArgs*/ nullptr); -} - -void codegen(const Config &Conf, TargetMachine *TM, AddStreamFn AddStream, - unsigned Task, Module &Mod, - const ModuleSummaryIndex &CombinedIndex) { +static void codegen(const Config &Conf, TargetMachine *TM, + AddStreamFn AddStream, unsigned Task, Module &Mod, + const ModuleSummaryIndex &CombinedIndex) { if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod)) return; - EmitBitcodeSection(Mod, Conf); + if (EmbedBitcode == LTOBitcodeEmbedding::EmbedOptimized) + llvm::EmbedBitcodeInModule(Mod, llvm::MemoryBufferRef(), + /*EmbedBitcode*/ true, + /*EmbedCmdline*/ false, + /*CmdArgs*/ std::vector<uint8_t>()); std::unique_ptr<ToolOutputFile> DwoOut; SmallString<1024> DwoFile(Conf.SplitDwarfOutput); @@ -396,6 +442,8 @@ void codegen(const Config &Conf, TargetMachine *TM, AddStreamFn AddStream, legacy::PassManager CodeGenPasses; CodeGenPasses.add( createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex)); + if (Conf.PreCodeGenPassesHook) + Conf.PreCodeGenPassesHook(CodeGenPasses); if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, DwoOut ? &DwoOut->os() : nullptr, Conf.CGFileType)) @@ -406,10 +454,11 @@ void codegen(const Config &Conf, TargetMachine *TM, AddStreamFn AddStream, DwoOut->keep(); } -void splitCodeGen(const Config &C, TargetMachine *TM, AddStreamFn AddStream, - unsigned ParallelCodeGenParallelismLevel, - std::unique_ptr<Module> Mod, - const ModuleSummaryIndex &CombinedIndex) { +static void splitCodeGen(const Config &C, TargetMachine *TM, + AddStreamFn AddStream, + unsigned ParallelCodeGenParallelismLevel, + std::unique_ptr<Module> Mod, + const ModuleSummaryIndex &CombinedIndex) { ThreadPool CodegenThreadPool( heavyweight_hardware_concurrency(ParallelCodeGenParallelismLevel)); unsigned ThreadCount = 0; @@ -457,7 +506,8 @@ void splitCodeGen(const Config &C, TargetMachine *TM, AddStreamFn AddStream, CodegenThreadPool.wait(); } -Expected<const Target *> initAndLookupTarget(const Config &C, Module &Mod) { +static Expected<const Target *> initAndLookupTarget(const Config &C, + Module &Mod) { if (!C.OverrideTriple.empty()) Mod.setTargetTriple(C.OverrideTriple); else if (Mod.getTargetTriple().empty()) @@ -469,7 +519,6 @@ Expected<const Target *> initAndLookupTarget(const Config &C, Module &Mod) { return make_error<StringError>(Msg, inconvertibleErrorCode()); return T; } -} Error lto::finalizeOptimizationRemarks( std::unique_ptr<ToolOutputFile> DiagOutputFile) { @@ -494,7 +543,8 @@ Error lto::backend(const Config &C, AddStreamFn AddStream, if (!C.CodeGenOnly) { if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false, - /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr)) + /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, + /*CmdArgs*/ std::vector<uint8_t>())) return Error::success(); } @@ -532,7 +582,8 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, Module &Mod, const ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap) { + MapVector<StringRef, BitcodeModule> &ModuleMap, + const std::vector<uint8_t> &CmdArgs) { Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod); if (!TOrErr) return TOrErr.takeError(); @@ -542,7 +593,8 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, // Setup optimization remarks. auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks( Mod.getContext(), Conf.RemarksFilename, Conf.RemarksPasses, - Conf.RemarksFormat, Conf.RemarksWithHotness, Task); + Conf.RemarksFormat, Conf.RemarksWithHotness, Conf.RemarksHotnessThreshold, + Task); if (!DiagFileOrErr) return DiagFileOrErr.takeError(); auto DiagnosticOutputFile = std::move(*DiagFileOrErr); @@ -559,6 +611,21 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(Task, Mod)) return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + auto OptimizeAndCodegen = + [&](Module &Mod, TargetMachine *TM, + std::unique_ptr<ToolOutputFile> DiagnosticOutputFile) { + if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true, + /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex, + CmdArgs)) + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + + codegen(Conf, TM, AddStream, Task, Mod, CombinedIndex); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + }; + + if (ThinLTOAssumeMerged) + return OptimizeAndCodegen(Mod, TM.get(), std::move(DiagnosticOutputFile)); + // When linking an ELF shared object, dso_local should be dropped. We // conservatively do this for -fpic. bool ClearDSOLocalOnDeclarations = @@ -599,10 +666,81 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod)) return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); - if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true, - /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex)) - return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + return OptimizeAndCodegen(Mod, TM.get(), std::move(DiagnosticOutputFile)); +} + +BitcodeModule *lto::findThinLTOModule(MutableArrayRef<BitcodeModule> BMs) { + if (ThinLTOAssumeMerged && BMs.size() == 1) + return BMs.begin(); + + for (BitcodeModule &BM : BMs) { + Expected<BitcodeLTOInfo> LTOInfo = BM.getLTOInfo(); + if (LTOInfo && LTOInfo->IsThinLTO) + return &BM; + } + return nullptr; +} + +Expected<BitcodeModule> lto::findThinLTOModule(MemoryBufferRef MBRef) { + Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef); + if (!BMsOrErr) + return BMsOrErr.takeError(); + + // The bitcode file may contain multiple modules, we want the one that is + // marked as being the ThinLTO module. + if (const BitcodeModule *Bm = lto::findThinLTOModule(*BMsOrErr)) + return *Bm; - codegen(Conf, TM.get(), AddStream, Task, Mod, CombinedIndex); - return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); + return make_error<StringError>("Could not find module summary", + inconvertibleErrorCode()); +} + +bool lto::loadReferencedModules( + const Module &M, const ModuleSummaryIndex &CombinedIndex, + FunctionImporter::ImportMapTy &ImportList, + MapVector<llvm::StringRef, llvm::BitcodeModule> &ModuleMap, + std::vector<std::unique_ptr<llvm::MemoryBuffer>> + &OwnedImportsLifetimeManager) { + if (ThinLTOAssumeMerged) + return true; + // We can simply import the values mentioned in the combined index, since + // we should only invoke this using the individual indexes written out + // via a WriteIndexesThinBackend. + for (const auto &GlobalList : CombinedIndex) { + // Ignore entries for undefined references. + if (GlobalList.second.SummaryList.empty()) + continue; + + auto GUID = GlobalList.first; + for (const auto &Summary : GlobalList.second.SummaryList) { + // Skip the summaries for the importing module. These are included to + // e.g. record required linkage changes. + if (Summary->modulePath() == M.getModuleIdentifier()) + continue; + // Add an entry to provoke importing by thinBackend. + ImportList[Summary->modulePath()].insert(GUID); + } + } + + for (auto &I : ImportList) { + ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MBOrErr = + llvm::MemoryBuffer::getFile(I.first()); + if (!MBOrErr) { + errs() << "Error loading imported file '" << I.first() + << "': " << MBOrErr.getError().message() << "\n"; + return false; + } + + Expected<BitcodeModule> BMOrErr = findThinLTOModule(**MBOrErr); + if (!BMOrErr) { + handleAllErrors(BMOrErr.takeError(), [&](ErrorInfoBase &EIB) { + errs() << "Error loading imported file '" << I.first() + << "': " << EIB.message() << '\n'; + }); + return false; + } + ModuleMap.insert({I.first(), *BMOrErr}); + OwnedImportsLifetimeManager.push_back(std::move(*MBOrErr)); + } + return true; } |
