Index: ELF/CMakeLists.txt =================================================================== --- ELF/CMakeLists.txt +++ ELF/CMakeLists.txt @@ -9,6 +9,7 @@ ICF.cpp InputFiles.cpp InputSection.cpp + LTO.cpp LinkerScript.cpp MarkLive.cpp OutputSections.cpp Index: ELF/LTO.h =================================================================== --- /dev/null +++ ELF/LTO.h @@ -0,0 +1,51 @@ +//===- LTO.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a way to combine bitcode files into one ELF +// file by compiling them using LLVM. +// +// If LTO is in use, your input files are not in regular ELF files +// but instead LLVM bitcode files. In that case, the linker has to +// convert bitcode files into the native format so that we can create +// an ELF file that contains native code. This file provides that +// functionality. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_LTO_H +#define LLD_ELF_LTO_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Linker/IRMover.h" + +namespace lld { +namespace elf { + +class BitcodeFile; +template class ObjectFile; + +class BitcodeCompiler { +public: + void add(BitcodeFile &F); + template std::unique_ptr> compile(); + +private: + llvm::LLVMContext Context; + llvm::Module Combined{"ld-temp.o", Context}; + llvm::IRMover Mover{Combined}; + SmallString<0> OwningData; + std::unique_ptr MB; +}; +} +} + +#endif Index: ELF/LTO.cpp =================================================================== --- /dev/null +++ ELF/LTO.cpp @@ -0,0 +1,144 @@ +//===- LTO.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LTO.h" +#include "Config.h" +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Linker/IRMover.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; + +using namespace lld; +using namespace lld::elf; + +// This is for use when debugging LTO. +static void saveLtoObjectFile(StringRef Buffer) { + std::error_code EC; + raw_fd_ostream OS(Config->OutputFile.str() + ".lto.o", EC, + sys::fs::OpenFlags::F_None); + check(EC); + OS << Buffer; +} + +// This is for use when debugging LTO. +static void saveBCFile(Module &M, StringRef Suffix) { + std::error_code EC; + raw_fd_ostream OS(Config->OutputFile.str() + Suffix.str(), EC, + sys::fs::OpenFlags::F_None); + check(EC); + WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true); +} + +static void runLTOPasses(Module &M, TargetMachine &TM) { + // Run LTO passes. + // FIXME: Reduce code duplication by sharing this code with the gold plugin. + legacy::PassManager LtoPasses; + LtoPasses.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis())); + PassManagerBuilder PMB; + PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple())); + PMB.Inliner = createFunctionInliningPass(); + PMB.VerifyInput = true; + PMB.VerifyOutput = true; + PMB.LoopVectorize = true; + PMB.SLPVectorize = true; + PMB.OptLevel = 2; // FIXME: This should be an option. + PMB.populateLTOPassManager(LtoPasses); + LtoPasses.run(M); + + if (Config->SaveTemps) + saveBCFile(M, ".lto.opt.bc"); +} + +void BitcodeCompiler::add(BitcodeFile &F) { + std::unique_ptr Obj = + check(IRObjectFile::create(F.MB, Context)); + std::vector Keep; + unsigned BodyIndex = 0; + ArrayRef Bodies = F.getSymbols(); + + for (const BasicSymbolRef &Sym : Obj->symbols()) { + GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); + assert(GV); + if (GV->hasAppendingLinkage()) { + Keep.push_back(GV); + continue; + } + if (BitcodeFile::shouldSkip(Sym)) + continue; + SymbolBody *B = Bodies[BodyIndex++]; + if (!B || &B->repl() != B) + continue; + auto *DB = dyn_cast(B); + if (!DB) + continue; + Keep.push_back(GV); + } + + Mover.move(Obj->takeModule(), Keep, + [](GlobalValue &, IRMover::ValueAdder) {}); +} + +// Merge all the bitcode files we have seen, codegen the result +// and return the resulting ObjectFile. +template +std::unique_ptr> BitcodeCompiler::compile() { + if (Config->SaveTemps) + saveBCFile(Combined, ".lto.bc"); + + StringRef TripleStr = Combined.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; + Reloc::Model R = Config->Pic ? Reloc::PIC_ : Reloc::Static; + std::unique_ptr TM( + TheTarget->createTargetMachine(TripleStr, "", "", Options, R)); + + runLTOPasses(Combined, *TM); + + raw_svector_ostream OS(OwningData); + legacy::PassManager CodeGenPasses; + if (TM->addPassesToEmitFile(CodeGenPasses, OS, + TargetMachine::CGFT_ObjectFile)) + fatal("failed to setup codegen"); + CodeGenPasses.run(Combined); + MB = MemoryBuffer::getMemBuffer(OwningData, "", false); + if (Config->SaveTemps) + saveLtoObjectFile(MB->getBuffer()); + + std::unique_ptr IF = createObjectFile(*MB); + auto *OF = cast>(IF.release()); + return std::unique_ptr>(OF); +} + +template std::unique_ptr> BitcodeCompiler::compile(); +template std::unique_ptr> BitcodeCompiler::compile(); +template std::unique_ptr> BitcodeCompiler::compile(); +template std::unique_ptr> BitcodeCompiler::compile(); Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -11,6 +11,7 @@ #define LLD_ELF_SYMBOL_TABLE_H #include "InputFiles.h" +#include "LTO.h" #include "llvm/ADT/MapVector.h" namespace llvm { @@ -74,8 +75,6 @@ std::unique_ptr codegen(llvm::Module &M); std::string conflictMsg(SymbolBody *Old, SymbolBody *New); - SmallString<0> OwningLTOData; - std::unique_ptr LtoBuffer; ObjectFile *createCombinedLtoObject(); // The order the global symbols are in is not defined. We can use an arbitrary @@ -101,6 +100,8 @@ // Set of .so files to not link the same shared object file more than once. llvm::DenseSet SoNames; + + std::unique_ptr Lto; }; } // namespace elf Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -18,16 +18,8 @@ #include "Config.h" #include "Error.h" #include "Symbols.h" -#include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/Linker/IRMover.h" #include "llvm/Support/StringSaver.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" using namespace llvm; using namespace llvm::object; @@ -101,130 +93,20 @@ resolve(B); } -// This is for use when debugging LTO. -static void saveLtoObjectFile(StringRef Buffer) { - std::error_code EC; - raw_fd_ostream OS(Config->OutputFile.str() + ".lto.o", EC, - sys::fs::OpenFlags::F_None); - check(EC); - OS << Buffer; -} - -// This is for use when debugging LTO. -static void saveBCFile(Module &M, StringRef Suffix) { - std::error_code EC; - raw_fd_ostream OS(Config->OutputFile.str() + Suffix.str(), EC, - sys::fs::OpenFlags::F_None); - check(EC); - WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true); -} - -static void runLTOPasses(Module &M, TargetMachine &TM) { - // Run LTO passes. - // FIXME: Reduce code duplication by sharing this code with the gold plugin. - legacy::PassManager LtoPasses; - LtoPasses.add( - createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis())); - PassManagerBuilder PMB; - PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple())); - PMB.Inliner = createFunctionInliningPass(); - PMB.VerifyInput = true; - PMB.VerifyOutput = true; - PMB.LoopVectorize = true; - PMB.SLPVectorize = true; - PMB.OptLevel = 2; // FIXME: This should be an option. - PMB.populateLTOPassManager(LtoPasses); - LtoPasses.run(M); - - if (Config->SaveTemps) - saveBCFile(M, ".lto.opt.bc"); -} - -// Codegen the module M and returns the resulting InputFile. -template -std::unique_ptr SymbolTable::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; - Reloc::Model R = Config->Pic ? Reloc::PIC_ : Reloc::Static; - std::unique_ptr TM( - TheTarget->createTargetMachine(TripleStr, "", "", Options, R)); - - runLTOPasses(M, *TM); - - 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); - if (Config->SaveTemps) - saveLtoObjectFile(LtoBuffer->getBuffer()); - return createObjectFile(*LtoBuffer); -} - -static void addBitcodeFile(IRMover &Mover, BitcodeFile &F, - LLVMContext &Context) { - - std::unique_ptr Obj = - check(IRObjectFile::create(F.MB, Context)); - std::vector Keep; - unsigned BodyIndex = 0; - ArrayRef Bodies = F.getSymbols(); - - for (const BasicSymbolRef &Sym : Obj->symbols()) { - GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); - assert(GV); - if (GV->hasAppendingLinkage()) { - Keep.push_back(GV); - continue; - } - if (BitcodeFile::shouldSkip(Sym)) - continue; - SymbolBody *B = Bodies[BodyIndex++]; - if (!B || &B->repl() != B) - continue; - auto *DB = dyn_cast(B); - if (!DB) - continue; - Keep.push_back(GV); - } - - Mover.move(Obj->takeModule(), Keep, - [](GlobalValue &, IRMover::ValueAdder) {}); -} - -// Merge all the bitcode files we have seen, codegen the result and return -// the resulting ObjectFile. -template -elf::ObjectFile *SymbolTable::createCombinedLtoObject() { - LLVMContext Context; - Module Combined("ld-temp.o", Context); - IRMover Mover(Combined); - for (const std::unique_ptr &F : BitcodeFiles) - addBitcodeFile(Mover, *F, Context); - if (Config->SaveTemps) - saveBCFile(Combined, ".lto.bc"); - std::unique_ptr F = codegen(Combined); - ObjectFiles.emplace_back(cast>(F.release())); - return &*ObjectFiles.back(); -} - +// Compile bitcode files to the native ELF format and replace bitcode +// symbols with regular ELF symbols, so that the link continues as if +// bitcode files were in the native format from the beginning. template void SymbolTable::addCombinedLtoObject() { if (BitcodeFiles.empty()) return; - ObjectFile *Obj = createCombinedLtoObject(); + + // Compile bitcode files. + Lto.reset(new BitcodeCompiler); + for (const std::unique_ptr &F : BitcodeFiles) + Lto->add(*F); + std::unique_ptr> Obj = Lto->compile(); + + // Replace bitcode symbols. llvm::DenseSet DummyGroups; Obj->parse(DummyGroups); for (SymbolBody *Body : Obj->getNonLocalSymbols()) { @@ -233,6 +115,7 @@ continue; Sym->Body = Body; } + ObjectFiles.push_back(std::move(Obj)); } // Add an undefined symbol.