//===- LTO.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "LTO.h" #include "Config.h" #include "Driver.h" #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" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/ParallelCG.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" #include "llvm/LTO/legacy/UpdateCompilerUsed.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" using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; // This is for use when debugging LTO. static void saveBuffer(StringRef Buffer, const Twine &Path) { std::error_code EC; raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); if (EC) error(EC, "cannot create " + Path); OS << Buffer; } // This is for use when debugging LTO. static void saveBCFile(Module &M, const Twine &Path) { std::error_code EC; raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); if (EC) error(EC, "cannot create " + Path); WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true); } static void runNewCustomLtoPasses(Module &M, TargetMachine &TM) { PassBuilder PB(&TM); AAManager AA; // Parse a custom AA pipeline if asked to. if (!PB.parseAAPipeline(AA, Config->LtoAAPipeline)) { error("Unable to parse AA pipeline description: " + Config->LtoAAPipeline); return; } 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; PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple())); PMB.Inliner = createFunctionInliningPass(); PMB.VerifyInput = PMB.VerifyOutput = !Config->DisableVerify; PMB.LoopVectorize = true; PMB.SLPVectorize = true; 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, Config->OutputFile + ".lto.opt.bc"); } static bool shouldInternalize(const SmallPtrSet &Used, Symbol *S, GlobalValue *GV) { if (S->IsUsedInRegularObj || Used.count(GV)) return false; return !S->includeInDynsym(); } BitcodeCompiler::BitcodeCompiler() : Combined(new Module("ld-temp.o", Driver->Context)) {} static void undefine(Symbol *S) { replaceBody(S, S->body()->getName(), STV_DEFAULT, S->body()->Type, nullptr); } static void handleUndefinedAsmRefs(const BasicSymbolRef &Sym, GlobalValue *GV, StringSet<> &AsmUndefinedRefs) { // GV associated => not an assembly symbol, bail out. if (GV) return; // This is an undefined reference to a symbol in asm. We put that in // compiler.used, so that we can preserve it from being dropped from // the output, without necessarily preventing its internalization. SmallString<64> Name; raw_svector_ostream OS(Name); Sym.printName(OS); AsmUndefinedRefs.insert(Name.str()); } void BitcodeCompiler::add(BitcodeFile &F) { std::unique_ptr Obj = std::move(F.Obj); std::vector Keep; unsigned BodyIndex = 0; ArrayRef Syms = F.getSymbols(); Module &M = Obj->getModule(); if (M.getDataLayoutStr().empty()) fatal("invalid bitcode file: " + F.getName() + " has no datalayout"); // Discard non-compatible debug infos if necessary. M.materializeMetadata(); UpgradeDebugInfo(M); // If a symbol appears in @llvm.used, the linker is required // to treat the symbol as there is a reference to the symbol // that it cannot see. Therefore, we can't internalize. SmallPtrSet Used; collectUsedGlobalVariables(M, Used, /* CompilerUsed */ false); for (const BasicSymbolRef &Sym : Obj->symbols()) { uint32_t Flags = Sym.getFlags(); GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); if (GV && GV->hasAppendingLinkage()) Keep.push_back(GV); if (BitcodeFile::shouldSkip(Flags)) continue; Symbol *S = Syms[BodyIndex++]; if (Flags & BasicSymbolRef::SF_Undefined) { handleUndefinedAsmRefs(Sym, GV, AsmUndefinedRefs); continue; } auto *B = dyn_cast(S->body()); if (!B || B->file() != &F) continue; // We collect the set of symbols we want to internalize here // and change the linkage after the IRMover executed, i.e. after // we imported the symbols and satisfied undefined references // to it. We can't just change linkage here because otherwise // the IRMover will just rename the symbol. if (GV && shouldInternalize(Used, S, GV)) InternalizedSyms.insert(GV->getName()); // At this point we know that either the combined LTO object will provide a // definition of a symbol, or we will internalize it. In either case, we // need to undefine the symbol. In the former case, the real definition // needs to be able to replace the original definition without conflicting. // In the latter case, we need to allow the combined LTO object to provide a // definition with the same name, for example when doing parallel codegen. undefine(S); if (!GV) // Module asm symbol. continue; switch (GV->getLinkage()) { default: break; case GlobalValue::LinkOnceAnyLinkage: GV->setLinkage(GlobalValue::WeakAnyLinkage); break; case GlobalValue::LinkOnceODRLinkage: GV->setLinkage(GlobalValue::WeakODRLinkage); break; } Keep.push_back(GV); } IRMover Mover(*Combined); if (Error E = Mover.move(Obj->takeModule(), Keep, [](GlobalValue &, IRMover::ValueAdder) {})) { handleAllErrors(std::move(E), [&](const ErrorInfoBase &EIB) { fatal("failed to link module " + F.getName() + ": " + EIB.message()); }); } } static void internalize(GlobalValue &GV) { assert(!GV.hasLocalLinkage() && "Trying to internalize a symbol with local linkage!"); GV.setLinkage(GlobalValue::InternalLinkage); } std::vector> BitcodeCompiler::runSplitCodegen( const std::function()> &TMFactory) { unsigned NumThreads = Config->LtoJobs; OwningData.resize(NumThreads); std::list OSs; std::vector OSPtrs; for (SmallString<0> &Obj : OwningData) { OSs.emplace_back(Obj); OSPtrs.push_back(&OSs.back()); } splitCodeGen(std::move(Combined), OSPtrs, {}, TMFactory); std::vector> ObjFiles; for (SmallString<0> &Obj : OwningData) ObjFiles.push_back(createObjectFile( MemoryBufferRef(Obj, "LLD-INTERNAL-combined-lto-object"))); // If -save-temps is given, we need to save temporary objects to files. // This is for debugging. if (Config->SaveTemps) { if (NumThreads == 1) { saveBuffer(OwningData[0], Config->OutputFile + ".lto.o"); } else { for (unsigned I = 0; I < NumThreads; ++I) saveBuffer(OwningData[I], Config->OutputFile + Twine(I) + ".lto.o"); } } return ObjFiles; } // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile. std::vector> BitcodeCompiler::compile() { for (const auto &Name : InternalizedSyms) { GlobalValue *GV = Combined->getNamedValue(Name.first()); assert(GV); internalize(*GV); } std::string TheTriple = Combined->getTargetTriple(); std::string Msg; const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg); if (!T) fatal("target not found: " + Msg); // LLD supports the new relocations. TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); Options.RelaxELFRelocations = true; auto CreateTargetMachine = [&]() { return std::unique_ptr(T->createTargetMachine( TheTriple, "", "", Options, Config->Pic ? Reloc::PIC_ : Reloc::Static)); }; std::unique_ptr TM = CreateTargetMachine(); // Update llvm.compiler.used so that optimizations won't strip // off AsmUndefinedReferences. updateCompilerUsed(*Combined, *TM, AsmUndefinedRefs); if (Config->SaveTemps) saveBCFile(*Combined, Config->OutputFile + ".lto.bc"); runLTOPasses(*Combined, *TM); if (HasError) return {}; return runSplitCodegen(CreateTargetMachine); }