[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