ELF: Create LTO.{cpp,h} and move LTO-related code to that file.
The code for LTO has been growing, so now is probably a good time to move it to its own file. SymbolTable.cpp is for symbol table, and because compiling bitcode files are semantically not a part of symbol table, this is I think a good thing to do. http://reviews.llvm.org/D18370 llvm-svn: 264091
This commit is contained in:
parent
3baa23b50c
commit
259924869b
|
@ -9,6 +9,7 @@ add_lld_library(lldELF
|
|||
ICF.cpp
|
||||
InputFiles.cpp
|
||||
InputSection.cpp
|
||||
LTO.cpp
|
||||
LinkerScript.cpp
|
||||
MarkLive.cpp
|
||||
OutputSections.cpp
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
//===- 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);
|
||||
}
|
||||
|
||||
// Run LTO passes.
|
||||
// FIXME: Reduce code duplication by sharing this code with the gold plugin.
|
||||
static void runLTOPasses(Module &M, TargetMachine &TM) {
|
||||
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<IRObjectFile> Obj =
|
||||
check(IRObjectFile::create(F.MB, Context));
|
||||
std::vector<GlobalValue *> Keep;
|
||||
unsigned BodyIndex = 0;
|
||||
ArrayRef<SymbolBody *> 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))
|
||||
if (SymbolBody *B = Bodies[BodyIndex++])
|
||||
if (&B->repl() == B && isa<DefinedBitcode>(B))
|
||||
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 <class ELFT>
|
||||
std::unique_ptr<elf::ObjectFile<ELFT>> 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<TargetMachine> 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,
|
||||
"LLD-INTERNAL-combined-lto-object", false);
|
||||
if (Config->SaveTemps)
|
||||
saveLtoObjectFile(MB->getBuffer());
|
||||
|
||||
std::unique_ptr<InputFile> IF = createObjectFile(*MB);
|
||||
auto *OF = cast<ObjectFile<ELFT>>(IF.release());
|
||||
return std::unique_ptr<ObjectFile<ELFT>>(OF);
|
||||
}
|
||||
|
||||
template std::unique_ptr<elf::ObjectFile<ELF32LE>> BitcodeCompiler::compile();
|
||||
template std::unique_ptr<elf::ObjectFile<ELF32BE>> BitcodeCompiler::compile();
|
||||
template std::unique_ptr<elf::ObjectFile<ELF64LE>> BitcodeCompiler::compile();
|
||||
template std::unique_ptr<elf::ObjectFile<ELF64BE>> BitcodeCompiler::compile();
|
|
@ -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 ELFT> class ObjectFile;
|
||||
|
||||
class BitcodeCompiler {
|
||||
public:
|
||||
void add(BitcodeFile &F);
|
||||
template <class ELFT> std::unique_ptr<ObjectFile<ELFT>> compile();
|
||||
|
||||
private:
|
||||
llvm::LLVMContext Context;
|
||||
llvm::Module Combined{"ld-temp.o", Context};
|
||||
llvm::IRMover Mover{Combined};
|
||||
SmallString<0> OwningData;
|
||||
std::unique_ptr<MemoryBuffer> MB;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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,131 +93,17 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
|
|||
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 <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;
|
||||
Reloc::Model R = Config->Pic ? Reloc::PIC_ : Reloc::Static;
|
||||
std::unique_ptr<TargetMachine> 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, "LLD-INTERNAL-combined-lto-object", false);
|
||||
if (Config->SaveTemps)
|
||||
saveLtoObjectFile(LtoBuffer->getBuffer());
|
||||
return createObjectFile(*LtoBuffer);
|
||||
}
|
||||
|
||||
static void addBitcodeFile(IRMover &Mover, BitcodeFile &F,
|
||||
LLVMContext &Context) {
|
||||
|
||||
std::unique_ptr<IRObjectFile> Obj =
|
||||
check(IRObjectFile::create(F.MB, Context));
|
||||
std::vector<GlobalValue *> Keep;
|
||||
unsigned BodyIndex = 0;
|
||||
ArrayRef<SymbolBody *> 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<DefinedBitcode>(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 <class ELFT>
|
||||
elf::ObjectFile<ELFT> *SymbolTable<ELFT>::createCombinedLtoObject() {
|
||||
LLVMContext Context;
|
||||
Module Combined("ld-temp.o", Context);
|
||||
IRMover Mover(Combined);
|
||||
for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles)
|
||||
addBitcodeFile(Mover, *F, Context);
|
||||
if (Config->SaveTemps)
|
||||
saveBCFile(Combined, ".lto.bc");
|
||||
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();
|
||||
|
||||
// Compile bitcode files.
|
||||
Lto.reset(new BitcodeCompiler);
|
||||
for (const std::unique_ptr<BitcodeFile> &F : BitcodeFiles)
|
||||
Lto->add(*F);
|
||||
std::unique_ptr<ObjectFile<ELFT>> Obj = Lto->compile<ELFT>();
|
||||
|
||||
// Replace bitcode symbols.
|
||||
llvm::DenseSet<StringRef> DummyGroups;
|
||||
Obj->parse(DummyGroups);
|
||||
for (SymbolBody *Body : Obj->getNonLocalSymbols()) {
|
||||
|
@ -234,6 +112,7 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLtoObject() {
|
|||
continue;
|
||||
Sym->Body = Body;
|
||||
}
|
||||
ObjectFiles.push_back(std::move(Obj));
|
||||
}
|
||||
|
||||
// Add an undefined symbol.
|
||||
|
|
|
@ -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 @@ private:
|
|||
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
|
||||
|
@ -101,6 +100,8 @@ private:
|
|||
|
||||
// Set of .so files to not link the same shared object file more than once.
|
||||
llvm::DenseSet<StringRef> SoNames;
|
||||
|
||||
std::unique_ptr<BitcodeCompiler> Lto;
|
||||
};
|
||||
|
||||
} // namespace elf
|
||||
|
|
Loading…
Reference in New Issue