[lld] r294234 - Add an option to use the MSVC linker to link LTO-generated object files.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 6 12:47:56 PST 2017


Author: ruiu
Date: Mon Feb  6 14:47:55 2017
New Revision: 294234

URL: http://llvm.org/viewvc/llvm-project?rev=294234&view=rev
Log:
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

Added:
    lld/trunk/test/COFF/Inputs/msvclto.s
    lld/trunk/test/COFF/msvclto.ll
Modified:
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/Driver.h
    lld/trunk/COFF/DriverUtils.cpp
    lld/trunk/COFF/LTO.cpp
    lld/trunk/COFF/LTO.h
    lld/trunk/COFF/Options.td
    lld/trunk/COFF/SymbolTable.cpp
    lld/trunk/COFF/SymbolTable.h

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Mon Feb  6 14:47:55 2017
@@ -814,6 +814,14 @@ void LinkerDriver::link(ArrayRef<const c
       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();

Modified: lld/trunk/COFF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.h (original)
+++ lld/trunk/COFF/Driver.h Mon Feb  6 14:47:55 2017
@@ -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,

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Mon Feb  6 14:47:55 2017
@@ -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 &O
 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<Memor
   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

Modified: lld/trunk/COFF/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/LTO.cpp?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/LTO.cpp (original)
+++ lld/trunk/COFF/LTO.cpp Mon Feb  6 14:47:55 2017
@@ -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
         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;
 }

Modified: lld/trunk/COFF/LTO.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/LTO.h?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/LTO.h (original)
+++ lld/trunk/COFF/LTO.h Mon Feb  6 14:47:55 2017
@@ -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;

Modified: lld/trunk/COFF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Options.td?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/Options.td (original)
+++ lld/trunk/COFF/Options.td Mon Feb  6 14:47:55 2017
@@ -92,6 +92,7 @@ def help_q : Flag<["/?", "-?"], "">, Ali
 
 // LLD extensions
 def nosymtab : F<"nosymtab">;
+def msvclto : F<"msvclto">;
 
 // Flags for debugging
 def debugpdb : F<"debugpdb">;

Modified: lld/trunk/COFF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.cpp?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.cpp (original)
+++ lld/trunk/COFF/SymbolTable.cpp Mon Feb  6 14:47:55 2017
@@ -351,19 +351,22 @@ SymbolBody *SymbolTable::addUndefined(St
   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

Modified: lld/trunk/COFF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/SymbolTable.h?rev=294234&r1=294233&r2=294234&view=diff
==============================================================================
--- lld/trunk/COFF/SymbolTable.h (original)
+++ lld/trunk/COFF/SymbolTable.h Mon Feb  6 14:47:55 2017
@@ -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.

Added: lld/trunk/test/COFF/Inputs/msvclto.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/msvclto.s?rev=294234&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/msvclto.s (added)
+++ lld/trunk/test/COFF/Inputs/msvclto.s Mon Feb  6 14:47:55 2017
@@ -0,0 +1,3 @@
+.globl foo
+foo:
+ret

Added: lld/trunk/test/COFF/msvclto.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/msvclto.ll?rev=294234&view=auto
==============================================================================
--- lld/trunk/test/COFF/msvclto.ll (added)
+++ lld/trunk/test/COFF/msvclto.ll Mon Feb  6 14:47:55 2017
@@ -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
+}




More information about the llvm-commits mailing list