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
This commit is contained in:
Peter Collingbourne 2015-08-28 22:16:09 +00:00
parent adbcf12029
commit df5783b7a5
7 changed files with 89 additions and 37 deletions

View File

@ -91,6 +91,9 @@ struct Configuration {
// Used for /opt:lldlto=N // Used for /opt:lldlto=N
unsigned LTOOptLevel = 2; unsigned LTOOptLevel = 2;
// Used for /opt:lldltojobs=N
unsigned LTOJobs = 1;
// Used for /merge:from=to (e.g. /merge:.rdata=.text) // Used for /merge:from=to (e.g. /merge:.rdata=.text)
std::map<StringRef, StringRef> Merge; std::map<StringRef, StringRef> Merge;

View File

@ -372,9 +372,14 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
if (StringRef(S).startswith("lldlto=")) { if (StringRef(S).startswith("lldlto=")) {
StringRef OptLevel = StringRef(S).substr(7); StringRef OptLevel = StringRef(S).substr(7);
if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
Config->LTOOptLevel > 3) { Config->LTOOptLevel > 3)
error("/opt:lldlto: invalid optimization level: " + OptLevel); 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; continue;
} }
if (S != "ref" && S != "icf" && S != "noicf" && if (S != "ref" && S != "icf" && S != "noicf" &&
@ -594,9 +599,9 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
Symtab.run(); Symtab.run();
} }
// Do LTO by compiling bitcode input files to a native COFF file // Do LTO by compiling bitcode input files to a set of native COFF files then
// then link that file. // link those files.
Symtab.addCombinedLTOObject(); Symtab.addCombinedLTOObjects();
// Make sure we have resolved all symbols. // Make sure we have resolved all symbols.
Symtab.reportRemainingUndefines(/*Resolve=*/true); Symtab.reportRemainingUndefines(/*Resolve=*/true);

View File

@ -331,21 +331,7 @@ void SymbolTable::printMap(llvm::raw_ostream &OS) {
} }
} }
void SymbolTable::addCombinedLTOObject() { void SymbolTable::addCombinedLTOObject(ObjectFile *Obj) {
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);
for (SymbolBody *Body : Obj->getSymbols()) { for (SymbolBody *Body : Obj->getSymbols()) {
if (!Body->isExternal()) if (!Body->isExternal())
continue; continue;
@ -371,6 +357,25 @@ void SymbolTable::addCombinedLTOObject() {
if (Comp < 0) if (Comp < 0)
Sym->Body = Body; 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<ObjectFile *> Objs = createLTOObjects(&CG);
for (ObjectFile *Obj : Objs)
addCombinedLTOObject(Obj);
size_t NumBitcodeFiles = BitcodeFiles.size(); size_t NumBitcodeFiles = BitcodeFiles.size();
run(); run();
@ -379,8 +384,8 @@ void SymbolTable::addCombinedLTOObject() {
} }
// Combine and compile bitcode files and then return the result // Combine and compile bitcode files and then return the result
// as a regular COFF object file. // as a vector of regular COFF object files.
ObjectFile *SymbolTable::createLTOObject(LTOCodeGenerator *CG) { std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
// All symbols referenced by non-bitcode objects must be preserved. // All symbols referenced by non-bitcode objects must be preserved.
for (ObjectFile *File : ObjectFiles) for (ObjectFile *File : ObjectFiles)
for (SymbolBody *Body : File->getSymbols()) for (SymbolBody *Body : File->getSymbols())
@ -406,14 +411,32 @@ ObjectFile *SymbolTable::createLTOObject(LTOCodeGenerator *CG) {
CG->addModule(BitcodeFiles[I]->getModule()); CG->addModule(BitcodeFiles[I]->getModule());
std::string ErrMsg; std::string ErrMsg;
LTOMB = CG->compile(false, false, false, ErrMsg); // take MB ownership if (!CG->optimize(false, false, false, ErrMsg))
if (!LTOMB)
error(ErrMsg); error(ErrMsg);
auto *Obj = new ObjectFile(LTOMB->getMemBufferRef());
Files.emplace_back(Obj); Objs.resize(Config->LTOJobs);
ObjectFiles.push_back(Obj); // Use std::list to avoid invalidation of pointers in OSPtrs.
Obj->parse(); std::list<raw_svector_ostream> OSs;
return Obj; std::vector<raw_pwrite_stream *> OSPtrs;
for (SmallVector<char, 0> &Obj : Objs) {
OSs.emplace_back(Obj);
OSPtrs.push_back(&OSs.back());
}
if (!CG->compileOptimized(OSPtrs, ErrMsg))
error(ErrMsg);
std::vector<ObjectFile *> ObjFiles;
for (SmallVector<char, 0> &Obj : Objs) {
auto *ObjFile = new ObjectFile(
MemoryBufferRef(StringRef(Obj.data(), Obj.size()), "<LTO object>"));
Files.emplace_back(ObjFile);
ObjectFiles.push_back(ObjFile);
ObjFile->parse();
ObjFiles.push_back(ObjFile);
}
return ObjFiles;
} }
} // namespace coff } // namespace coff

View File

@ -68,10 +68,10 @@ public:
// Print a layout map to OS. // Print a layout map to OS.
void printMap(llvm::raw_ostream &OS); void printMap(llvm::raw_ostream &OS);
// Build a COFF object representing the combined contents of BitcodeFiles // Build a set of COFF objects representing the combined contents of
// and add it to the symbol table. Called after all files are added and // BitcodeFiles and add them to the symbol table. Called after all files are
// before the writer writes results to a file. // added and before the writer writes results to a file.
void addCombinedLTOObject(); void addCombinedLTOObjects();
// The writer needs to handle DLL import libraries specially in // The writer needs to handle DLL import libraries specially in
// order to create the import descriptor table. // order to create the import descriptor table.
@ -98,7 +98,8 @@ private:
StringRef findByPrefix(StringRef Prefix); StringRef findByPrefix(StringRef Prefix);
void addMemberFile(Lazy *Body); void addMemberFile(Lazy *Body);
ObjectFile *createLTOObject(llvm::LTOCodeGenerator *CG); void addCombinedLTOObject(ObjectFile *Obj);
std::vector<ObjectFile *> createLTOObjects(llvm::LTOCodeGenerator *CG);
llvm::DenseMap<StringRef, Symbol *> Symtab; llvm::DenseMap<StringRef, Symbol *> Symtab;
@ -107,7 +108,7 @@ private:
std::vector<InputFile *> ObjectQueue; std::vector<InputFile *> ObjectQueue;
std::vector<BitcodeFile *> BitcodeFiles; std::vector<BitcodeFile *> BitcodeFiles;
std::unique_ptr<MemoryBuffer> LTOMB; std::vector<SmallVector<char, 0>> Objs;
llvm::BumpPtrAllocator Alloc; llvm::BumpPtrAllocator Alloc;
}; };

View File

@ -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: <lto object>:
; CHECK: foo
define void @foo() {
call void @bar()
ret void
}
; CHECK: <lto object>:
; CHECK: bar
define void @bar() {
call void @foo()
ret void
}

View File

@ -4,7 +4,7 @@
# RUN: lld-link /out:%t2.exe /entry:g /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj # RUN: lld-link /out:%t2.exe /entry:g /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj
# RUN: FileCheck %s < %t2.map # RUN: FileCheck %s < %t2.map
# CHECK: lto-llvm{{.*}}: # CHECK: <lto object>:
# CHECK-NOT: : # CHECK-NOT: :
# CHECK: {{ g$}} # CHECK: {{ g$}}

View File

@ -5,7 +5,7 @@
# RUN: lld-link /out:%t2.exe /entry:f /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj # 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 # RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map
# CHECK1: lto-llvm{{.*}}: # CHECK1: <lto object>:
# CHECK1-NOT: : # CHECK1-NOT: :
# CHECK1: {{ g$}} # CHECK1: {{ g$}}