Add an option to use the MSVC linker to link LTO-generated object files.

This patch defines a new command line option, /MSVCLTO, to LLD.
If that option is given, LLD invokes link.exe to link LTO-generated
object files. This is hacky but useful because link.exe can create
PDB files.

Differential Revision: https://reviews.llvm.org/D29526

llvm-svn: 294234
This commit is contained in:
Rui Ueyama
2017-02-06 20:47:55 +00:00
parent efc4eba816
commit 1e0b158dbd
10 changed files with 120 additions and 17 deletions

View File

@@ -814,6 +814,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
addUndefined(mangle("_load_config_used"));
} while (run());
// If /msvclto is given, we use the MSVC linker to link LTO output files.
// This is useful because MSVC link.exe can generate complete PDBs.
if (Args.hasArg(OPT_msvclto)) {
std::vector<StringRef> ObjectFiles = Symtab.compileBitcodeFiles();
runMSVCLinker(Args, ObjectFiles);
exit(0);
}
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files.
Symtab.addCombinedLTOObjects();

View File

@@ -178,6 +178,8 @@ void checkFailIfMismatch(StringRef Arg);
std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
void runMSVCLinker(llvm::opt::InputArgList &Args, ArrayRef<StringRef> Objects);
// Create enum with OPT_xxx values for each option in Options.td
enum {
OPT_INVALID = 0,

View File

@@ -50,10 +50,18 @@ public:
void add(const char *S) { Args.push_back(Saver.save(S).data()); }
void run() {
if (Config->Verbose) {
outs() << Prog;
for (const char *Arg : Args)
outs() << " " << Arg;
outs() << '\n';
}
ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog);
if (auto EC = ExeOrErr.getError())
fatal(EC, "unable to find " + Prog + " in PATH: ");
const char *Exe = Saver.save(*ExeOrErr).data();
Args.insert(Args.begin(), Exe);
Args.push_back(nullptr);
if (sys::ExecuteAndWait(Args[0], Args.data()) != 0) {
@@ -282,11 +290,19 @@ static void quoteAndPrint(raw_ostream &Out, StringRef S) {
namespace {
class TemporaryFile {
public:
TemporaryFile(StringRef Prefix, StringRef Extn) {
TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
SmallString<128> S;
if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
fatal(EC, "cannot create a temporary file");
Path = S.str();
if (!Contents.empty()) {
std::error_code EC;
raw_fd_ostream OS(Path, EC, sys::fs::F_None);
if (EC)
fatal(EC, "failed to open " + Path);
OS << Contents;
}
}
TemporaryFile(TemporaryFile &&Obj) {
@@ -617,6 +633,60 @@ convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
return File.getMemoryBuffer();
}
static bool isBitcodeFile(StringRef Path) {
std::unique_ptr<MemoryBuffer> MB = check(
MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
StringRef Buf = MB->getBuffer();
return sys::fs::identify_magic(Buf) == sys::fs::file_magic::bitcode;
}
// Run MSVC link.exe for given in-memory object files.
// Command line options are copied from those given to LLD.
// This is for the /msvclto option.
void runMSVCLinker(opt::InputArgList &Args, ArrayRef<StringRef> Objects) {
// Write the in-memory object files to disk.
std::vector<TemporaryFile> Temps;
for (StringRef S : Objects)
Temps.emplace_back("lto", "obj", S);
// Create a response file.
std::string Rsp = "/nologo ";
for (TemporaryFile &T : Temps)
Rsp += quote(T.Path) + " ";
for (auto *Arg : Args) {
switch (Arg->getOption().getID()) {
case OPT_linkrepro:
case OPT_lldmap:
case OPT_lldmap_file:
case OPT_msvclto:
// LLD-specific options are stripped.
break;
case OPT_opt:
if (!StringRef(Arg->getValue()).startswith("lld"))
Rsp += toString(Arg) + " ";
break;
case OPT_INPUT:
// Bitcode files are stripped as they've been compiled to
// native object files.
if (!isBitcodeFile(Arg->getValue()))
Rsp += quote(Arg->getValue()) + " ";
break;
default:
Rsp += toString(Arg) + " ";
}
}
if (Config->Verbose)
outs() << "link.exe " << Rsp << "\n";
// Run MSVC link.exe.
Temps.emplace_back("lto", "rsp", Rsp);
Executor E("link.exe");
E.add(Twine("@" + Temps.back().Path));
E.run();
}
// Create OptTable
// Create prefix string literals used in Options.td

View File

@@ -105,9 +105,8 @@ void BitcodeCompiler::add(BitcodeFile &F) {
}
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting ObjectFile(s).
std::vector<InputFile *> BitcodeCompiler::compile() {
std::vector<InputFile *> Ret;
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
unsigned MaxTasks = LTOObj->getMaxTasks();
Buff.resize(MaxTasks);
@@ -116,10 +115,9 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
llvm::make_unique<raw_svector_ostream>(Buff[Task]));
}));
for (unsigned I = 0; I != MaxTasks; ++I) {
if (Buff[I].empty())
continue;
Ret.push_back(make<ObjectFile>(MemoryBufferRef(Buff[I], "lto.tmp")));
}
std::vector<StringRef> Ret;
for (unsigned I = 0; I != MaxTasks; ++I)
if (!Buff[I].empty())
Ret.emplace_back(Buff[I].data(), Buff[I].size());
return Ret;
}

View File

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

View File

@@ -92,6 +92,7 @@ def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// LLD extensions
def nosymtab : F<"nosymtab">;
def msvclto : F<"msvclto">;
// Flags for debugging
def debugpdb : F<"debugpdb">;

View File

@@ -351,19 +351,22 @@ SymbolBody *SymbolTable::addUndefined(StringRef Name) {
return addUndefined(Name, nullptr, false)->body();
}
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFiles.empty())
return;
std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
LTO.reset(new BitcodeCompiler);
for (BitcodeFile *F : BitcodeFiles)
LTO->add(*F);
return LTO->compile();
}
for (auto *File : LTO->compile()) {
auto *Obj = cast<ObjectFile>(File);
ObjectFiles.push_back(Obj);
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFiles.empty())
return;
for (StringRef Object : compileBitcodeFiles()) {
auto *Obj = make<ObjectFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
ObjectFiles.push_back(Obj);
}
}
} // namespace coff
} // namespace lld

View File

@@ -74,6 +74,7 @@ public:
// 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();
std::vector<StringRef> compileBitcodeFiles();
// The writer needs to handle DLL import libraries specially in
// order to create the import descriptor table.

View File

@@ -0,0 +1,3 @@
.globl foo
foo:
ret

17
lld/test/COFF/msvclto.ll Normal file
View File

@@ -0,0 +1,17 @@
; RUN: llvm-as -o %t1.obj %s
; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t2.obj %p/Inputs/msvclto.s
; RUN: lld-link %t1.obj %t2.obj /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
; RUN: /entry:main /verbose /subsystem:console > %t.log 2>&1 || true
; RUN: FileCheck %s < %t.log
; CHECK: link.exe /nologo {{.*}} {{.*}}2.obj /out:{{.*}}.exe /opt:icf /entry:main /verbose /subsystem:console
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
declare void @foo()
define i32 @main() {
call void @foo()
ret i32 0
}