Path: blob/main/contrib/llvm-project/llvm/lib/LTO/LTOBackend.cpp
35234 views
//===-LTOBackend.cpp - LLVM Link Time Optimizer Backend -------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the "backend" phase of LTO, i.e. it performs9// optimization and code generation on a loaded module. It is generally used10// internally by the LTO class but can also be used independently, for example11// to implement a standalone ThinLTO backend.12//13//===----------------------------------------------------------------------===//1415#include "llvm/LTO/LTOBackend.h"16#include "llvm/Analysis/AliasAnalysis.h"17#include "llvm/Analysis/CGSCCPassManager.h"18#include "llvm/Analysis/ModuleSummaryAnalysis.h"19#include "llvm/Analysis/TargetLibraryInfo.h"20#include "llvm/Bitcode/BitcodeReader.h"21#include "llvm/Bitcode/BitcodeWriter.h"22#include "llvm/IR/LLVMRemarkStreamer.h"23#include "llvm/IR/LegacyPassManager.h"24#include "llvm/IR/PassManager.h"25#include "llvm/IR/Verifier.h"26#include "llvm/LTO/LTO.h"27#include "llvm/MC/TargetRegistry.h"28#include "llvm/Object/ModuleSymbolTable.h"29#include "llvm/Passes/PassBuilder.h"30#include "llvm/Passes/PassPlugin.h"31#include "llvm/Passes/StandardInstrumentations.h"32#include "llvm/Support/Error.h"33#include "llvm/Support/FileSystem.h"34#include "llvm/Support/MemoryBuffer.h"35#include "llvm/Support/Path.h"36#include "llvm/Support/Program.h"37#include "llvm/Support/ThreadPool.h"38#include "llvm/Support/ToolOutputFile.h"39#include "llvm/Support/VirtualFileSystem.h"40#include "llvm/Support/raw_ostream.h"41#include "llvm/Target/TargetMachine.h"42#include "llvm/TargetParser/SubtargetFeature.h"43#include "llvm/Transforms/IPO/WholeProgramDevirt.h"44#include "llvm/Transforms/Scalar/LoopPassManager.h"45#include "llvm/Transforms/Utils/FunctionImportUtils.h"46#include "llvm/Transforms/Utils/SplitModule.h"47#include <optional>4849using namespace llvm;50using namespace lto;5152#define DEBUG_TYPE "lto-backend"5354enum class LTOBitcodeEmbedding {55DoNotEmbed = 0,56EmbedOptimized = 1,57EmbedPostMergePreOptimized = 258};5960static cl::opt<LTOBitcodeEmbedding> EmbedBitcode(61"lto-embed-bitcode", cl::init(LTOBitcodeEmbedding::DoNotEmbed),62cl::values(clEnumValN(LTOBitcodeEmbedding::DoNotEmbed, "none",63"Do not embed"),64clEnumValN(LTOBitcodeEmbedding::EmbedOptimized, "optimized",65"Embed after all optimization passes"),66clEnumValN(LTOBitcodeEmbedding::EmbedPostMergePreOptimized,67"post-merge-pre-opt",68"Embed post merge, but before optimizations")),69cl::desc("Embed LLVM bitcode in object files produced by LTO"));7071static cl::opt<bool> ThinLTOAssumeMerged(72"thinlto-assume-merged", cl::init(false),73cl::desc("Assume the input has already undergone ThinLTO function "74"importing and the other pre-optimization pipeline changes."));7576namespace llvm {77extern cl::opt<bool> NoPGOWarnMismatch;78}7980[[noreturn]] static void reportOpenError(StringRef Path, Twine Msg) {81errs() << "failed to open " << Path << ": " << Msg << '\n';82errs().flush();83exit(1);84}8586Error Config::addSaveTemps(std::string OutputFileName, bool UseInputModulePath,87const DenseSet<StringRef> &SaveTempsArgs) {88ShouldDiscardValueNames = false;8990std::error_code EC;91if (SaveTempsArgs.empty() || SaveTempsArgs.contains("resolution")) {92ResolutionFile =93std::make_unique<raw_fd_ostream>(OutputFileName + "resolution.txt", EC,94sys::fs::OpenFlags::OF_TextWithCRLF);95if (EC) {96ResolutionFile.reset();97return errorCodeToError(EC);98}99}100101auto setHook = [&](std::string PathSuffix, ModuleHookFn &Hook) {102// Keep track of the hook provided by the linker, which also needs to run.103ModuleHookFn LinkerHook = Hook;104Hook = [=](unsigned Task, const Module &M) {105// If the linker's hook returned false, we need to pass that result106// through.107if (LinkerHook && !LinkerHook(Task, M))108return false;109110std::string PathPrefix;111// If this is the combined module (not a ThinLTO backend compile) or the112// user hasn't requested using the input module's path, emit to a file113// named from the provided OutputFileName with the Task ID appended.114if (M.getModuleIdentifier() == "ld-temp.o" || !UseInputModulePath) {115PathPrefix = OutputFileName;116if (Task != (unsigned)-1)117PathPrefix += utostr(Task) + ".";118} else119PathPrefix = M.getModuleIdentifier() + ".";120std::string Path = PathPrefix + PathSuffix + ".bc";121std::error_code EC;122raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::OF_None);123// Because -save-temps is a debugging feature, we report the error124// directly and exit.125if (EC)126reportOpenError(Path, EC.message());127WriteBitcodeToFile(M, OS, /*ShouldPreserveUseListOrder=*/false);128return true;129};130};131132auto SaveCombinedIndex =133[=](const ModuleSummaryIndex &Index,134const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {135std::string Path = OutputFileName + "index.bc";136std::error_code EC;137raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::OF_None);138// Because -save-temps is a debugging feature, we report the error139// directly and exit.140if (EC)141reportOpenError(Path, EC.message());142writeIndexToFile(Index, OS);143144Path = OutputFileName + "index.dot";145raw_fd_ostream OSDot(Path, EC, sys::fs::OpenFlags::OF_Text);146if (EC)147reportOpenError(Path, EC.message());148Index.exportToDot(OSDot, GUIDPreservedSymbols);149return true;150};151152if (SaveTempsArgs.empty()) {153setHook("0.preopt", PreOptModuleHook);154setHook("1.promote", PostPromoteModuleHook);155setHook("2.internalize", PostInternalizeModuleHook);156setHook("3.import", PostImportModuleHook);157setHook("4.opt", PostOptModuleHook);158setHook("5.precodegen", PreCodeGenModuleHook);159CombinedIndexHook = SaveCombinedIndex;160} else {161if (SaveTempsArgs.contains("preopt"))162setHook("0.preopt", PreOptModuleHook);163if (SaveTempsArgs.contains("promote"))164setHook("1.promote", PostPromoteModuleHook);165if (SaveTempsArgs.contains("internalize"))166setHook("2.internalize", PostInternalizeModuleHook);167if (SaveTempsArgs.contains("import"))168setHook("3.import", PostImportModuleHook);169if (SaveTempsArgs.contains("opt"))170setHook("4.opt", PostOptModuleHook);171if (SaveTempsArgs.contains("precodegen"))172setHook("5.precodegen", PreCodeGenModuleHook);173if (SaveTempsArgs.contains("combinedindex"))174CombinedIndexHook = SaveCombinedIndex;175}176177return Error::success();178}179180#define HANDLE_EXTENSION(Ext) \181llvm::PassPluginLibraryInfo get##Ext##PluginInfo();182#include "llvm/Support/Extension.def"183184static void RegisterPassPlugins(ArrayRef<std::string> PassPlugins,185PassBuilder &PB) {186#define HANDLE_EXTENSION(Ext) \187get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB);188#include "llvm/Support/Extension.def"189190// Load requested pass plugins and let them register pass builder callbacks191for (auto &PluginFN : PassPlugins) {192auto PassPlugin = PassPlugin::Load(PluginFN);193if (!PassPlugin)194report_fatal_error(PassPlugin.takeError(), /*gen_crash_diag=*/false);195PassPlugin->registerPassBuilderCallbacks(PB);196}197}198199static std::unique_ptr<TargetMachine>200createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) {201StringRef TheTriple = M.getTargetTriple();202SubtargetFeatures Features;203Features.getDefaultSubtargetFeatures(Triple(TheTriple));204for (const std::string &A : Conf.MAttrs)205Features.AddFeature(A);206207std::optional<Reloc::Model> RelocModel;208if (Conf.RelocModel)209RelocModel = *Conf.RelocModel;210else if (M.getModuleFlag("PIC Level"))211RelocModel =212M.getPICLevel() == PICLevel::NotPIC ? Reloc::Static : Reloc::PIC_;213214std::optional<CodeModel::Model> CodeModel;215if (Conf.CodeModel)216CodeModel = *Conf.CodeModel;217else218CodeModel = M.getCodeModel();219220std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(221TheTriple, Conf.CPU, Features.getString(), Conf.Options, RelocModel,222CodeModel, Conf.CGOptLevel));223224assert(TM && "Failed to create target machine");225226if (std::optional<uint64_t> LargeDataThreshold = M.getLargeDataThreshold())227TM->setLargeDataThreshold(*LargeDataThreshold);228229return TM;230}231232static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,233unsigned OptLevel, bool IsThinLTO,234ModuleSummaryIndex *ExportSummary,235const ModuleSummaryIndex *ImportSummary) {236auto FS = vfs::getRealFileSystem();237std::optional<PGOOptions> PGOOpt;238if (!Conf.SampleProfile.empty())239PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping,240/*MemoryProfile=*/"", FS, PGOOptions::SampleUse,241PGOOptions::NoCSAction,242PGOOptions::ColdFuncOpt::Default, true);243else if (Conf.RunCSIRInstr) {244PGOOpt = PGOOptions("", Conf.CSIRProfile, Conf.ProfileRemapping,245/*MemoryProfile=*/"", FS, PGOOptions::IRUse,246PGOOptions::CSIRInstr, PGOOptions::ColdFuncOpt::Default,247Conf.AddFSDiscriminator);248} else if (!Conf.CSIRProfile.empty()) {249PGOOpt = PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping,250/*MemoryProfile=*/"", FS, PGOOptions::IRUse,251PGOOptions::CSIRUse, PGOOptions::ColdFuncOpt::Default,252Conf.AddFSDiscriminator);253NoPGOWarnMismatch = !Conf.PGOWarnMismatch;254} else if (Conf.AddFSDiscriminator) {255PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,256PGOOptions::NoAction, PGOOptions::NoCSAction,257PGOOptions::ColdFuncOpt::Default, true);258}259TM->setPGOOption(PGOOpt);260261LoopAnalysisManager LAM;262FunctionAnalysisManager FAM;263CGSCCAnalysisManager CGAM;264ModuleAnalysisManager MAM;265266PassInstrumentationCallbacks PIC;267StandardInstrumentations SI(Mod.getContext(), Conf.DebugPassManager,268Conf.VerifyEach);269SI.registerCallbacks(PIC, &MAM);270PassBuilder PB(TM, Conf.PTO, PGOOpt, &PIC);271272RegisterPassPlugins(Conf.PassPlugins, PB);273274std::unique_ptr<TargetLibraryInfoImpl> TLII(275new TargetLibraryInfoImpl(Triple(TM->getTargetTriple())));276if (Conf.Freestanding)277TLII->disableAllFunctions();278FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });279280// Parse a custom AA pipeline if asked to.281if (!Conf.AAPipeline.empty()) {282AAManager AA;283if (auto Err = PB.parseAAPipeline(AA, Conf.AAPipeline)) {284report_fatal_error(Twine("unable to parse AA pipeline description '") +285Conf.AAPipeline + "': " + toString(std::move(Err)));286}287// Register the AA manager first so that our version is the one used.288FAM.registerPass([&] { return std::move(AA); });289}290291// Register all the basic analyses with the managers.292PB.registerModuleAnalyses(MAM);293PB.registerCGSCCAnalyses(CGAM);294PB.registerFunctionAnalyses(FAM);295PB.registerLoopAnalyses(LAM);296PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);297298ModulePassManager MPM;299300if (!Conf.DisableVerify)301MPM.addPass(VerifierPass());302303OptimizationLevel OL;304305switch (OptLevel) {306default:307llvm_unreachable("Invalid optimization level");308case 0:309OL = OptimizationLevel::O0;310break;311case 1:312OL = OptimizationLevel::O1;313break;314case 2:315OL = OptimizationLevel::O2;316break;317case 3:318OL = OptimizationLevel::O3;319break;320}321322// Parse a custom pipeline if asked to.323if (!Conf.OptPipeline.empty()) {324if (auto Err = PB.parsePassPipeline(MPM, Conf.OptPipeline)) {325report_fatal_error(Twine("unable to parse pass pipeline description '") +326Conf.OptPipeline + "': " + toString(std::move(Err)));327}328} else if (IsThinLTO) {329MPM.addPass(PB.buildThinLTODefaultPipeline(OL, ImportSummary));330} else {331MPM.addPass(PB.buildLTODefaultPipeline(OL, ExportSummary));332}333334if (!Conf.DisableVerify)335MPM.addPass(VerifierPass());336337MPM.run(Mod, MAM);338}339340bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,341bool IsThinLTO, ModuleSummaryIndex *ExportSummary,342const ModuleSummaryIndex *ImportSummary,343const std::vector<uint8_t> &CmdArgs) {344if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) {345// FIXME: the motivation for capturing post-merge bitcode and command line346// is replicating the compilation environment from bitcode, without needing347// to understand the dependencies (the functions to be imported). This348// assumes a clang - based invocation, case in which we have the command349// line.350// It's not very clear how the above motivation would map in the351// linker-based case, so we currently don't plumb the command line args in352// that case.353if (CmdArgs.empty())354LLVM_DEBUG(355dbgs() << "Post-(Thin)LTO merge bitcode embedding was requested, but "356"command line arguments are not available");357llvm::embedBitcodeInModule(Mod, llvm::MemoryBufferRef(),358/*EmbedBitcode*/ true, /*EmbedCmdline*/ true,359/*Cmdline*/ CmdArgs);360}361// FIXME: Plumb the combined index into the new pass manager.362runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary,363ImportSummary);364return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);365}366367static void codegen(const Config &Conf, TargetMachine *TM,368AddStreamFn AddStream, unsigned Task, Module &Mod,369const ModuleSummaryIndex &CombinedIndex) {370if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod))371return;372373if (EmbedBitcode == LTOBitcodeEmbedding::EmbedOptimized)374llvm::embedBitcodeInModule(Mod, llvm::MemoryBufferRef(),375/*EmbedBitcode*/ true,376/*EmbedCmdline*/ false,377/*CmdArgs*/ std::vector<uint8_t>());378379std::unique_ptr<ToolOutputFile> DwoOut;380SmallString<1024> DwoFile(Conf.SplitDwarfOutput);381if (!Conf.DwoDir.empty()) {382std::error_code EC;383if (auto EC = llvm::sys::fs::create_directories(Conf.DwoDir))384report_fatal_error(Twine("Failed to create directory ") + Conf.DwoDir +385": " + EC.message());386387DwoFile = Conf.DwoDir;388sys::path::append(DwoFile, std::to_string(Task) + ".dwo");389TM->Options.MCOptions.SplitDwarfFile = std::string(DwoFile);390} else391TM->Options.MCOptions.SplitDwarfFile = Conf.SplitDwarfFile;392393if (!DwoFile.empty()) {394std::error_code EC;395DwoOut = std::make_unique<ToolOutputFile>(DwoFile, EC, sys::fs::OF_None);396if (EC)397report_fatal_error(Twine("Failed to open ") + DwoFile + ": " +398EC.message());399}400401Expected<std::unique_ptr<CachedFileStream>> StreamOrErr =402AddStream(Task, Mod.getModuleIdentifier());403if (Error Err = StreamOrErr.takeError())404report_fatal_error(std::move(Err));405std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr;406TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName;407408legacy::PassManager CodeGenPasses;409TargetLibraryInfoImpl TLII(Triple(Mod.getTargetTriple()));410CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));411CodeGenPasses.add(412createImmutableModuleSummaryIndexWrapperPass(&CombinedIndex));413if (Conf.PreCodeGenPassesHook)414Conf.PreCodeGenPassesHook(CodeGenPasses);415if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS,416DwoOut ? &DwoOut->os() : nullptr,417Conf.CGFileType))418report_fatal_error("Failed to setup codegen");419CodeGenPasses.run(Mod);420421if (DwoOut)422DwoOut->keep();423}424425static void splitCodeGen(const Config &C, TargetMachine *TM,426AddStreamFn AddStream,427unsigned ParallelCodeGenParallelismLevel, Module &Mod,428const ModuleSummaryIndex &CombinedIndex) {429DefaultThreadPool CodegenThreadPool(430heavyweight_hardware_concurrency(ParallelCodeGenParallelismLevel));431unsigned ThreadCount = 0;432const Target *T = &TM->getTarget();433434const auto HandleModulePartition =435[&](std::unique_ptr<Module> MPart) {436// We want to clone the module in a new context to multi-thread the437// codegen. We do it by serializing partition modules to bitcode438// (while still on the main thread, in order to avoid data races) and439// spinning up new threads which deserialize the partitions into440// separate contexts.441// FIXME: Provide a more direct way to do this in LLVM.442SmallString<0> BC;443raw_svector_ostream BCOS(BC);444WriteBitcodeToFile(*MPart, BCOS);445446// Enqueue the task447CodegenThreadPool.async(448[&](const SmallString<0> &BC, unsigned ThreadId) {449LTOLLVMContext Ctx(C);450Expected<std::unique_ptr<Module>> MOrErr =451parseBitcodeFile(MemoryBufferRef(BC.str(), "ld-temp.o"), Ctx);452if (!MOrErr)453report_fatal_error("Failed to read bitcode");454std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());455456std::unique_ptr<TargetMachine> TM =457createTargetMachine(C, T, *MPartInCtx);458459codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx,460CombinedIndex);461},462// Pass BC using std::move to ensure that it get moved rather than463// copied into the thread's context.464std::move(BC), ThreadCount++);465};466467// Try target-specific module splitting first, then fallback to the default.468if (!TM->splitModule(Mod, ParallelCodeGenParallelismLevel,469HandleModulePartition)) {470SplitModule(Mod, ParallelCodeGenParallelismLevel, HandleModulePartition,471false);472}473474// Because the inner lambda (which runs in a worker thread) captures our local475// variables, we need to wait for the worker threads to terminate before we476// can leave the function scope.477CodegenThreadPool.wait();478}479480static Expected<const Target *> initAndLookupTarget(const Config &C,481Module &Mod) {482if (!C.OverrideTriple.empty())483Mod.setTargetTriple(C.OverrideTriple);484else if (Mod.getTargetTriple().empty())485Mod.setTargetTriple(C.DefaultTriple);486487std::string Msg;488const Target *T = TargetRegistry::lookupTarget(Mod.getTargetTriple(), Msg);489if (!T)490return make_error<StringError>(Msg, inconvertibleErrorCode());491return T;492}493494Error lto::finalizeOptimizationRemarks(495std::unique_ptr<ToolOutputFile> DiagOutputFile) {496// Make sure we flush the diagnostic remarks file in case the linker doesn't497// call the global destructors before exiting.498if (!DiagOutputFile)499return Error::success();500DiagOutputFile->keep();501DiagOutputFile->os().flush();502return Error::success();503}504505Error lto::backend(const Config &C, AddStreamFn AddStream,506unsigned ParallelCodeGenParallelismLevel, Module &Mod,507ModuleSummaryIndex &CombinedIndex) {508Expected<const Target *> TOrErr = initAndLookupTarget(C, Mod);509if (!TOrErr)510return TOrErr.takeError();511512std::unique_ptr<TargetMachine> TM = createTargetMachine(C, *TOrErr, Mod);513514LLVM_DEBUG(dbgs() << "Running regular LTO\n");515if (!C.CodeGenOnly) {516if (!opt(C, TM.get(), 0, Mod, /*IsThinLTO=*/false,517/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,518/*CmdArgs*/ std::vector<uint8_t>()))519return Error::success();520}521522if (ParallelCodeGenParallelismLevel == 1) {523codegen(C, TM.get(), AddStream, 0, Mod, CombinedIndex);524} else {525splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, Mod,526CombinedIndex);527}528return Error::success();529}530531static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals,532const ModuleSummaryIndex &Index) {533std::vector<GlobalValue*> DeadGVs;534for (auto &GV : Mod.global_values())535if (GlobalValueSummary *GVS = DefinedGlobals.lookup(GV.getGUID()))536if (!Index.isGlobalValueLive(GVS)) {537DeadGVs.push_back(&GV);538convertToDeclaration(GV);539}540541// Now that all dead bodies have been dropped, delete the actual objects542// themselves when possible.543for (GlobalValue *GV : DeadGVs) {544GV->removeDeadConstantUsers();545// Might reference something defined in native object (i.e. dropped a546// non-prevailing IR def, but we need to keep the declaration).547if (GV->use_empty())548GV->eraseFromParent();549}550}551552Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,553Module &Mod, const ModuleSummaryIndex &CombinedIndex,554const FunctionImporter::ImportMapTy &ImportList,555const GVSummaryMapTy &DefinedGlobals,556MapVector<StringRef, BitcodeModule> *ModuleMap,557const std::vector<uint8_t> &CmdArgs) {558Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);559if (!TOrErr)560return TOrErr.takeError();561562std::unique_ptr<TargetMachine> TM = createTargetMachine(Conf, *TOrErr, Mod);563564// Setup optimization remarks.565auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(566Mod.getContext(), Conf.RemarksFilename, Conf.RemarksPasses,567Conf.RemarksFormat, Conf.RemarksWithHotness, Conf.RemarksHotnessThreshold,568Task);569if (!DiagFileOrErr)570return DiagFileOrErr.takeError();571auto DiagnosticOutputFile = std::move(*DiagFileOrErr);572573// Set the partial sample profile ratio in the profile summary module flag of574// the module, if applicable.575Mod.setPartialSampleProfileRatio(CombinedIndex);576577LLVM_DEBUG(dbgs() << "Running ThinLTO\n");578if (Conf.CodeGenOnly) {579codegen(Conf, TM.get(), AddStream, Task, Mod, CombinedIndex);580return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));581}582583if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(Task, Mod))584return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));585586auto OptimizeAndCodegen =587[&](Module &Mod, TargetMachine *TM,588std::unique_ptr<ToolOutputFile> DiagnosticOutputFile) {589if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true,590/*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex,591CmdArgs))592return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));593594codegen(Conf, TM, AddStream, Task, Mod, CombinedIndex);595return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));596};597598if (ThinLTOAssumeMerged)599return OptimizeAndCodegen(Mod, TM.get(), std::move(DiagnosticOutputFile));600601// When linking an ELF shared object, dso_local should be dropped. We602// conservatively do this for -fpic.603bool ClearDSOLocalOnDeclarations =604TM->getTargetTriple().isOSBinFormatELF() &&605TM->getRelocationModel() != Reloc::Static &&606Mod.getPIELevel() == PIELevel::Default;607renameModuleForThinLTO(Mod, CombinedIndex, ClearDSOLocalOnDeclarations);608609dropDeadSymbols(Mod, DefinedGlobals, CombinedIndex);610611thinLTOFinalizeInModule(Mod, DefinedGlobals, /*PropagateAttrs=*/true);612613if (Conf.PostPromoteModuleHook && !Conf.PostPromoteModuleHook(Task, Mod))614return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));615616if (!DefinedGlobals.empty())617thinLTOInternalizeModule(Mod, DefinedGlobals);618619if (Conf.PostInternalizeModuleHook &&620!Conf.PostInternalizeModuleHook(Task, Mod))621return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));622623auto ModuleLoader = [&](StringRef Identifier) {624assert(Mod.getContext().isODRUniquingDebugTypes() &&625"ODR Type uniquing should be enabled on the context");626if (ModuleMap) {627auto I = ModuleMap->find(Identifier);628assert(I != ModuleMap->end());629return I->second.getLazyModule(Mod.getContext(),630/*ShouldLazyLoadMetadata=*/true,631/*IsImporting*/ true);632}633634ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MBOrErr =635llvm::MemoryBuffer::getFile(Identifier);636if (!MBOrErr)637return Expected<std::unique_ptr<llvm::Module>>(make_error<StringError>(638Twine("Error loading imported file ") + Identifier + " : ",639MBOrErr.getError()));640641Expected<BitcodeModule> BMOrErr = findThinLTOModule(**MBOrErr);642if (!BMOrErr)643return Expected<std::unique_ptr<llvm::Module>>(make_error<StringError>(644Twine("Error loading imported file ") + Identifier + " : " +645toString(BMOrErr.takeError()),646inconvertibleErrorCode()));647648Expected<std::unique_ptr<Module>> MOrErr =649BMOrErr->getLazyModule(Mod.getContext(),650/*ShouldLazyLoadMetadata=*/true,651/*IsImporting*/ true);652if (MOrErr)653(*MOrErr)->setOwnedMemoryBuffer(std::move(*MBOrErr));654return MOrErr;655};656657FunctionImporter Importer(CombinedIndex, ModuleLoader,658ClearDSOLocalOnDeclarations);659if (Error Err = Importer.importFunctions(Mod, ImportList).takeError())660return Err;661662// Do this after any importing so that imported code is updated.663updateMemProfAttributes(Mod, CombinedIndex);664updatePublicTypeTestCalls(Mod, CombinedIndex.withWholeProgramVisibility());665666if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod))667return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));668669return OptimizeAndCodegen(Mod, TM.get(), std::move(DiagnosticOutputFile));670}671672BitcodeModule *lto::findThinLTOModule(MutableArrayRef<BitcodeModule> BMs) {673if (ThinLTOAssumeMerged && BMs.size() == 1)674return BMs.begin();675676for (BitcodeModule &BM : BMs) {677Expected<BitcodeLTOInfo> LTOInfo = BM.getLTOInfo();678if (LTOInfo && LTOInfo->IsThinLTO)679return &BM;680}681return nullptr;682}683684Expected<BitcodeModule> lto::findThinLTOModule(MemoryBufferRef MBRef) {685Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef);686if (!BMsOrErr)687return BMsOrErr.takeError();688689// The bitcode file may contain multiple modules, we want the one that is690// marked as being the ThinLTO module.691if (const BitcodeModule *Bm = lto::findThinLTOModule(*BMsOrErr))692return *Bm;693694return make_error<StringError>("Could not find module summary",695inconvertibleErrorCode());696}697698bool lto::initImportList(const Module &M,699const ModuleSummaryIndex &CombinedIndex,700FunctionImporter::ImportMapTy &ImportList) {701if (ThinLTOAssumeMerged)702return true;703// We can simply import the values mentioned in the combined index, since704// we should only invoke this using the individual indexes written out705// via a WriteIndexesThinBackend.706for (const auto &GlobalList : CombinedIndex) {707// Ignore entries for undefined references.708if (GlobalList.second.SummaryList.empty())709continue;710711auto GUID = GlobalList.first;712for (const auto &Summary : GlobalList.second.SummaryList) {713// Skip the summaries for the importing module. These are included to714// e.g. record required linkage changes.715if (Summary->modulePath() == M.getModuleIdentifier())716continue;717// Add an entry to provoke importing by thinBackend.718// Try emplace the entry first. If an entry with the same key already719// exists, set the value to 'std::min(existing-value, new-value)' to make720// sure a definition takes precedence over a declaration.721auto [Iter, Inserted] = ImportList[Summary->modulePath()].try_emplace(722GUID, Summary->importType());723724if (!Inserted)725Iter->second = std::min(Iter->second, Summary->importType());726}727}728return true;729}730731732