From df5783b7a5a38535f3eca15f571c2072f367245c Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 28 Aug 2015 22:16:09 +0000 Subject: [PATCH] COFF: Implement parallel LTO code generation. This is exposed via a new flag /opt:lldltojobs=N, where N is the number of code generation threads. Differential Revision: http://reviews.llvm.org/D12309 llvm-svn: 246342 --- lld/COFF/Config.h | 3 ++ lld/COFF/Driver.cpp | 15 ++++--- lld/COFF/SymbolTable.cpp | 71 ++++++++++++++++++++----------- lld/COFF/SymbolTable.h | 13 +++--- lld/test/COFF/lto-parallel.ll | 20 +++++++++ lld/test/COFF/weak-external.test | 2 +- lld/test/COFF/weak-external3.test | 2 +- 7 files changed, 89 insertions(+), 37 deletions(-) create mode 100644 lld/test/COFF/lto-parallel.ll diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 4c1d90db60dc..4fb02c50f8cd 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -91,6 +91,9 @@ struct Configuration { // 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; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 649890f46d51..6781ccf5f292 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -372,9 +372,14 @@ void LinkerDriver::link(llvm::ArrayRef ArgsArr) { 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 @@ void LinkerDriver::link(llvm::ArrayRef ArgsArr) { 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); diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 1fb450b9e6bc..47b91f5df1ba 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -331,21 +331,7 @@ void SymbolTable::printMap(llvm::raw_ostream &OS) { } } -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 @@ void SymbolTable::addCombinedLTOObject() { 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 @@ void SymbolTable::addCombinedLTOObject() { } // 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 @@ ObjectFile *SymbolTable::createLTOObject(LTOCodeGenerator *CG) { 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); - auto *Obj = new ObjectFile(LTOMB->getMemBufferRef()); - Files.emplace_back(Obj); - ObjectFiles.push_back(Obj); - Obj->parse(); - return Obj; + + 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); + + 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 diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 1a3c89f7b15c..b8d12c4f92eb 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -68,10 +68,10 @@ public: // 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 @@ private: 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 @@ private: std::vector ObjectQueue; std::vector BitcodeFiles; - std::unique_ptr LTOMB; + std::vector> Objs; llvm::BumpPtrAllocator Alloc; }; diff --git a/lld/test/COFF/lto-parallel.ll b/lld/test/COFF/lto-parallel.ll new file mode 100644 index 000000000000..2303797019a5 --- /dev/null +++ b/lld/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 +} diff --git a/lld/test/COFF/weak-external.test b/lld/test/COFF/weak-external.test index bb0b3f6fcab1..3997170b897a 100644 --- a/lld/test/COFF/weak-external.test +++ b/lld/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$}} diff --git a/lld/test/COFF/weak-external3.test b/lld/test/COFF/weak-external3.test index f13bd492b455..9ba32982d505 100644 --- a/lld/test/COFF/weak-external3.test +++ b/lld/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$}}