[COFF] Assign unique identifiers to ObjFiles from LTO

Use the unique filenames that are used when /lldsavetemps is passed.
After this change, module names for LTO blobs in PDBs will be unique.
Visual Studio and probably other debuggers expect module names to be
unique.

Revert some changes from 1e0b158db (2017) that are no longer necessary
after removing MSVC LTO support.

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D78221
This commit is contained in:
Reid Kleckner 2020-04-15 09:54:22 -07:00
parent cd28a4736a
commit 91a6bfed61
9 changed files with 94 additions and 39 deletions

View File

@ -144,7 +144,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// Merge all the bitcode files we have seen, codegen the result // Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects. // and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() { std::vector<InputFile *> BitcodeCompiler::compile() {
unsigned maxTasks = ltoObj->getMaxTasks(); unsigned maxTasks = ltoObj->getMaxTasks();
buf.resize(maxTasks); buf.resize(maxTasks);
files.resize(maxTasks); files.resize(maxTasks);
@ -188,22 +188,32 @@ std::vector<StringRef> BitcodeCompiler::compile() {
if (!config->ltoCache.empty()) if (!config->ltoCache.empty())
pruneCache(config->ltoCache, config->ltoCachePolicy); pruneCache(config->ltoCache, config->ltoCachePolicy);
std::vector<StringRef> ret; std::vector<InputFile *> ret;
for (unsigned i = 0; i != maxTasks; ++i) { for (unsigned i = 0; i != maxTasks; ++i) {
if (buf[i].empty()) // Assign unique names to LTO objects. This ensures they have unique names
continue; // in the PDB if one is produced. The names should look like:
if (config->saveTemps) { // - foo.exe.lto.obj
if (i == 0) // - foo.exe.lto.1.obj
saveBuffer(buf[i], config->outputFile + ".lto.obj"); // - ...
else StringRef ltoObjName =
saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.obj"); saver.save(Twine(config->outputFile) + ".lto" +
} (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj");
ret.emplace_back(buf[i].data(), buf[i].size());
}
for (std::unique_ptr<MemoryBuffer> &file : files) // Get the native object contents either from the cache or from memory. Do
if (file) // not use the cached MemoryBuffer directly, or the PDB will not be
ret.push_back(file->getBuffer()); // deterministic.
StringRef objBuf;
if (files[i])
objBuf = files[i]->getBuffer();
else
objBuf = buf[i];
if (objBuf.empty())
continue;
if (config->saveTemps)
saveBuffer(buf[i], ltoObjName);
ret.push_back(make<ObjFile>(MemoryBufferRef(objBuf, ltoObjName)));
}
return ret; return ret;
} }

View File

@ -45,7 +45,7 @@ public:
~BitcodeCompiler(); ~BitcodeCompiler();
void add(BitcodeFile &f); void add(BitcodeFile &f);
std::vector<StringRef> compile(); std::vector<InputFile *> compile();
private: private:
std::unique_ptr<llvm::lto::LTO> ltoObj; std::unique_ptr<llvm::lto::LTO> ltoObj;

View File

@ -789,20 +789,16 @@ Symbol *SymbolTable::addUndefined(StringRef name) {
return addUndefined(name, nullptr, false); return addUndefined(name, nullptr, false);
} }
std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
lto.reset(new BitcodeCompiler);
for (BitcodeFile *f : BitcodeFile::instances)
lto->add(*f);
return lto->compile();
}
void SymbolTable::addCombinedLTOObjects() { void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFile::instances.empty()) if (BitcodeFile::instances.empty())
return; return;
ScopedTimer t(ltoTimer); ScopedTimer t(ltoTimer);
for (StringRef object : compileBitcodeFiles()) { lto.reset(new BitcodeCompiler);
auto *obj = make<ObjFile>(MemoryBufferRef(object, "lto.tmp")); for (BitcodeFile *f : BitcodeFile::instances)
lto->add(*f);
for (InputFile *newObj : lto->compile()) {
ObjFile *obj = cast<ObjFile>(newObj);
obj->parse(); obj->parse();
ObjFile::instances.push_back(obj); ObjFile::instances.push_back(obj);
} }

View File

@ -77,7 +77,6 @@ public:
// BitcodeFiles and add them to the symbol table. Called after all files are // BitcodeFiles and add them to the symbol table. Called after all files are
// added and before the writer writes results to a file. // added and before the writer writes results to a file.
void addCombinedLTOObjects(); void addCombinedLTOObjects();
std::vector<StringRef> compileBitcodeFiles();
// Creates an Undefined symbol for a given name. // Creates an Undefined symbol for a given name.
Symbol *addUndefined(StringRef name); Symbol *addUndefined(StringRef name);

View File

@ -1,23 +1,35 @@
; REQUIRES: x86 ; REQUIRES: x86
; RUN: llvm-as -o %t.obj %s ; RUN: llvm-as -o %t.obj %s
; RUN: lld-link -opt:noicf /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=2 /subsystem:console /lldmap:%t.map %t.obj ; RUN: lld-link -opt:noicf /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=2 /subsystem:console /lldmap:%t.map %t.obj /debug /pdb:%t.pdb
; RUN: FileCheck %s < %t.map ; RUN: FileCheck %s < %t.map
; RUN: llvm-pdbutil dump %t.pdb --modules | FileCheck %s --check-prefix=PDB
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc" target triple = "x86_64-pc-windows-msvc"
; CHECK: lto.tmp ; CHECK: lto-parallel.ll.tmp.exe.lto.obj:
; CHECK: lto.tmp ; CHECK: lto-parallel.ll.tmp.exe.lto.obj:
; CHECK-NEXT: foo ; CHECK-NEXT: foo
define void @foo() { define void @foo() {
call void @bar() call void @bar()
ret void ret void
} }
; CHECK: lto.tmp ; CHECK: lto-parallel.ll.tmp.exe.lto.1.obj:
; CHECK: lto.tmp ; CHECK: lto-parallel.ll.tmp.exe.lto.1.obj:
; CHECK: bar ; CHECK: bar
define void @bar() { define void @bar() {
call void @foo() call void @foo()
ret void ret void
} }
; Objects in the PDB should receive distinct names.
; PDB: Modules
; PDB: Mod 0000 | `{{.*}}lto-parallel.ll.tmp.exe.lto.obj`:
; PDB: Obj: `{{.*}}lto-parallel.ll.tmp.exe.lto.obj`:
; PDB: Mod 0001 | `{{.*}}lto-parallel.ll.tmp.exe.lto.1.obj`:
; PDB: Obj: `{{.*}}lto-parallel.ll.tmp.exe.lto.1.obj`:
; PDB: Mod 0002 | `* Linker *`:
; PDB: Obj: ``:

View File

@ -0,0 +1,38 @@
; REQUIRES: x86
; RUN: rm -rf %t && mkdir -p %t && cd %t
; RUN: opt -thinlto-bc -o main.bc %s
; RUN: opt -thinlto-bc -o foo.bc %S/Inputs/lto-dep.ll
; Even if the native object is cached, the PDB must be the same.
; RUN: rm -rf thinltocachedir && mkdir thinltocachedir
; RUN: lld-link /lldltocache:thinltocachedir /out:main.exe /entry:main /subsystem:console main.bc foo.bc /debug /pdb:main.pdb
; RUN: llvm-pdbutil dump --modules main.pdb | FileCheck %s
; Run again with the cache. Make sure we get the same object names.
; RUN: lld-link /lldltocache:thinltocachedir /out:main.exe /entry:main /subsystem:console main.bc foo.bc /debug /pdb:main.pdb
; RUN: llvm-pdbutil dump --modules main.pdb | FileCheck %s
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
define i32 @main() {
call void @foo()
ret i32 0
}
declare void @foo()
; CHECK: Modules
; CHECK: ============================================================
; CHECK: Mod 0000 | `{{.*}}main.exe.lto.obj`:
; CHECK: Obj: `{{.*}}main.exe.lto.obj`:
; CHECK: Mod 0001 | `{{.*}}main.exe.lto.1.obj`:
; CHECK: Obj: `{{.*}}main.exe.lto.1.obj`:
; CHECK: Mod 0002 | `{{.*}}main.exe.lto.2.obj`:
; CHECK: Obj: `{{.*}}main.exe.lto.2.obj`:
; CHECK: Mod 0003 | `* Linker *`:

View File

@ -4,15 +4,15 @@
; RUN: opt -thinlto-bc -o %T/thinlto/main.obj %s ; RUN: opt -thinlto-bc -o %T/thinlto/main.obj %s
; RUN: opt -thinlto-bc -o %T/thinlto/foo.obj %S/Inputs/lto-dep.ll ; RUN: opt -thinlto-bc -o %T/thinlto/foo.obj %S/Inputs/lto-dep.ll
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj ; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj
; RUN: llvm-nm %T/thinlto/main.exe1.lto.obj | FileCheck %s ; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; Test various possible options for /opt:lldltojobs ; Test various possible options for /opt:lldltojobs
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=1 ; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=1
; RUN: llvm-nm %T/thinlto/main.exe1.lto.obj | FileCheck %s ; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=all ; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=all
; RUN: llvm-nm %T/thinlto/main.exe1.lto.obj | FileCheck %s ; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=100 ; RUN: lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=100
; RUN: llvm-nm %T/thinlto/main.exe1.lto.obj | FileCheck %s ; RUN: llvm-nm %T/thinlto/main.exe.lto.1.obj | FileCheck %s
; RUN: not lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=foo 2>&1 | FileCheck %s --check-prefix=BAD-JOBS ; RUN: not lld-link /lldsavetemps /out:%T/thinlto/main.exe /entry:main /subsystem:console %T/thinlto/main.obj %T/thinlto/foo.obj /opt:lldltojobs=foo 2>&1 | FileCheck %s --check-prefix=BAD-JOBS
; BAD-JOBS: error: /opt:lldltojobs: invalid job count: foo ; BAD-JOBS: error: /opt:lldltojobs: invalid job count: foo

View File

@ -5,8 +5,8 @@
# 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.tmp # CHECK: .lto.obj:
# CHECK-NEXT: lto.tmp # CHECK-NEXT: .lto.obj:
# CHECK-NEXT: 0 g # CHECK-NEXT: 0 g
--- !COFF --- !COFF

View File

@ -6,8 +6,8 @@
# 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.tmp # CHECK1: .lto.obj:
# CHECK1: lto.tmp # CHECK1-NEXT: .lto.obj:
# CHECK1-NEXT: 0 g # CHECK1-NEXT: 0 g
# CHECK2: weak-external3.test.tmp.obj # CHECK2: weak-external3.test.tmp.obj