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:
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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">;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
3
lld/test/COFF/Inputs/msvclto.s
Normal file
3
lld/test/COFF/Inputs/msvclto.s
Normal file
@@ -0,0 +1,3 @@
|
||||
.globl foo
|
||||
foo:
|
||||
ret
|
||||
17
lld/test/COFF/msvclto.ll
Normal file
17
lld/test/COFF/msvclto.ll
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user