Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/COFF/Config.h @@ -91,6 +91,9 @@ // Used for /opt:lldlto=N unsigned LTOOptLevel = 2; + // Used for /opt:lldltojobs=N + unsigned LTOJobs = 1; + // Used for /merge:from=to (e.g. /merge:.rdata=.text) std::map Merge; Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -372,9 +372,14 @@ if (StringRef(S).startswith("lldlto=")) { StringRef OptLevel = StringRef(S).substr(7); if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || - Config->LTOOptLevel > 3) { + Config->LTOOptLevel > 3) error("/opt:lldlto: invalid optimization level: " + OptLevel); - } + continue; + } + if (StringRef(S).startswith("lldltojobs=")) { + StringRef Jobs = StringRef(S).substr(11); + if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) + error("/opt:lldltojobs: invalid job count: " + Jobs); continue; } if (S != "ref" && S != "icf" && S != "noicf" && @@ -594,9 +599,9 @@ Symtab.run(); } - // Do LTO by compiling bitcode input files to a native COFF file - // then link that file. - Symtab.addCombinedLTOObject(); + // Do LTO by compiling bitcode input files to a set of native COFF files then + // link those files. + Symtab.addCombinedLTOObjects(); // Make sure we have resolved all symbols. Symtab.reportRemainingUndefines(/*Resolve=*/true); Index: lld/trunk/COFF/SymbolTable.h =================================================================== --- lld/trunk/COFF/SymbolTable.h +++ lld/trunk/COFF/SymbolTable.h @@ -68,10 +68,10 @@ // Print a layout map to OS. void printMap(llvm::raw_ostream &OS); - // Build a COFF object representing the combined contents of BitcodeFiles - // and add it to the symbol table. Called after all files are added and - // before the writer writes results to a file. - void addCombinedLTOObject(); + // Build a set of COFF objects representing the combined contents of + // BitcodeFiles and add them to the symbol table. Called after all files are + // added and before the writer writes results to a file. + void addCombinedLTOObjects(); // The writer needs to handle DLL import libraries specially in // order to create the import descriptor table. @@ -98,7 +98,8 @@ StringRef findByPrefix(StringRef Prefix); void addMemberFile(Lazy *Body); - ObjectFile *createLTOObject(llvm::LTOCodeGenerator *CG); + void addCombinedLTOObject(ObjectFile *Obj); + std::vector createLTOObjects(llvm::LTOCodeGenerator *CG); llvm::DenseMap Symtab; @@ -107,7 +108,7 @@ std::vector ObjectQueue; std::vector BitcodeFiles; - std::unique_ptr LTOMB; + std::vector> Objs; llvm::BumpPtrAllocator Alloc; }; Index: lld/trunk/COFF/SymbolTable.cpp =================================================================== --- lld/trunk/COFF/SymbolTable.cpp +++ lld/trunk/COFF/SymbolTable.cpp @@ -331,21 +331,7 @@ } } -void SymbolTable::addCombinedLTOObject() { - if (BitcodeFiles.empty()) - return; - - // Diagnose any undefined symbols early, but do not resolve weak externals, - // as resolution breaks the invariant that each Symbol points to a unique - // SymbolBody, which we rely on to replace DefinedBitcode symbols correctly. - reportRemainingUndefines(/*Resolve=*/false); - - // Create an object file and add it to the symbol table by replacing any - // DefinedBitcode symbols with the definitions in the object file. - LTOCodeGenerator CG; - CG.setOptLevel(Config->LTOOptLevel); - ObjectFile *Obj = createLTOObject(&CG); - +void SymbolTable::addCombinedLTOObject(ObjectFile *Obj) { for (SymbolBody *Body : Obj->getSymbols()) { if (!Body->isExternal()) continue; @@ -371,6 +357,25 @@ if (Comp < 0) Sym->Body = Body; } +} + +void SymbolTable::addCombinedLTOObjects() { + if (BitcodeFiles.empty()) + return; + + // Diagnose any undefined symbols early, but do not resolve weak externals, + // as resolution breaks the invariant that each Symbol points to a unique + // SymbolBody, which we rely on to replace DefinedBitcode symbols correctly. + reportRemainingUndefines(/*Resolve=*/false); + + // Create an object file and add it to the symbol table by replacing any + // DefinedBitcode symbols with the definitions in the object file. + LTOCodeGenerator CG; + CG.setOptLevel(Config->LTOOptLevel); + std::vector Objs = createLTOObjects(&CG); + + for (ObjectFile *Obj : Objs) + addCombinedLTOObject(Obj); size_t NumBitcodeFiles = BitcodeFiles.size(); run(); @@ -379,8 +384,8 @@ } // Combine and compile bitcode files and then return the result -// as a regular COFF object file. -ObjectFile *SymbolTable::createLTOObject(LTOCodeGenerator *CG) { +// as a vector of regular COFF object files. +std::vector SymbolTable::createLTOObjects(LTOCodeGenerator *CG) { // All symbols referenced by non-bitcode objects must be preserved. for (ObjectFile *File : ObjectFiles) for (SymbolBody *Body : File->getSymbols()) @@ -406,14 +411,32 @@ CG->addModule(BitcodeFiles[I]->getModule()); std::string ErrMsg; - LTOMB = CG->compile(false, false, false, ErrMsg); // take MB ownership - if (!LTOMB) + if (!CG->optimize(false, false, false, ErrMsg)) + error(ErrMsg); + + Objs.resize(Config->LTOJobs); + // Use std::list to avoid invalidation of pointers in OSPtrs. + std::list OSs; + std::vector OSPtrs; + for (SmallVector &Obj : Objs) { + OSs.emplace_back(Obj); + OSPtrs.push_back(&OSs.back()); + } + + if (!CG->compileOptimized(OSPtrs, ErrMsg)) error(ErrMsg); - auto *Obj = new ObjectFile(LTOMB->getMemBufferRef()); - Files.emplace_back(Obj); - ObjectFiles.push_back(Obj); - Obj->parse(); - return Obj; + + std::vector ObjFiles; + for (SmallVector &Obj : Objs) { + auto *ObjFile = new ObjectFile( + MemoryBufferRef(StringRef(Obj.data(), Obj.size()), "")); + Files.emplace_back(ObjFile); + ObjectFiles.push_back(ObjFile); + ObjFile->parse(); + ObjFiles.push_back(ObjFile); + } + + return ObjFiles; } } // namespace coff Index: lld/trunk/test/COFF/lto-parallel.ll =================================================================== --- lld/trunk/test/COFF/lto-parallel.ll +++ lld/trunk/test/COFF/lto-parallel.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as -o %t.obj %s +; RUN: lld-link /out:%t.exe /entry:foo /include:bar /opt:lldltojobs=2 /subsystem:console /lldmap:%t.map %t.obj +; RUN: FileCheck %s < %t.map + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +; CHECK: : +; CHECK: foo +define void @foo() { + call void @bar() + ret void +} + +; CHECK: : +; CHECK: bar +define void @bar() { + call void @foo() + ret void +} Index: lld/trunk/test/COFF/weak-external.test =================================================================== --- lld/trunk/test/COFF/weak-external.test +++ lld/trunk/test/COFF/weak-external.test @@ -4,7 +4,7 @@ # RUN: lld-link /out:%t2.exe /entry:g /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj # RUN: FileCheck %s < %t2.map -# CHECK: lto-llvm{{.*}}: +# CHECK: : # CHECK-NOT: : # CHECK: {{ g$}} Index: lld/trunk/test/COFF/weak-external3.test =================================================================== --- lld/trunk/test/COFF/weak-external3.test +++ lld/trunk/test/COFF/weak-external3.test @@ -5,7 +5,7 @@ # RUN: lld-link /out:%t2.exe /entry:f /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj # RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map -# CHECK1: lto-llvm{{.*}}: +# CHECK1: : # CHECK1-NOT: : # CHECK1: {{ g$}}