Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -93,6 +93,7 @@ ELFKind EKind = ELFNoneKind; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t EntryAddr = -1; + unsigned CGThreads; unsigned LtoO; unsigned Optimize; }; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -308,6 +308,7 @@ Config->LtoO = getInteger(Args, OPT_lto_O, 2); if (Config->LtoO > 3) error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O)); + Config->CGThreads = getInteger(Args, OPT_jobs, 1); Config->ZExecStack = hasZOption(Args, "execstack"); Config->ZNodelete = hasZOption(Args, "nodelete"); Index: ELF/LTO.h =================================================================== --- ELF/LTO.h +++ ELF/LTO.h @@ -37,18 +37,19 @@ class BitcodeCompiler { public: void add(BitcodeFile &F); - std::unique_ptr compile(); + std::vector> compile(); BitcodeCompiler() : Combined(new llvm::Module("ld-temp.o", Context)), Mover(*Combined) {} private: + std::vector> runSplitCodegen(); llvm::TargetMachine *getTargetMachine(); llvm::LLVMContext Context; std::unique_ptr Combined; llvm::IRMover Mover; - SmallString<0> OwningData; + std::vector> OwningData; std::unique_ptr MB; llvm::StringSet<> InternalizedSyms; }; Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -16,6 +16,7 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/CommandFlags.h" +#include "llvm/CodeGen/ParallelCG.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Linker/IRMover.h" #include "llvm/Support/StringSaver.h" @@ -33,10 +34,12 @@ using namespace lld::elf; // This is for use when debugging LTO. -static void saveLtoObjectFile(StringRef Buffer) { +static void saveLtoObjectFile(StringRef Buffer, unsigned I, bool Many) { std::error_code EC; - raw_fd_ostream OS(Config->OutputFile.str() + ".lto.o", EC, - sys::fs::OpenFlags::F_None); + SmallString<128> FileName = Config->OutputFile; + FileName += (Many) ? utostr(I) : ""; + FileName += ".lto.o"; + raw_fd_ostream OS(FileName, EC, sys::fs::OpenFlags::F_None); check(EC); OS << Buffer; } @@ -136,9 +139,63 @@ GV.setLinkage(GlobalValue::InternalLinkage); } +static SubtargetFeatures getFeatures(Triple &TheTriple) { + SubtargetFeatures Features; + Features.getDefaultSubtargetFeatures(TheTriple); + for (const std::string &A : MAttrs) + Features.AddFeature(A); + return Features; +} + +static CodeGenOpt::Level getCGOptLevel() { + switch (Config->LtoO) { + case 0: + return CodeGenOpt::None; + case 1: + return CodeGenOpt::Less; + case 2: + return CodeGenOpt::Default; + case 3: + return CodeGenOpt::Aggressive; + } + llvm_unreachable("Invalid optimization level"); +} + +std::vector> BitcodeCompiler::runSplitCodegen() { + unsigned NumThreads = (Config->CGThreads >= 1) ? Config->CGThreads : 1; + OwningData.resize(NumThreads); + + std::list OSs; + std::vector OSPtrs; + for (SmallString<0> &Obj : OwningData) { + OSs.emplace_back(Obj); + OSPtrs.push_back(&OSs.back()); + } + + std::string MCpu; + Triple TheTriple(Combined->getTargetTriple()); + SubtargetFeatures Features = getFeatures(TheTriple); + splitCodeGen(std::move(Combined), OSPtrs, {}, MCpu, Features.getString(), + InitTargetOptionsFromCodeGenFlags(), + Config->Pic ? Reloc::PIC_ : Reloc::Static, CodeModel::Default, + getCGOptLevel()); + + std::vector> ObjFiles; + for (SmallString<0> &Obj : OwningData) { + ObjFiles.push_back(createObjectFile( + MemoryBufferRef(Obj, "LLD-INTERNAL-combined-lto-object"))); + } + + if (Config->SaveTemps) + for (unsigned I = 0; I < NumThreads; ++I) + saveLtoObjectFile(OwningData[I], I, NumThreads > 1); + + return ObjFiles; +} + // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile. -std::unique_ptr BitcodeCompiler::compile() { +std::vector> BitcodeCompiler::compile() { for (const auto &Name : InternalizedSyms) { GlobalValue *GV = Combined->getNamedValue(Name.first()); assert(GV); @@ -151,17 +208,7 @@ std::unique_ptr TM(getTargetMachine()); runLTOPasses(*Combined, *TM); - raw_svector_ostream OS(OwningData); - legacy::PassManager CodeGenPasses; - if (TM->addPassesToEmitFile(CodeGenPasses, OS, - TargetMachine::CGFT_ObjectFile)) - fatal("failed to setup codegen"); - CodeGenPasses.run(*Combined); - MB = MemoryBuffer::getMemBuffer(OwningData, - "LLD-INTERNAL-combined-lto-object", false); - if (Config->SaveTemps) - saveLtoObjectFile(MB->getBuffer()); - return createObjectFile(*MB); + return runSplitCodegen(); } TargetMachine *BitcodeCompiler::getTargetMachine() { Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -233,7 +233,9 @@ // Aliases for ignored options def alias_version_script_version_script : Joined<["--"], "version-script=">, Alias; -// Debugging/developer options +// LTO-related options. +def jobs : Joined<["--"], "jobs=">, + HelpText<"Number of threads to run codegen">; def disable_verify : Flag<["-"], "disable-verify">; def mllvm : Separate<["-"], "mllvm">; def save_temps : Flag<["-"], "save-temps">; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -110,24 +110,26 @@ Lto.reset(new BitcodeCompiler); for (const std::unique_ptr &F : BitcodeFiles) Lto->add(*F); - std::unique_ptr IF = Lto->compile(); - ObjectFile *Obj = cast>(IF.release()); - - // Replace bitcode symbols. - llvm::DenseSet DummyGroups; - Obj->parse(DummyGroups); - for (SymbolBody *Body : Obj->getNonLocalSymbols()) { - Symbol *Sym = insert(Body); - Sym->Body->setUsedInRegularObj(); - if (Sym->Body->isShared()) - Sym->Body->MustBeInDynSym = true; - if (Sym->Body->MustBeInDynSym) - Body->MustBeInDynSym = true; - if (!Sym->Body->isUndefined() && Body->isUndefined()) - continue; - Sym->Body = Body; + std::vector> IFs = Lto->compile(); + for (auto &IF : IFs) { + ObjectFile *Obj = cast>(IF.release()); + + // Replace bitcode symbols. + llvm::DenseSet DummyGroups; + Obj->parse(DummyGroups); + for (SymbolBody *Body : Obj->getNonLocalSymbols()) { + Symbol *Sym = insert(Body); + Sym->Body->setUsedInRegularObj(); + if (Sym->Body->isShared()) + Sym->Body->MustBeInDynSym = true; + if (Sym->Body->MustBeInDynSym) + Body->MustBeInDynSym = true; + if (!Sym->Body->isUndefined() && Body->isUndefined()) + continue; + Sym->Body = Body; + } + ObjectFiles.emplace_back(Obj); } - ObjectFiles.emplace_back(Obj); } // Add an undefined symbol.