aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/LTO/LTOBackend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/LTO/LTOBackend.cpp')
-rw-r--r--llvm/lib/LTO/LTOBackend.cpp240
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;
}