mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 01:15:50 +08:00
Summary: llvm/CodeGen/CommandFlags.h a utility function InitTargetOptionsFromCodeGenFlags which is used to set target options from flags based on the command line. The command line flags are stored in globals defined in the same file, and including the file in multiple places causes the globals to be defined multiple times, leading to linker errors. This change adds a single place in lld where these globals are defined and exports only the utility function. This makes it possible to call InitTargetOptionsFromCodeGenFlags from multiple places in lld, which a follow-up change will do. Reviewers: davide, ruiu Reviewed By: davide, ruiu Subscribers: mgorny Differential Revision: https://reviews.llvm.org/D29058 llvm-svn: 293965
160 lines
4.9 KiB
C++
160 lines
4.9 KiB
C++
//===- 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 "lld/Core/TargetOptionsCommandFlags.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
|
#include "llvm/LTO/Config.h"
|
|
#include "llvm/LTO/LTO.h"
|
|
#include "llvm/Object/SymbolicFile.h"
|
|
#include "llvm/Support/CodeGen.h"
|
|
#include "llvm/Support/ELF.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <system_error>
|
|
#include <vector>
|
|
|
|
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 saveBuffer(StringRef Buffer, const Twine &Path) {
|
|
std::error_code EC;
|
|
raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
|
|
if (EC)
|
|
error("cannot create " + Path + ": " + EC.message());
|
|
OS << Buffer;
|
|
}
|
|
|
|
static void diagnosticHandler(const DiagnosticInfo &DI) {
|
|
SmallString<128> ErrStorage;
|
|
raw_svector_ostream OS(ErrStorage);
|
|
DiagnosticPrinterRawOStream DP(OS);
|
|
DI.print(DP);
|
|
warn(ErrStorage);
|
|
}
|
|
|
|
static void checkError(Error E) {
|
|
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
|
|
error(EIB.message());
|
|
return Error::success();
|
|
});
|
|
}
|
|
|
|
static std::unique_ptr<lto::LTO> createLTO() {
|
|
lto::Config Conf;
|
|
|
|
// LLD supports the new relocations.
|
|
Conf.Options = InitTargetOptionsFromCodeGenFlags();
|
|
Conf.Options.RelaxELFRelocations = true;
|
|
|
|
Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
|
|
Conf.DisableVerify = Config->DisableVerify;
|
|
Conf.DiagHandler = diagnosticHandler;
|
|
Conf.OptLevel = Config->LTOO;
|
|
|
|
// Set up a custom pipeline if we've been asked to.
|
|
Conf.OptPipeline = Config->LTONewPmPasses;
|
|
Conf.AAPipeline = Config->LTOAAPipeline;
|
|
|
|
if (Config->SaveTemps)
|
|
checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
|
|
/*UseInputModulePath*/ true));
|
|
|
|
lto::ThinBackend Backend;
|
|
if (Config->ThinLTOJobs != -1u)
|
|
Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
|
|
return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
|
|
Config->LTOPartitions);
|
|
}
|
|
|
|
BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
|
|
|
|
BitcodeCompiler::~BitcodeCompiler() = default;
|
|
|
|
static void undefine(Symbol *S) {
|
|
replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
|
|
STV_DEFAULT, S->body()->Type, nullptr);
|
|
}
|
|
|
|
void BitcodeCompiler::add(BitcodeFile &F) {
|
|
lto::InputFile &Obj = *F.Obj;
|
|
unsigned SymNum = 0;
|
|
std::vector<Symbol *> Syms = F.getSymbols();
|
|
std::vector<lto::SymbolResolution> Resols(Syms.size());
|
|
|
|
// Provide a resolution to the LTO API for each symbol.
|
|
for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
|
|
Symbol *Sym = Syms[SymNum];
|
|
lto::SymbolResolution &R = Resols[SymNum];
|
|
++SymNum;
|
|
SymbolBody *B = Sym->body();
|
|
|
|
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
|
|
// reports two symbols for module ASM defined. Without this check, lld
|
|
// flags an undefined in IR with a definition in ASM as prevailing.
|
|
// Once IRObjectFile is fixed to report only one symbol this hack can
|
|
// be removed.
|
|
R.Prevailing =
|
|
!(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) &&
|
|
B->File == &F;
|
|
|
|
R.VisibleToRegularObj =
|
|
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
|
|
if (R.Prevailing)
|
|
undefine(Sym);
|
|
}
|
|
checkError(LTOObj->add(std::move(F.Obj), Resols));
|
|
}
|
|
|
|
// 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;
|
|
unsigned MaxTasks = LTOObj->getMaxTasks();
|
|
Buff.resize(MaxTasks);
|
|
|
|
checkError(LTOObj->run([&](size_t Task) {
|
|
return llvm::make_unique<lto::NativeObjectStream>(
|
|
llvm::make_unique<raw_svector_ostream>(Buff[Task]));
|
|
}));
|
|
|
|
for (unsigned I = 0; I != MaxTasks; ++I) {
|
|
if (Buff[I].empty())
|
|
continue;
|
|
if (Config->SaveTemps) {
|
|
if (I == 0)
|
|
saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
|
|
else
|
|
saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
|
|
}
|
|
InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
|
|
Ret.push_back(Obj);
|
|
}
|
|
return Ret;
|
|
}
|