diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 5590d217e96ff..8382ae0873adb 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1451,11 +1451,11 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex, // FIXME: Both ExecuteAction and thinBackend set up optimization remarks for // the same context. finalizeLLVMOptimizationRemarks(M->getContext()); - if (Error E = - thinBackend(Conf, -1, AddStream, *M, *CombinedIndex, ImportList, - ModuleToDefinedGVSummaries[M->getModuleIdentifier()], - /*ModuleMap=*/nullptr, Conf.CodeGenOnly, - /*IRAddStream=*/nullptr, CGOpts.CmdArgs)) { + if (Error E = thinBackend( + Conf, -1, AddStream, *M, *CombinedIndex, ImportList, + ModuleToDefinedGVSummaries[M->getModuleIdentifier()], + /*ModuleMap=*/nullptr, Conf.CodeGenOnly, /*BitcodeLibFuncs=*/{}, + /*IRAddStream=*/nullptr, CGOpts.CmdArgs)) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { errs() << "Error running ThinLTO backend: " << EIB.message() << '\n'; }); diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 8647752be31fe..b7a6aa89efb96 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2701,14 +2701,30 @@ static void markBuffersAsDontNeed(Ctx &ctx, bool skipLinkedOutput) { template void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) { llvm::TimeTraceScope timeScope("LTO"); + // Capture the triple before moving the bitcode into the bitcode compiler. + // Note that this assumes that the set of possible libfuncs is roughly + // equivalent for all bitcode translation units. + std::optional tt; + if (!ctx.bitcodeFiles.empty()) + tt = llvm::Triple(ctx.bitcodeFiles.front()->obj->getTargetTriple()); // Compile bitcode files and replace bitcode symbols. lto.reset(new BitcodeCompiler(ctx)); for (BitcodeFile *file : ctx.bitcodeFiles) lto->add(*file); - if (!ctx.bitcodeFiles.empty()) + llvm::BumpPtrAllocator alloc; + llvm::StringSaver saver(alloc); + if (!ctx.bitcodeFiles.empty()) { markBuffersAsDontNeed(ctx, skipLinkedOutput); + SmallVector bitcodeLibFuncs; + for (StringRef libFunc : lto::LTO::getLibFuncSymbols(*tt, saver)) + if (Symbol *sym = ctx.symtab->find(libFunc); + sym && isa(sym->file)) + bitcodeLibFuncs.push_back(libFunc); + lto->setBitcodeLibFuncs(bitcodeLibFuncs); + } + ltoObjectFiles = lto->compile(); for (auto &file : ltoObjectFiles) { auto *obj = cast>(file.get()); diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 80c6d2482f9fa..ed1a8c6ddae4f 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -195,10 +195,10 @@ BitcodeCompiler::BitcodeCompiler(Ctx &ctx) : ctx(ctx) { ctx.arg.thinLTOEmitImportsFiles); } - constexpr llvm::lto::LTO::LTOKind ltoModes[3] = - {llvm::lto::LTO::LTOKind::LTOK_UnifiedThin, - llvm::lto::LTO::LTOKind::LTOK_UnifiedRegular, - llvm::lto::LTO::LTOKind::LTOK_Default}; + constexpr llvm::lto::LTO::LTOKind ltoModes[3] = { + llvm::lto::LTO::LTOKind::LTOK_UnifiedThin, + llvm::lto::LTO::LTOKind::LTOK_UnifiedRegular, + llvm::lto::LTO::LTOKind::LTOK_Default}; ltoObj = std::make_unique(createConfig(ctx), backend, ctx.arg.ltoPartitions, ltoModes[ctx.arg.ltoKind]); @@ -422,3 +422,8 @@ SmallVector, 0> BitcodeCompiler::compile() { } return ret; } + +void BitcodeCompiler::setBitcodeLibFuncs( + const SmallVector &bitcodeLibFuncs) { + ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs); +} diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h index acf3bcff7f2f1..b9547202901fd 100644 --- a/lld/ELF/LTO.h +++ b/lld/ELF/LTO.h @@ -43,6 +43,7 @@ class BitcodeCompiler { void add(BitcodeFile &f); SmallVector, 0> compile(); + void setBitcodeLibFuncs(const SmallVector &bitcodeLibFuncs); private: Ctx &ctx; diff --git a/lld/test/ELF/lto/libcall-archive-bitcode.test b/lld/test/ELF/lto/libcall-archive-bitcode.test new file mode 100644 index 0000000000000..20735b5c89c99 --- /dev/null +++ b/lld/test/ELF/lto/libcall-archive-bitcode.test @@ -0,0 +1,41 @@ +; REQUIRES: x86 + +; RUN: rm -rf %t && split-file %s %t && cd %t +; RUN: llvm-as main.ll -o main.o +; RUN: llvm-as bcmp.ll -o bcmp.o +; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnu memcmp.s -o memcmp.o +; RUN: llvm-ar rc libc.a bcmp.o memcmp.o + +;; Ensure that no memcmp->bcmp translation occurs during LTO because bcmp is in +;; bitcode, but was not brought into the link. This would fail the link by +;; extracting bitcode after LTO. +; RUN: ld.lld -o out main.o -L. -lc +; RUN: llvm-nm out | FileCheck %s + +;--- bcmp.ll +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @bcmp(ptr %0, ptr %1, i64 %2) { + ret i32 0 +} + +;--- memcmp.s +.globl memcmp +memcmp: + ret + +;--- main.ll +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i1 @_start(ptr %0, ptr %1, i64 %2) { + %cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2) + %eq = icmp eq i32 %cmp, 0 + ret i1 %eq +} + +; CHECK-NOT: bcmp +; CHECK: memcmp +declare i32 @memcmp(ptr, ptr, i64) + diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index 3a4dc5a3dfcf8..3ee5d455774b3 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -264,7 +264,8 @@ class ThinBackendProc { using ThinBackendFunction = std::function( const Config &C, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache)>; + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs)>; /// This type defines the behavior following the thin-link phase during ThinLTO. /// It encapsulates a backend function and a strategy for thread pool @@ -279,10 +280,11 @@ struct ThinBackend { std::unique_ptr operator()( const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache) { + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs) { assert(isValid() && "Invalid backend function"); return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries, - std::move(AddStream), std::move(Cache)); + std::move(AddStream), std::move(Cache), BitcodeLibFuncs); } ThreadPoolStrategy getParallelism() const { return Parallelism; } bool isValid() const { return static_cast(Func); } @@ -400,6 +402,12 @@ class LTO { LLVM_ABI Error add(std::unique_ptr Obj, ArrayRef Res); + /// Set the list of functions implemented in bitcode across the link, whether + /// extracted or not. Such functions may not be referenced if they were not + /// extracted by the time LTO occurs. + LLVM_ABI void + setBitcodeLibFuncs(const SmallVector &BitcodeLibFuncs); + /// Returns an upper bound on the number of tasks that the client may expect. /// This may only be called after all IR object files have been added. For a /// full description of tasks see LTOBackend.h. @@ -420,6 +428,14 @@ class LTO { LLVM_ABI static SmallVector getRuntimeLibcallSymbols(const Triple &TT); + /// Static method that returns a list of library function symbols that can be + /// generated by LTO but might not be visible from bitcode symbol table. + /// Unlike the runtime libcalls, the linker can report to the code generator + /// which of these are actually available in the link, and the code generator + /// can then only reference that set of symbols. + LLVM_ABI static SmallVector + getLibFuncSymbols(const Triple &TT, llvm::StringSaver &Saver); + private: Config Conf; @@ -591,6 +607,8 @@ class LTO { // Diagnostic optimization remarks file LLVMRemarkFileHandle DiagnosticOutputFile; + + SmallVector BitcodeLibFuncs; }; /// The resolution for a symbol. The linker must provide a SymbolResolution for diff --git a/llvm/include/llvm/LTO/LTOBackend.h b/llvm/include/llvm/LTO/LTOBackend.h index 48ad5aa64f61f..6a7d7e0d87ac9 100644 --- a/llvm/include/llvm/LTO/LTOBackend.h +++ b/llvm/include/llvm/LTO/LTOBackend.h @@ -39,13 +39,15 @@ LLVM_ABI bool opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary, - const std::vector &CmdArgs); + const std::vector &CmdArgs, + const SmallVector &BitcodeLibFuncs); /// Runs a regular LTO backend. The regular LTO backend can also act as the /// regular LTO phase of ThinLTO, which may need to access the combined index. LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, Module &M, - ModuleSummaryIndex &CombinedIndex); + ModuleSummaryIndex &CombinedIndex, + const SmallVector &BitcodeLibFuncs); /// Runs a ThinLTO backend. /// If \p ModuleMap is not nullptr, all the module files to be imported have @@ -62,6 +64,7 @@ thinBackend(const Config &C, unsigned Task, AddStreamFn AddStream, Module &M, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector *ModuleMap, bool CodeGenOnly, + const SmallVector &BitcodeLibFuncs, AddStreamFn IRAddStream = nullptr, const std::vector &CmdArgs = std::vector()); diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index a02af59600c44..97d3952b05d06 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -763,6 +763,10 @@ Error LTO::add(std::unique_ptr Input, return Error::success(); } +void LTO::setBitcodeLibFuncs(const SmallVector &BitcodeLibFuncs) { + this->BitcodeLibFuncs = BitcodeLibFuncs; +} + Expected> LTO::addModule(InputFile &Input, ArrayRef InputRes, unsigned ModI, ArrayRef Res) { @@ -1385,9 +1389,9 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { } if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) { - if (Error Err = - backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel, - *RegularLTO.CombinedModule, ThinLTO.CombinedIndex)) + if (Error Err = backend( + Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel, + *RegularLTO.CombinedModule, ThinLTO.CombinedIndex, BitcodeLibFuncs)) return Err; } @@ -1407,6 +1411,21 @@ SmallVector LTO::getRuntimeLibcallSymbols(const Triple &TT) { return LibcallSymbols; } +SmallVector LTO::getLibFuncSymbols(const Triple &TT, + StringSaver &Saver) { + auto TLII = std::make_unique(TT); + TargetLibraryInfo TLI(*TLII); + SmallVector LibFuncSymbols; + LibFuncSymbols.reserve(LibFunc::NumLibFuncs); + for (unsigned I = 0, E = static_cast(LibFunc::NumLibFuncs); I != E; + ++I) { + LibFunc F = static_cast(I); + if (TLI.has(F)) + LibFuncSymbols.push_back(Saver.save(TLI.getName(F)).data()); + } + return LibFuncSymbols; +} + Error ThinBackendProc::emitFiles( const FunctionImporter::ImportMapTy &ImportList, llvm::StringRef ModulePath, const std::string &NewModulePath) const { @@ -1484,6 +1503,7 @@ class CGThinBackend : public ThinBackendProc { class InProcessThinBackend : public CGThinBackend { protected: FileCache Cache; + const SmallVector &BitcodeLibFuncs; public: InProcessThinBackend( @@ -1491,11 +1511,12 @@ class InProcessThinBackend : public CGThinBackend { ThreadPoolStrategy ThinLTOParallelism, const DenseMap &ModuleToDefinedGVSummaries, AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite, - bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles) + bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles, + const SmallVector &BitcodeLibFuncs) : CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries, AddStream, OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles, ThinLTOParallelism), - Cache(std::move(Cache)) {} + Cache(std::move(Cache)), BitcodeLibFuncs(BitcodeLibFuncs) {} virtual Error runThinLTOBackendThread( AddStreamFn AddStream, FileCache Cache, unsigned Task, BitcodeModule BM, @@ -1516,7 +1537,7 @@ class InProcessThinBackend : public CGThinBackend { return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex, ImportList, DefinedGlobals, &ModuleMap, - Conf.CodeGenOnly); + Conf.CodeGenOnly, BitcodeLibFuncs); }; if (ShouldEmitIndexFiles) { if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str())) @@ -1601,13 +1622,14 @@ class FirstRoundThinBackend : public InProcessThinBackend { const Config &Conf, ModuleSummaryIndex &CombinedIndex, ThreadPoolStrategy ThinLTOParallelism, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn CGAddStream, FileCache CGCache, AddStreamFn IRAddStream, + AddStreamFn CGAddStream, FileCache CGCache, + const SmallVector &BitcodeLibFuncs, AddStreamFn IRAddStream, FileCache IRCache) : InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism, ModuleToDefinedGVSummaries, std::move(CGAddStream), std::move(CGCache), /*OnWrite=*/nullptr, /*ShouldEmitIndexFiles=*/false, - /*ShouldEmitImportsFiles=*/false), + /*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs), IRAddStream(std::move(IRAddStream)), IRCache(std::move(IRCache)) {} Error runThinLTOBackendThread( @@ -1630,7 +1652,7 @@ class FirstRoundThinBackend : public InProcessThinBackend { return thinBackend(Conf, Task, CGAddStream, **MOrErr, CombinedIndex, ImportList, DefinedGlobals, &ModuleMap, - Conf.CodeGenOnly, IRAddStream); + Conf.CodeGenOnly, BitcodeLibFuncs, IRAddStream); }; // Like InProcessThinBackend, we produce index files as needed for // FirstRoundThinBackend. However, these files are not generated for @@ -1697,6 +1719,7 @@ class SecondRoundThinBackend : public InProcessThinBackend { ThreadPoolStrategy ThinLTOParallelism, const DenseMap &ModuleToDefinedGVSummaries, AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs, std::unique_ptr> IRFiles, stable_hash CombinedCGDataHash) : InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism, @@ -1704,7 +1727,7 @@ class SecondRoundThinBackend : public InProcessThinBackend { std::move(Cache), /*OnWrite=*/nullptr, /*ShouldEmitIndexFiles=*/false, - /*ShouldEmitImportsFiles=*/false), + /*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs), IRFiles(std::move(IRFiles)), CombinedCGDataHash(CombinedCGDataHash) {} Error runThinLTOBackendThread( @@ -1725,7 +1748,7 @@ class SecondRoundThinBackend : public InProcessThinBackend { return thinBackend(Conf, Task, AddStream, *LoadedModule, CombinedIndex, ImportList, DefinedGlobals, &ModuleMap, - /*CodeGenOnly=*/true); + /*CodeGenOnly=*/true, BitcodeLibFuncs); }; if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) || all_of(CombinedIndex.getModuleHash(ModuleID), @@ -1764,11 +1787,12 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism, auto Func = [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache) { + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs) { return std::make_unique( Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, AddStream, Cache, OnWrite, ShouldEmitIndexFiles, - ShouldEmitImportsFiles); + ShouldEmitImportsFiles, BitcodeLibFuncs); }; return ThinBackend(Func, Parallelism); } @@ -1885,7 +1909,8 @@ ThinBackend lto::createWriteIndexesThinBackend( auto Func = [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache) { + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs) { return std::make_unique( Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles, @@ -2103,7 +2128,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, if (!CodeGenDataThinLTOTwoRounds) { std::unique_ptr BackendProc = ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, - AddStream, Cache); + AddStream, Cache, BitcodeLibFuncs); return RunBackends(BackendProc.get()); } @@ -2126,7 +2151,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n"); auto FirstRoundLTO = std::make_unique( Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, - CG.AddStream, CG.Cache, IR.AddStream, IR.Cache); + CG.AddStream, CG.Cache, BitcodeLibFuncs, IR.AddStream, IR.Cache); if (Error E = RunBackends(FirstRoundLTO.get())) return E; @@ -2142,7 +2167,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n"); auto SecondRoundLTO = std::make_unique( Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, - AddStream, Cache, IR.getResult(), CombinedHash); + AddStream, Cache, BitcodeLibFuncs, IR.getResult(), CombinedHash); return RunBackends(SecondRoundLTO.get()); } @@ -2620,7 +2645,8 @@ ThinBackend lto::createOutOfProcessThinBackend( auto Func = [=](const Config &Conf, ModuleSummaryIndex &CombinedIndex, const DenseMap &ModuleToDefinedGVSummaries, - AddStreamFn AddStream, FileCache Cache) { + AddStreamFn AddStream, FileCache Cache, + const SmallVector &BitcodeLibFuncs) { return std::make_unique( Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, AddStream, Cache, OnWrite, ShouldEmitIndexFiles, diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 93118becedbac..bd91249db50ed 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -239,7 +239,8 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, unsigned OptLevel, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, - const ModuleSummaryIndex *ImportSummary) { + const ModuleSummaryIndex *ImportSummary, + const DenseSet &BitcodeLibFuncs) { std::optional PGOOpt; if (!Conf.SampleProfile.empty()) PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping, @@ -281,6 +282,28 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM, new TargetLibraryInfoImpl(TM->getTargetTriple())); if (Conf.Freestanding) TLII->disableAllFunctions(); + + TargetLibraryInfo TLI(*TLII); + for (unsigned I = 0, E = static_cast(LibFunc::NumLibFuncs); I != E; + ++I) { + LibFunc F = static_cast(I); + StringRef Name = TLI.getName(F); + GlobalValue *Val = Mod.getNamedValue(Name); + + // LibFuncs present in the current TU can always be referenced. + if (Val && !Val->isDeclaration()) + continue; + + // LibFuncs not implemented in bitcode can always be referenced. + if (!BitcodeLibFuncs.contains(Name)) + continue; + + // FIXME: Functions that are somewhere in a ThinLTO link (just not imported + // in this module) should not be disabled, as they have already been + // extracted. + TLII->setUnavailable(F); + } + FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); // Parse a custom AA pipeline if asked to. @@ -364,7 +387,8 @@ static bool isEmptyModule(const Module &Mod) { bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary, - const std::vector &CmdArgs) { + const std::vector &CmdArgs, + const SmallVector &BitcodeLibFuncs) { llvm::TimeTraceScope timeScope("opt"); if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) { // FIXME: the motivation for capturing post-merge bitcode and command line @@ -389,9 +413,11 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, // analysis in the case of a ThinLTO build where this might be an empty // regular LTO combined module, with a large combined index from ThinLTO. if (!isEmptyModule(Mod)) { + DenseSet BitcodeLibFuncsSet(BitcodeLibFuncs.begin(), + BitcodeLibFuncs.end()); // FIXME: Plumb the combined index into the new pass manager. runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary, - ImportSummary); + ImportSummary, BitcodeLibFuncsSet); } return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } @@ -552,7 +578,8 @@ Error lto::finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile) { Error lto::backend(const Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, Module &Mod, - ModuleSummaryIndex &CombinedIndex) { + ModuleSummaryIndex &CombinedIndex, + const SmallVector &BitcodeLibFuncs) { llvm::TimeTraceScope timeScope("LTO backend"); Expected TOrErr = initAndLookupTarget(C, Mod); if (!TOrErr) @@ -564,7 +591,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream, if (!C.CodeGenOnly) { if (!opt(C, TM.get(), 0, Mod, /*IsThinLTO=*/false, /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, - /*CmdArgs*/ std::vector())) + /*CmdArgs*/ std::vector(), BitcodeLibFuncs)) return Error::success(); } @@ -604,7 +631,9 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector *ModuleMap, - bool CodeGenOnly, AddStreamFn IRAddStream, + bool CodeGenOnly, + const SmallVector &BitcodeLibFuncs, + AddStreamFn IRAddStream, const std::vector &CmdArgs) { llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier()); Expected TOrErr = initAndLookupTarget(Conf, Mod); @@ -643,7 +672,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, // Perform optimization and code generation for ThinLTO. if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true, /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex, - CmdArgs)) + CmdArgs, BitcodeLibFuncs)) return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); // Save the current module before the first codegen round. diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index 8aa404da15286..599c5c2eb5f84 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -614,7 +614,7 @@ bool LTOCodeGenerator::optimize() { TargetMach = createTargetMachine(); if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false, /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr, - /*CmdArgs*/ std::vector())) { + /*CmdArgs*/ std::vector(), {})) { emitError("LTO middle-end optimizations failed"); return false; } @@ -639,7 +639,7 @@ bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream, Config.CodeGenOnly = true; Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule, - CombinedIndex); + CombinedIndex, {}); assert(!Err && "unexpected code-generation failure"); (void)Err; diff --git a/llvm/lib/Object/CMakeLists.txt b/llvm/lib/Object/CMakeLists.txt index 0f6d2f7c59a5c..c48d251249488 100644 --- a/llvm/lib/Object/CMakeLists.txt +++ b/llvm/lib/Object/CMakeLists.txt @@ -51,6 +51,7 @@ add_llvm_component_library(LLVMObject BinaryFormat MCParser Support + Target TargetParser TextAPI ) diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp index a45b34eb2e706..92ed072a80267 100644 --- a/llvm/lib/Object/IRSymtab.cpp +++ b/llvm/lib/Object/IRSymtab.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Comdat.h" @@ -75,12 +76,14 @@ struct Builder { Builder(SmallVector &Symtab, StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc, const Triple &TT) : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc), TT(TT), - Libcalls(TT) {} + TLII(TT), TLI(TLII), Libcalls(TT) {} DenseMap ComdatMap; Mangler Mang; const Triple &TT; + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI; // FIXME: This shouldn't be here. RTLIB::RuntimeLibcallsInfo Libcalls; @@ -95,6 +98,9 @@ struct Builder { std::vector DependentLibraries; bool isPreservedName(StringRef Name) { + LibFunc F; + if (TLI.getLibFunc(Name, F) && TLI.has(F)) + return true; return Libcalls.getSupportedLibcallImpl(Name) != RTLIB::Unsupported; } diff --git a/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll b/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll new file mode 100644 index 0000000000000..95a599fe75e8b --- /dev/null +++ b/llvm/test/LTO/Resolution/X86/libcall-external-bitcode.ll @@ -0,0 +1,20 @@ +; RUN: opt %s -o %t -module-summary -mtriple x86_64-unknown-linux-musl +; RUN: llvm-lto2 run -o %t2 \ +; RUN: -r %t,foo,plx \ +; RUN: -r %t,memcmp,x \ +; RUN: -r %t,bcmp,pl --bitcode-libfuncs=bcmp %t -save-temps +; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s + +define i1 @foo(ptr %0, ptr %1, i64 %2) { + ; CHECK-LABEL: define{{.*}}i1 @foo + ; CHECK-NEXT: %cmp = {{.*}}call i32 @memcmp + ; CHECK-NEXT: %eq = icmp eq i32 %cmp, 0 + ; CHECK-NEXT: ret i1 %eq + + %cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2) + %eq = icmp eq i32 %cmp, 0 + ret i1 %eq +} + +declare i32 @memcmp(ptr, ptr, i64) +declare i32 @bcmp(ptr, ptr, i64) diff --git a/llvm/test/LTO/Resolution/X86/libcall-external-not-bitcode.ll b/llvm/test/LTO/Resolution/X86/libcall-external-not-bitcode.ll new file mode 100644 index 0000000000000..2e6cc798d22cd --- /dev/null +++ b/llvm/test/LTO/Resolution/X86/libcall-external-not-bitcode.ll @@ -0,0 +1,20 @@ +; RUN: opt %s -o %t -module-summary -mtriple x86_64-unknown-linux-musl +; RUN: llvm-lto2 run -o %t2 \ +; RUN: -r %t,foo,plx \ +; RUN: -r %t,memcmp,x \ +; RUN: -r %t,bcmp,pl %t -save-temps +; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s + +define i1 @foo(ptr %0, ptr %1, i64 %2) { + ; CHECK-LABEL: define{{.*}}i1 @foo + ; CHECK-NEXT: %bcmp = {{.*}}call i32 @bcmp + ; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0 + ; CHECK-NEXT: ret i1 %eq + + %cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2) + %eq = icmp eq i32 %cmp, 0 + ret i1 %eq +} + +declare i32 @memcmp(ptr, ptr, i64) +declare i32 @bcmp(ptr, ptr, i64) diff --git a/llvm/test/LTO/Resolution/X86/libcall-in-tu.ll b/llvm/test/LTO/Resolution/X86/libcall-in-tu.ll new file mode 100644 index 0000000000000..948f21a6536ca --- /dev/null +++ b/llvm/test/LTO/Resolution/X86/libcall-in-tu.ll @@ -0,0 +1,34 @@ +;; This test comes from a real world scenario in LTO, where the definition of +;; bcmp was deleted because it has no uses, but later instcombine re-introduced +;; a call to bcmp() as part of SimplifyLibCalls. Such deletions must not be +;; allowed. + +; RUN: opt %s -o %t -module-summary -mtriple x86_64-unknown-linux-musl +; RUN: llvm-lto2 run -o %t2 \ +; RUN: -r %t,foo,plx \ +; RUN: -r %t,memcmp,x \ +; RUN: -r %t,bcmp,pl \ +; RUN: -r %t,bcmp_impl,x %t -save-temps +; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s + +define i1 @foo(ptr %0, ptr %1, i64 %2) { + ; CHECK-LABEL: define{{.*}}i1 @foo + ; CHECK-NEXT: %bcmp = {{.*}}call i32 @bcmp + ; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0 + ; CHECK-NEXT: ret i1 %eq + + %cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2) + %eq = icmp eq i32 %cmp, 0 + ret i1 %eq +} + +declare i32 @memcmp(ptr, ptr, i64) +declare i32 @bcmp_impl(ptr, ptr, i64) + +;; Ensure bcmp is not removed from module because it is external. +; CHECK: define dso_local i32 @bcmp +define i32 @bcmp(ptr %0, ptr %1, i64 %2) noinline { + %r = call i32 @bcmp_impl(ptr %0, ptr %1, i64 %2) + ret i32 %r +} + diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp index 399306f39daeb..fbac9700db04f 100644 --- a/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -232,6 +232,10 @@ static cl::opt AllVtablesHaveTypeInfos("all-vtables-have-type-infos", cl::Hidden, cl::desc("All vtables have type infos")); +static cl::list + BitcodeLibFuncs("bitcode-libfuncs", cl::Hidden, + cl::desc("set of libfuncs implemented in bitcode")); + static void check(Error E, std::string Msg) { if (!E) return; @@ -468,6 +472,9 @@ static int run(int argc, char **argv) { if (HasErrors) return 1; + Lto.setBitcodeLibFuncs( + SmallVector(BitcodeLibFuncs.begin(), BitcodeLibFuncs.end())); + auto AddStream = [&](size_t Task, const Twine &ModuleName) -> std::unique_ptr {