[lld] r260726 - Add initial LTO support.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 12 12:54:57 PST 2016


Author: rafael
Date: Fri Feb 12 14:54:57 2016
New Revision: 260726

URL: http://llvm.org/viewvc/llvm-project?rev=260726&view=rev
Log:
Add initial LTO support.

Added:
    lld/trunk/test/ELF/lto/
    lld/trunk/test/ELF/lto/lto-start.ll
Modified:
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/SymbolTable.cpp
    lld/trunk/ELF/SymbolTable.h
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/test/ELF/lit.local.cfg

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Fri Feb 12 14:54:57 2016
@@ -17,6 +17,7 @@
 #include "Writer.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/raw_ostream.h"
 #include <utility>
 
@@ -112,6 +113,9 @@ void LinkerDriver::addFile(StringRef Pat
   case file_magic::elf_shared_object:
     Files.push_back(createSharedFile(MBRef));
     return;
+  case sys::fs::file_magic::bitcode:
+    Files.push_back(make_unique<BitcodeFile>(MBRef));
+    return;
   default:
     Files.push_back(createObjectFile(MBRef));
   }
@@ -293,6 +297,11 @@ void LinkerDriver::createFiles(opt::Inpu
 }
 
 template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
+  // For LTO
+  InitializeAllTargets();
+  InitializeAllTargetMCs();
+  InitializeAllAsmPrinters();
+
   SymbolTable<ELFT> Symtab;
   std::unique_ptr<TargetInfo> TI(createTarget());
   Target = TI.get();
@@ -352,6 +361,8 @@ template <class ELFT> void LinkerDriver:
   for (StringRef S : Config->Undefined)
     Symtab.addUndefinedOpt(S);
 
+  Symtab.addCombinedLtoObject();
+
   for (auto *Arg : Args.filtered(OPT_wrap))
     Symtab.wrap(Arg->getValue());
 

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Fri Feb 12 14:54:57 2016
@@ -12,6 +12,9 @@
 #include "InputSection.h"
 #include "Symbols.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 using namespace llvm::ELF;
@@ -423,6 +426,28 @@ template <class ELFT> void SharedFile<EL
   }
 }
 
+BitcodeFile::BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
+
+bool BitcodeFile::classof(const InputFile *F) {
+  return F->kind() == BitcodeKind;
+}
+
+void BitcodeFile::parse() {
+  LLVMContext Context;
+  ErrorOr<std::unique_ptr<IRObjectFile>> ObjOrErr =
+      IRObjectFile::create(MB, Context);
+  fatal(ObjOrErr);
+  IRObjectFile &Obj = **ObjOrErr;
+  for (const BasicSymbolRef &Sym : Obj.symbols()) {
+    SmallString<64> Name;
+    raw_svector_ostream OS(Name);
+    Sym.printName(OS);
+    StringRef NameRef = Saver.save(StringRef(Name));
+    SymbolBody *Body = new (Alloc) DefinedBitcode(NameRef);
+    SymbolBodies.push_back(Body);
+  }
+}
+
 template <typename T>
 static std::unique_ptr<InputFile> createELFFileAux(MemoryBufferRef MB) {
   std::unique_ptr<T> Ret = llvm::make_unique<T>(MB);

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri Feb 12 14:54:57 2016
@@ -20,6 +20,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ELF.h"
+#include "llvm/Support/StringSaver.h"
 
 namespace lld {
 namespace elf2 {
@@ -33,10 +34,11 @@ class SymbolBody;
 // The root class of input files.
 class InputFile {
 public:
-  enum Kind { ObjectKind, SharedKind, ArchiveKind };
+  enum Kind { ObjectKind, SharedKind, ArchiveKind, BitcodeKind };
   Kind kind() const { return FileKind; }
 
   StringRef getName() const { return MB.getBufferIdentifier(); }
+  MemoryBufferRef MB;
 
   // Filename of .a which contained this file. If this file was
   // not in an archive file, it is the empty string. We use this
@@ -45,7 +47,6 @@ public:
 
 protected:
   InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
-  MemoryBufferRef MB;
 
 private:
   const Kind FileKind;
@@ -178,6 +179,19 @@ private:
   llvm::DenseSet<uint64_t> Seen;
 };
 
+class BitcodeFile : public InputFile {
+public:
+  explicit BitcodeFile(MemoryBufferRef M);
+  static bool classof(const InputFile *F);
+  void parse();
+
+  std::vector<SymbolBody *> SymbolBodies;
+
+private:
+  llvm::BumpPtrAllocator Alloc;
+  llvm::StringSaver Saver{Alloc};
+};
+
 // .so file.
 template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
   typedef ELFFileBase<ELFT> Base;

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Fri Feb 12 14:54:57 2016
@@ -1483,6 +1483,8 @@ void SymbolTableSection<ELFT>::writeGlob
     case SymbolBody::UndefinedKind:
     case SymbolBody::LazyKind:
       break;
+    case SymbolBody::DefinedBitcodeKind:
+      llvm_unreachable("Should have been replaced");
     }
 
     ESym->st_name = P.second;

Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Fri Feb 12 14:54:57 2016
@@ -18,7 +18,12 @@
 #include "Config.h"
 #include "Error.h"
 #include "Symbols.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Linker/Linker.h"
 #include "llvm/Support/StringSaver.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetMachine.h"
 
 using namespace llvm;
 using namespace llvm::object;
@@ -74,6 +79,15 @@ void SymbolTable<ELFT>::addFile(std::uni
     return;
   }
 
+  // LLVM bitcode file.
+  if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
+    BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
+    F->parse();
+    for (SymbolBody *B : F->SymbolBodies)
+      resolve(B);
+    return;
+  }
+
   // .o file
   auto *F = cast<ObjectFile<ELFT>>(FileP);
   ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
@@ -82,6 +96,70 @@ void SymbolTable<ELFT>::addFile(std::uni
     resolve(B);
 }
 
+// Codegen the module M and returns the resulting InputFile.
+template <class ELFT>
+std::unique_ptr<InputFile> SymbolTable<ELFT>::codegen(Module &M) {
+  StringRef TripleStr = M.getTargetTriple();
+  Triple TheTriple(TripleStr);
+
+  // FIXME: Should we have a default triple? The gold plugin uses
+  // sys::getDefaultTargetTriple(), but that is probably wrong given that this
+  // might be a cross linker.
+
+  std::string ErrMsg;
+  const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
+  if (!TheTarget)
+    fatal("Target not found: " + ErrMsg);
+
+  TargetOptions Options;
+  std::unique_ptr<TargetMachine> TM(
+      TheTarget->createTargetMachine(TripleStr, "", "", Options));
+
+  raw_svector_ostream OS(OwningLTOData);
+  legacy::PassManager CodeGenPasses;
+  if (TM->addPassesToEmitFile(CodeGenPasses, OS,
+                              TargetMachine::CGFT_ObjectFile))
+    fatal("Failed to setup codegen");
+  CodeGenPasses.run(M);
+  LtoBuffer = MemoryBuffer::getMemBuffer(OwningLTOData, "", false);
+  return createObjectFile(*LtoBuffer);
+}
+
+// Merge all the bitcode files we have seen, codegen the result and return
+// the resulting ObjectFile.
+template <class ELFT>
+ObjectFile<ELFT> *SymbolTable<ELFT>::createCombinedLtoObject() {
+  LLVMContext Context;
+  Module Combined("ld-temp.o", Context);
+  Linker L(Combined);
+  for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles) {
+    std::unique_ptr<MemoryBuffer> Buffer =
+        MemoryBuffer::getMemBuffer(F->MB, false);
+    ErrorOr<std::unique_ptr<Module>> MOrErr =
+        getLazyBitcodeModule(std::move(Buffer), Context,
+                             /*ShouldLazyLoadMetadata*/ true);
+    fatal(MOrErr);
+    std::unique_ptr<Module> &M = *MOrErr;
+    L.linkInModule(std::move(M));
+  }
+  std::unique_ptr<InputFile> F = codegen(Combined);
+  ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(F.release()));
+  return &*ObjectFiles.back();
+}
+
+template <class ELFT> void SymbolTable<ELFT>::addCombinedLtoObject() {
+  if (BitcodeFiles.empty())
+    return;
+  ObjectFile<ELFT> *Obj = createCombinedLtoObject();
+  // FIXME: We probably have to ignore comdats here.
+  Obj->parse(ComdatGroups);
+  for (SymbolBody *Body : Obj->getSymbols()) {
+    Symbol *Sym = insert(Body);
+    assert(isa<DefinedBitcode>(Sym->Body));
+    Sym->Body = Body;
+  }
+}
+
 // Add an undefined symbol.
 template <class ELFT>
 SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {

Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Fri Feb 12 14:54:57 2016
@@ -13,6 +13,10 @@
 #include "InputFiles.h"
 #include "llvm/ADT/MapVector.h"
 
+namespace llvm {
+class Module;
+}
+
 namespace lld {
 namespace elf2 {
 class Lazy;
@@ -36,6 +40,7 @@ template <class ELFT> class SymbolTable
 
 public:
   void addFile(std::unique_ptr<InputFile> File);
+  void addCombinedLtoObject();
 
   const llvm::MapVector<StringRef, Symbol *> &getSymbols() const {
     return Symtab;
@@ -66,8 +71,13 @@ private:
   void addLazy(Lazy *New);
   void addMemberFile(Undefined *Undef, Lazy *L);
   void resolve(SymbolBody *Body);
+  std::unique_ptr<InputFile> codegen(llvm::Module &M);
   std::string conflictMsg(SymbolBody *Old, SymbolBody *New);
 
+  SmallString<0> OwningLTOData;
+  std::unique_ptr<MemoryBuffer> LtoBuffer;
+  ObjectFile<ELFT> *createCombinedLtoObject();
+
   // The order the global symbols are in is not defined. We can use an arbitrary
   // order, but it has to be reproducible. That is true even when cross linking.
   // The default hashing of StringRef produces different results on 32 and 64
@@ -87,6 +97,7 @@ private:
   std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
   std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
   std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
+  std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles;
 
   // Set of .so files to not link the same shared object file more than once.
   llvm::DenseSet<StringRef> SoNames;

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Fri Feb 12 14:54:57 2016
@@ -69,6 +69,8 @@ typename ELFFile<ELFT>::uintX_t SymbolBo
   case LazyKind:
     assert(isUsedInRegularObj() && "Lazy symbol reached writer");
     return 0;
+  case DefinedBitcodeKind:
+    llvm_unreachable("Should have been replaced");
   }
   llvm_unreachable("Invalid symbol kind");
 }
@@ -159,6 +161,13 @@ Defined::Defined(Kind K, StringRef Name,
                  bool IsTls, bool IsFunction)
     : SymbolBody(K, Name, IsWeak, Visibility, IsTls, IsFunction) {}
 
+DefinedBitcode::DefinedBitcode(StringRef Name)
+    : Defined(DefinedBitcodeKind, Name, false, STV_DEFAULT, false, false) {}
+
+bool DefinedBitcode::classof(const SymbolBody *S) {
+  return S->kind() == DefinedBitcodeKind;
+}
+
 Undefined::Undefined(SymbolBody::Kind K, StringRef N, bool IsWeak,
                      uint8_t Visibility, bool IsTls)
     : SymbolBody(K, N, IsWeak, Visibility, IsTls, /*IsFunction*/ false),

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Fri Feb 12 14:54:57 2016
@@ -65,6 +65,7 @@ public:
     SharedKind,
     DefinedElfLast = SharedKind,
     DefinedCommonKind,
+    DefinedBitcodeKind,
     DefinedSyntheticKind,
     DefinedLast = DefinedSyntheticKind,
     UndefinedElfKind,
@@ -187,6 +188,12 @@ public:
   }
 };
 
+class DefinedBitcode : public Defined {
+public:
+  DefinedBitcode(StringRef Name);
+  static bool classof(const SymbolBody *S);
+};
+
 class DefinedCommon : public Defined {
 public:
   DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, bool IsWeak,

Modified: lld/trunk/test/ELF/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lit.local.cfg?rev=260726&r1=260725&r2=260726&view=diff
==============================================================================
--- lld/trunk/test/ELF/lit.local.cfg (original)
+++ lld/trunk/test/ELF/lit.local.cfg Fri Feb 12 14:54:57 2016
@@ -1,2 +1,2 @@
-config.suffixes = ['.test', '.s']
+config.suffixes = ['.test', '.s', '.ll']
 

Added: lld/trunk/test/ELF/lto/lto-start.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/lto-start.ll?rev=260726&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/lto-start.ll (added)
+++ lld/trunk/test/ELF/lto/lto-start.ll Fri Feb 12 14:54:57 2016
@@ -0,0 +1,23 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld -m elf_x86_64 %t.o -o %t2
+; RUN: llvm-readobj -t %t2 | FileCheck %s
+
+; CHECK:      Format: ELF64-x86-64
+; CHECK-NEXT: Arch: x86_64
+; CHECK-NEXT: AddressSize: 64bit
+
+; CHECK:      Name: _start
+; CHECK-NEXT: Value:
+; CHECK-NEXT: Size: 1
+; CHECK-NEXT: Binding: Global
+; CHECK-NEXT: Type: Function
+; CHECK-NEXT: Other:
+; CHECK-NEXT: Section: .text
+
+target triple = "x86_64-unknown-linux-gnu"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @_start() {
+  ret void
+}




More information about the llvm-commits mailing list