mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-10-10 21:04:56 +00:00
[ELF/LTO] Switch to the new resolution-based API.
Differential Revision: https://reviews.llvm.org/D24492 llvm-svn: 282656
This commit is contained in:
parent
0aff59f32d
commit
786d8e33db
@ -12,6 +12,8 @@
|
||||
|
||||
#include "lld/Core/LLVM.h"
|
||||
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
@ -31,6 +33,13 @@ template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) {
|
||||
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
|
||||
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg, const Twine &Prefix);
|
||||
|
||||
inline void check(Error E) {
|
||||
handleAllErrors(std::move(E), [&](llvm::ErrorInfoBase &EIB) {
|
||||
error(EIB.message());
|
||||
return Error::success();
|
||||
});
|
||||
}
|
||||
|
||||
template <class T> T check(ErrorOr<T> E) {
|
||||
if (auto EC = E.getError())
|
||||
fatal(EC.message());
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "llvm/CodeGen/Analysis.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/LTO/LTO.h"
|
||||
#include "llvm/MC/StringTableBuilder.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -397,13 +398,12 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
|
||||
case SHN_UNDEF:
|
||||
return elf::Symtab<ELFT>::X
|
||||
->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
|
||||
/*CanOmitFromDynSym*/ false, /*HasUnnamedAddr*/ false,
|
||||
this)
|
||||
/*CanOmitFromDynSym*/ false, this)
|
||||
->body();
|
||||
case SHN_COMMON:
|
||||
return elf::Symtab<ELFT>::X
|
||||
->addCommon(Name, Sym->st_size, Sym->st_value, Binding, Sym->st_other,
|
||||
Sym->getType(), /*HasUnnamedAddr*/ false, this)
|
||||
Sym->getType(), this)
|
||||
->body();
|
||||
}
|
||||
|
||||
@ -416,8 +416,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
|
||||
if (Sec == &InputSection<ELFT>::Discarded)
|
||||
return elf::Symtab<ELFT>::X
|
||||
->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
|
||||
/*CanOmitFromDynSym*/ false,
|
||||
/*HasUnnamedAddr*/ false, this)
|
||||
/*CanOmitFromDynSym*/ false, this)
|
||||
->body();
|
||||
return elf::Symtab<ELFT>::X->addRegular(Name, *Sym, Sec)->body();
|
||||
}
|
||||
@ -639,8 +638,8 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
|
||||
EMachine = getBitcodeMachineKind(MB);
|
||||
}
|
||||
|
||||
static uint8_t getGvVisibility(const GlobalValue *GV) {
|
||||
switch (GV->getVisibility()) {
|
||||
static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
|
||||
switch (GvVisibility) {
|
||||
case GlobalValue::DefaultVisibility:
|
||||
return STV_DEFAULT;
|
||||
case GlobalValue::HiddenVisibility:
|
||||
@ -652,84 +651,48 @@ static uint8_t getGvVisibility(const GlobalValue *GV) {
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
Symbol *BitcodeFile::createSymbol(const DenseSet<const Comdat *> &KeptComdats,
|
||||
const IRObjectFile &Obj,
|
||||
const BasicSymbolRef &Sym) {
|
||||
const GlobalValue *GV = Obj.getSymbolGV(Sym.getRawDataRefImpl());
|
||||
|
||||
SmallString<64> Name;
|
||||
raw_svector_ostream OS(Name);
|
||||
Sym.printName(OS);
|
||||
StringRef NameRef = Saver.save(StringRef(Name));
|
||||
|
||||
uint32_t Flags = Sym.getFlags();
|
||||
static Symbol *createBitcodeSymbol(const DenseSet<const Comdat *> &KeptComdats,
|
||||
const lto::InputFile::Symbol &ObjSym,
|
||||
StringSaver &Saver, BitcodeFile *F) {
|
||||
StringRef NameRef = Saver.save(ObjSym.getName());
|
||||
uint32_t Flags = ObjSym.getFlags();
|
||||
uint32_t Binding = (Flags & BasicSymbolRef::SF_Weak) ? STB_WEAK : STB_GLOBAL;
|
||||
|
||||
uint8_t Type = STT_NOTYPE;
|
||||
uint8_t Visibility;
|
||||
bool CanOmitFromDynSym = false;
|
||||
bool HasUnnamedAddr = false;
|
||||
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
|
||||
uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
|
||||
bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
|
||||
|
||||
// FIXME: Expose a thread-local flag for module asm symbols.
|
||||
if (GV) {
|
||||
if (GV->isThreadLocal())
|
||||
Type = STT_TLS;
|
||||
CanOmitFromDynSym = canBeOmittedFromSymbolTable(GV);
|
||||
Visibility = getGvVisibility(GV);
|
||||
HasUnnamedAddr =
|
||||
GV->getUnnamedAddr() == llvm::GlobalValue::UnnamedAddr::Global;
|
||||
} else {
|
||||
// FIXME: Set SF_Hidden flag correctly for module asm symbols, and expose
|
||||
// protected visibility.
|
||||
Visibility = STV_DEFAULT;
|
||||
}
|
||||
if (const Comdat *C = check(ObjSym.getComdat()))
|
||||
if (!KeptComdats.count(C))
|
||||
return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
|
||||
CanOmitFromDynSym, F);
|
||||
|
||||
if (GV)
|
||||
if (const Comdat *C = GV->getComdat())
|
||||
if (!KeptComdats.count(C))
|
||||
return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
|
||||
CanOmitFromDynSym, HasUnnamedAddr,
|
||||
this);
|
||||
|
||||
const Module &M = Obj.getModule();
|
||||
if (Flags & BasicSymbolRef::SF_Undefined)
|
||||
return Symtab<ELFT>::X->addUndefined(NameRef, Binding, Visibility, Type,
|
||||
CanOmitFromDynSym, HasUnnamedAddr,
|
||||
this);
|
||||
if (Flags & BasicSymbolRef::SF_Common) {
|
||||
// FIXME: Set SF_Common flag correctly for module asm symbols, and expose
|
||||
// size and alignment.
|
||||
assert(GV);
|
||||
const DataLayout &DL = M.getDataLayout();
|
||||
uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
|
||||
return Symtab<ELFT>::X->addCommon(NameRef, Size, GV->getAlignment(),
|
||||
Binding, Visibility, STT_OBJECT,
|
||||
HasUnnamedAddr, this);
|
||||
}
|
||||
return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type,
|
||||
CanOmitFromDynSym, HasUnnamedAddr, this);
|
||||
}
|
||||
CanOmitFromDynSym, F);
|
||||
|
||||
bool BitcodeFile::shouldSkip(uint32_t Flags) {
|
||||
return !(Flags & BasicSymbolRef::SF_Global) ||
|
||||
(Flags & BasicSymbolRef::SF_FormatSpecific);
|
||||
if (Flags & BasicSymbolRef::SF_Common)
|
||||
return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
|
||||
ObjSym.getCommonAlignment(), Binding,
|
||||
Visibility, STT_OBJECT, F);
|
||||
|
||||
return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type,
|
||||
CanOmitFromDynSym, F);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void BitcodeFile::parse(DenseSet<StringRef> &ComdatGroups) {
|
||||
Obj = check(IRObjectFile::create(MB, Driver->Context));
|
||||
const Module &M = Obj->getModule();
|
||||
|
||||
Obj = check(lto::InputFile::create(MB));
|
||||
DenseSet<const Comdat *> KeptComdats;
|
||||
for (const auto &P : M.getComdatSymbolTable()) {
|
||||
for (const auto &P : Obj->getComdatSymbolTable()) {
|
||||
StringRef N = Saver.save(P.first());
|
||||
if (ComdatGroups.insert(N).second)
|
||||
KeptComdats.insert(&P.second);
|
||||
}
|
||||
|
||||
for (const BasicSymbolRef &Sym : Obj->symbols())
|
||||
if (!shouldSkip(Sym.getFlags()))
|
||||
Symbols.push_back(createSymbol<ELFT>(KeptComdats, *Obj, Sym));
|
||||
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
|
||||
Symbols.push_back(
|
||||
createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, Saver, this));
|
||||
}
|
||||
|
||||
template <template <class> class T>
|
||||
@ -852,20 +815,12 @@ template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
|
||||
}
|
||||
|
||||
std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
|
||||
LLVMContext Context;
|
||||
std::unique_ptr<IRObjectFile> Obj =
|
||||
check(IRObjectFile::create(this->MB, Context));
|
||||
std::vector<StringRef> V;
|
||||
for (const BasicSymbolRef &Sym : Obj->symbols()) {
|
||||
uint32_t Flags = Sym.getFlags();
|
||||
if (BitcodeFile::shouldSkip(Flags))
|
||||
std::unique_ptr<lto::InputFile> Obj = check(lto::InputFile::create(this->MB));
|
||||
for (auto &ObjSym : Obj->symbols()) {
|
||||
if (ObjSym.getFlags() & BasicSymbolRef::SF_Undefined)
|
||||
continue;
|
||||
if (Flags & BasicSymbolRef::SF_Undefined)
|
||||
continue;
|
||||
SmallString<64> Name;
|
||||
raw_svector_ostream OS(Name);
|
||||
Sym.printName(OS);
|
||||
V.push_back(Saver.save(StringRef(Name)));
|
||||
V.push_back(Saver.save(ObjSym.getName()));
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
@ -27,6 +27,12 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
namespace lto {
|
||||
class InputFile;
|
||||
}
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
@ -247,17 +253,12 @@ public:
|
||||
template <class ELFT>
|
||||
void parse(llvm::DenseSet<StringRef> &ComdatGroups);
|
||||
ArrayRef<Symbol *> getSymbols() { return Symbols; }
|
||||
static bool shouldSkip(uint32_t Flags);
|
||||
std::unique_ptr<llvm::object::IRObjectFile> Obj;
|
||||
std::unique_ptr<llvm::lto::InputFile> Obj;
|
||||
|
||||
private:
|
||||
std::vector<Symbol *> Symbols;
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
llvm::StringSaver Saver{Alloc};
|
||||
template <class ELFT>
|
||||
Symbol *createSymbol(const llvm::DenseSet<const llvm::Comdat *> &KeptComdats,
|
||||
const llvm::object::IRObjectFile &Obj,
|
||||
const llvm::object::BasicSymbolRef &Sym);
|
||||
};
|
||||
|
||||
// .so file.
|
||||
|
322
lld/ELF/LTO.cpp
322
lld/ELF/LTO.cpp
@ -22,9 +22,11 @@
|
||||
#include "llvm/CodeGen/CommandFlags.h"
|
||||
#include "llvm/CodeGen/ParallelCG.h"
|
||||
#include "llvm/IR/AutoUpgrade.h"
|
||||
#include "llvm/IR/DiagnosticPrinter.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/LTO/LTO.h"
|
||||
#include "llvm/LTO/legacy/UpdateCompilerUsed.h"
|
||||
#include "llvm/Linker/IRMover.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
@ -51,283 +53,109 @@ static void saveBuffer(StringRef Buffer, const Twine &Path) {
|
||||
OS << Buffer;
|
||||
}
|
||||
|
||||
// This is for use when debugging LTO.
|
||||
static void saveBCFile(Module &M, const Twine &Path) {
|
||||
std::error_code EC;
|
||||
raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
|
||||
if (EC)
|
||||
error(EC, "cannot create " + Path);
|
||||
WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true);
|
||||
static void diagnosticHandler(const DiagnosticInfo &DI) {
|
||||
SmallString<128> ErrStorage;
|
||||
raw_svector_ostream OS(ErrStorage);
|
||||
DiagnosticPrinterRawOStream DP(OS);
|
||||
DI.print(DP);
|
||||
warning(ErrStorage);
|
||||
}
|
||||
|
||||
static void runNewCustomLtoPasses(Module &M, TargetMachine &TM) {
|
||||
PassBuilder PB(&TM);
|
||||
static std::unique_ptr<lto::LTO> createLTO() {
|
||||
lto::Config Conf;
|
||||
lto::ThinBackend Backend;
|
||||
|
||||
AAManager AA;
|
||||
// LLD supports the new relocations.
|
||||
Conf.Options = InitTargetOptionsFromCodeGenFlags();
|
||||
Conf.Options.RelaxELFRelocations = true;
|
||||
|
||||
// Parse a custom AA pipeline if asked to.
|
||||
if (!PB.parseAAPipeline(AA, Config->LtoAAPipeline)) {
|
||||
error("unable to parse AA pipeline description: " + Config->LtoAAPipeline);
|
||||
return;
|
||||
}
|
||||
Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
|
||||
Conf.DisableVerify = Config->DisableVerify;
|
||||
Conf.DiagHandler = diagnosticHandler;
|
||||
Conf.OptLevel = Config->LtoO;
|
||||
|
||||
LoopAnalysisManager LAM;
|
||||
FunctionAnalysisManager FAM;
|
||||
CGSCCAnalysisManager CGAM;
|
||||
ModuleAnalysisManager MAM;
|
||||
|
||||
// Register the AA manager first so that our version is the one used.
|
||||
FAM.registerPass([&] { return std::move(AA); });
|
||||
|
||||
// Register all the basic analyses with the managers.
|
||||
PB.registerModuleAnalyses(MAM);
|
||||
PB.registerCGSCCAnalyses(CGAM);
|
||||
PB.registerFunctionAnalyses(FAM);
|
||||
PB.registerLoopAnalyses(LAM);
|
||||
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
|
||||
|
||||
ModulePassManager MPM;
|
||||
if (!Config->DisableVerify)
|
||||
MPM.addPass(VerifierPass());
|
||||
|
||||
// Now, add all the passes we've been requested to.
|
||||
if (!PB.parsePassPipeline(MPM, Config->LtoNewPmPasses)) {
|
||||
error("unable to parse pass pipeline description: " +
|
||||
Config->LtoNewPmPasses);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Config->DisableVerify)
|
||||
MPM.addPass(VerifierPass());
|
||||
MPM.run(M, MAM);
|
||||
}
|
||||
|
||||
static void runOldLtoPasses(Module &M, TargetMachine &TM) {
|
||||
// Note that the gold plugin has a similar piece of code, so
|
||||
// it is probably better to move this code to a common place.
|
||||
legacy::PassManager LtoPasses;
|
||||
LtoPasses.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
|
||||
PassManagerBuilder PMB;
|
||||
PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple()));
|
||||
PMB.Inliner = createFunctionInliningPass();
|
||||
PMB.VerifyInput = PMB.VerifyOutput = !Config->DisableVerify;
|
||||
PMB.LoopVectorize = true;
|
||||
PMB.SLPVectorize = true;
|
||||
PMB.OptLevel = Config->LtoO;
|
||||
PMB.populateLTOPassManager(LtoPasses);
|
||||
LtoPasses.run(M);
|
||||
}
|
||||
|
||||
static void runLTOPasses(Module &M, TargetMachine &TM) {
|
||||
if (!Config->LtoNewPmPasses.empty()) {
|
||||
// The user explicitly asked for a set of passes to be run.
|
||||
// This needs the new PM to work as there's no clean way to
|
||||
// pass a set of passes to run in the legacy PM.
|
||||
runNewCustomLtoPasses(M, TM);
|
||||
if (HasError)
|
||||
return;
|
||||
} else {
|
||||
// Run the 'default' set of LTO passes. This code still uses
|
||||
// the legacy PM as the new one is not the default.
|
||||
runOldLtoPasses(M, TM);
|
||||
}
|
||||
// Set up a custom pipeline if we've been asked to.
|
||||
Conf.OptPipeline = Config->LtoNewPmPasses;
|
||||
Conf.AAPipeline = Config->LtoAAPipeline;
|
||||
|
||||
if (Config->SaveTemps)
|
||||
saveBCFile(M, Config->OutputFile + ".lto.opt.bc");
|
||||
check(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
|
||||
/*UseInputModulePath*/ true));
|
||||
|
||||
return make_unique<lto::LTO>(std::move(Conf), Backend, Config->LtoJobs);
|
||||
}
|
||||
|
||||
static bool shouldInternalize(const SmallPtrSet<GlobalValue *, 8> &Used,
|
||||
Symbol *S, GlobalValue *GV) {
|
||||
if (S->IsUsedInRegularObj || Used.count(GV))
|
||||
return false;
|
||||
return !S->includeInDynsym();
|
||||
}
|
||||
BitcodeCompiler::BitcodeCompiler() : LtoObj(createLTO()) {}
|
||||
|
||||
BitcodeCompiler::BitcodeCompiler()
|
||||
: Combined(new Module("ld-temp.o", Driver->Context)) {}
|
||||
BitcodeCompiler::~BitcodeCompiler() {}
|
||||
|
||||
static void undefine(Symbol *S) {
|
||||
replaceBody<Undefined>(S, S->body()->getName(), STV_DEFAULT, S->body()->Type,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
static void handleUndefinedAsmRefs(const BasicSymbolRef &Sym, GlobalValue *GV,
|
||||
StringSet<> &AsmUndefinedRefs) {
|
||||
// GV associated => not an assembly symbol, bail out.
|
||||
if (GV)
|
||||
return;
|
||||
|
||||
// This is an undefined reference to a symbol in asm. We put that in
|
||||
// compiler.used, so that we can preserve it from being dropped from
|
||||
// the output, without necessarily preventing its internalization.
|
||||
SmallString<64> Name;
|
||||
raw_svector_ostream OS(Name);
|
||||
Sym.printName(OS);
|
||||
AsmUndefinedRefs.insert(Name.str());
|
||||
}
|
||||
|
||||
void BitcodeCompiler::add(BitcodeFile &F) {
|
||||
std::unique_ptr<IRObjectFile> Obj = std::move(F.Obj);
|
||||
std::vector<GlobalValue *> Keep;
|
||||
unsigned BodyIndex = 0;
|
||||
ArrayRef<Symbol *> Syms = F.getSymbols();
|
||||
|
||||
Module &M = Obj->getModule();
|
||||
if (M.getDataLayoutStr().empty())
|
||||
lto::InputFile &Obj = *F.Obj;
|
||||
if (Obj.getDataLayoutStr().empty())
|
||||
fatal("invalid bitcode file: " + F.getName() + " has no datalayout");
|
||||
|
||||
// Discard non-compatible debug infos if necessary.
|
||||
M.materializeMetadata();
|
||||
UpgradeDebugInfo(M);
|
||||
unsigned SymNum = 0;
|
||||
std::vector<Symbol *> Syms = F.getSymbols();
|
||||
std::vector<lto::SymbolResolution> Resols(Syms.size());
|
||||
|
||||
// If a symbol appears in @llvm.used, the linker is required
|
||||
// to treat the symbol as there is a reference to the symbol
|
||||
// that it cannot see. Therefore, we can't internalize.
|
||||
SmallPtrSet<GlobalValue *, 8> Used;
|
||||
collectUsedGlobalVariables(M, Used, /* CompilerUsed */ false);
|
||||
// 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();
|
||||
|
||||
for (const BasicSymbolRef &Sym : Obj->symbols()) {
|
||||
uint32_t Flags = Sym.getFlags();
|
||||
GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());
|
||||
if (GV && GV->hasAppendingLinkage())
|
||||
Keep.push_back(GV);
|
||||
if (BitcodeFile::shouldSkip(Flags))
|
||||
continue;
|
||||
Symbol *S = Syms[BodyIndex++];
|
||||
if (GV)
|
||||
GV->setUnnamedAddr(S->HasUnnamedAddr ? GlobalValue::UnnamedAddr::Global
|
||||
: GlobalValue::UnnamedAddr::None);
|
||||
if (Flags & BasicSymbolRef::SF_Undefined) {
|
||||
handleUndefinedAsmRefs(Sym, GV, AsmUndefinedRefs);
|
||||
continue;
|
||||
}
|
||||
SymbolBody *B = S->body();
|
||||
if (B->File != &F)
|
||||
continue;
|
||||
// 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;
|
||||
|
||||
// We collect the set of symbols we want to internalize here
|
||||
// and change the linkage after the IRMover executed, i.e. after
|
||||
// we imported the symbols and satisfied undefined references
|
||||
// to it. We can't just change linkage here because otherwise
|
||||
// the IRMover will just rename the symbol.
|
||||
if (GV && shouldInternalize(Used, S, GV))
|
||||
InternalizedSyms.insert(GV->getName());
|
||||
|
||||
// At this point we know that either the combined LTO object will provide a
|
||||
// definition of a symbol, or we will internalize it. In either case, we
|
||||
// need to undefine the symbol. In the former case, the real definition
|
||||
// needs to be able to replace the original definition without conflicting.
|
||||
// In the latter case, we need to allow the combined LTO object to provide a
|
||||
// definition with the same name, for example when doing parallel codegen.
|
||||
if (auto *C = dyn_cast<DefinedCommon>(B)) {
|
||||
if (auto *GO = dyn_cast<GlobalObject>(GV))
|
||||
GO->setAlignment(C->Alignment);
|
||||
} else {
|
||||
undefine(S);
|
||||
}
|
||||
|
||||
if (!GV)
|
||||
// Module asm symbol.
|
||||
continue;
|
||||
|
||||
switch (GV->getLinkage()) {
|
||||
default:
|
||||
break;
|
||||
case GlobalValue::LinkOnceAnyLinkage:
|
||||
GV->setLinkage(GlobalValue::WeakAnyLinkage);
|
||||
break;
|
||||
case GlobalValue::LinkOnceODRLinkage:
|
||||
GV->setLinkage(GlobalValue::WeakODRLinkage);
|
||||
break;
|
||||
}
|
||||
|
||||
Keep.push_back(GV);
|
||||
R.VisibleToRegularObj =
|
||||
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
|
||||
if (R.Prevailing)
|
||||
undefine(Sym);
|
||||
}
|
||||
|
||||
IRMover Mover(*Combined);
|
||||
if (Error E = Mover.move(Obj->takeModule(), Keep,
|
||||
[](GlobalValue &, IRMover::ValueAdder) {})) {
|
||||
handleAllErrors(std::move(E), [&](const ErrorInfoBase &EIB) {
|
||||
fatal("failed to link module " + F.getName() + ": " + EIB.message());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void internalize(GlobalValue &GV) {
|
||||
assert(!GV.hasLocalLinkage() &&
|
||||
"Trying to internalize a symbol with local linkage!");
|
||||
GV.setLinkage(GlobalValue::InternalLinkage);
|
||||
}
|
||||
|
||||
std::vector<InputFile *> BitcodeCompiler::runSplitCodegen(
|
||||
const std::function<std::unique_ptr<TargetMachine>()> &TMFactory) {
|
||||
unsigned NumThreads = Config->LtoJobs;
|
||||
OwningData.resize(NumThreads);
|
||||
|
||||
std::list<raw_svector_ostream> OSs;
|
||||
std::vector<raw_pwrite_stream *> OSPtrs;
|
||||
for (SmallString<0> &Obj : OwningData) {
|
||||
OSs.emplace_back(Obj);
|
||||
OSPtrs.push_back(&OSs.back());
|
||||
}
|
||||
|
||||
splitCodeGen(std::move(Combined), OSPtrs, {}, TMFactory);
|
||||
|
||||
std::vector<InputFile *> ObjFiles;
|
||||
for (SmallString<0> &Obj : OwningData)
|
||||
ObjFiles.push_back(createObjectFile(
|
||||
MemoryBufferRef(Obj, "LLD-INTERNAL-combined-lto-object")));
|
||||
|
||||
// If -save-temps is given, we need to save temporary objects to files.
|
||||
// This is for debugging.
|
||||
if (Config->SaveTemps) {
|
||||
if (NumThreads == 1) {
|
||||
saveBuffer(OwningData[0], Config->OutputFile + ".lto.o");
|
||||
} else {
|
||||
for (unsigned I = 0; I < NumThreads; ++I)
|
||||
saveBuffer(OwningData[I], Config->OutputFile + Twine(I) + ".lto.o");
|
||||
}
|
||||
}
|
||||
|
||||
return ObjFiles;
|
||||
check(LtoObj->add(std::move(F.Obj), Resols));
|
||||
}
|
||||
|
||||
// Merge all the bitcode files we have seen, codegen the result
|
||||
// and return the resulting ObjectFile.
|
||||
// and return the resulting ObjectFile(s).
|
||||
std::vector<InputFile *> BitcodeCompiler::compile() {
|
||||
for (const auto &Name : InternalizedSyms) {
|
||||
GlobalValue *GV = Combined->getNamedValue(Name.first());
|
||||
assert(GV);
|
||||
internalize(*GV);
|
||||
}
|
||||
std::vector<InputFile *> Ret;
|
||||
unsigned MaxTasks = LtoObj->getMaxTasks();
|
||||
Buff.resize(MaxTasks);
|
||||
|
||||
std::string TheTriple = Combined->getTargetTriple();
|
||||
std::string Msg;
|
||||
const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg);
|
||||
if (!T)
|
||||
fatal("target not found: " + Msg);
|
||||
|
||||
// LLD supports the new relocations.
|
||||
TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
|
||||
Options.RelaxELFRelocations = true;
|
||||
|
||||
auto CreateTargetMachine = [&]() {
|
||||
return std::unique_ptr<TargetMachine>(T->createTargetMachine(
|
||||
TheTriple, "", "", Options, Config->Pic ? Reloc::PIC_ : Reloc::Static));
|
||||
auto AddStream =
|
||||
[&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
|
||||
return llvm::make_unique<lto::NativeObjectStream>(
|
||||
llvm::make_unique<llvm::raw_svector_ostream>(Buff[Task]));
|
||||
};
|
||||
|
||||
std::unique_ptr<TargetMachine> TM = CreateTargetMachine();
|
||||
|
||||
// Update llvm.compiler.used so that optimizations won't strip
|
||||
// off AsmUndefinedReferences.
|
||||
updateCompilerUsed(*Combined, *TM, AsmUndefinedRefs);
|
||||
|
||||
if (Config->SaveTemps)
|
||||
saveBCFile(*Combined, Config->OutputFile + ".lto.bc");
|
||||
|
||||
runLTOPasses(*Combined, *TM);
|
||||
check(LtoObj->run(AddStream));
|
||||
if (HasError)
|
||||
return {};
|
||||
return Ret;
|
||||
|
||||
return runSplitCodegen(CreateTargetMachine);
|
||||
for (unsigned I = 0; I != MaxTasks; ++I) {
|
||||
if (Buff[I].empty())
|
||||
continue;
|
||||
if (Config->SaveTemps) {
|
||||
if (MaxTasks == 1)
|
||||
saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
|
||||
else
|
||||
saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
|
||||
}
|
||||
MemoryBufferRef CompiledObjRef(Buff[I], "lto.tmp");
|
||||
InputFile *Obj = createObjectFile(CompiledObjRef);
|
||||
Ret.push_back(Obj);
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
@ -27,6 +27,12 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Linker/IRMover.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace lto {
|
||||
class LTO;
|
||||
}
|
||||
}
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
@ -36,17 +42,14 @@ class InputFile;
|
||||
class BitcodeCompiler {
|
||||
public:
|
||||
BitcodeCompiler();
|
||||
~BitcodeCompiler();
|
||||
void add(BitcodeFile &F);
|
||||
std::vector<InputFile *> compile();
|
||||
|
||||
private:
|
||||
std::vector<InputFile *> runSplitCodegen(
|
||||
const std::function<std::unique_ptr<llvm::TargetMachine>()> &TMFactory);
|
||||
std::unique_ptr<llvm::lto::LTO> LtoObj;
|
||||
|
||||
std::unique_ptr<llvm::Module> Combined;
|
||||
std::vector<SmallString<0>> OwningData;
|
||||
llvm::StringSet<> InternalizedSyms;
|
||||
llvm::StringSet<> AsmUndefinedRefs;
|
||||
private:
|
||||
std::vector<SmallString<0>> Buff;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +216,6 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef &Name) {
|
||||
Sym->Binding = STB_WEAK;
|
||||
Sym->Visibility = STV_DEFAULT;
|
||||
Sym->IsUsedInRegularObj = false;
|
||||
Sym->HasUnnamedAddr = true;
|
||||
Sym->ExportDynamic = false;
|
||||
Sym->Traced = V.Traced;
|
||||
std::tie(Name, Sym->VersionId) = getSymbolVersion(Name);
|
||||
@ -232,15 +231,12 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef &Name) {
|
||||
template <class ELFT>
|
||||
std::pair<Symbol *, bool>
|
||||
SymbolTable<ELFT>::insert(StringRef &Name, uint8_t Type, uint8_t Visibility,
|
||||
bool CanOmitFromDynSym, bool HasUnnamedAddr,
|
||||
InputFile *File) {
|
||||
bool CanOmitFromDynSym, InputFile *File) {
|
||||
bool IsUsedInRegularObj = !File || File->kind() == InputFile::ObjectKind;
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) = insert(Name);
|
||||
|
||||
// Merge in the new unnamed_addr attribute.
|
||||
S->HasUnnamedAddr &= HasUnnamedAddr;
|
||||
// Merge in the new symbol's visibility.
|
||||
S->Visibility = getMinVisibility(S->Visibility, Visibility);
|
||||
if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
|
||||
@ -269,19 +265,18 @@ std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Existing,
|
||||
|
||||
template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) {
|
||||
return addUndefined(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0,
|
||||
/*CanOmitFromDynSym*/ false, /*HasUnnamedAddr*/ false,
|
||||
/*File*/ nullptr);
|
||||
/*CanOmitFromDynSym*/ false, /*File*/ nullptr);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, uint8_t Binding,
|
||||
uint8_t StOther, uint8_t Type,
|
||||
bool CanOmitFromDynSym,
|
||||
bool HasUnnamedAddr, InputFile *File) {
|
||||
InputFile *File) {
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) =
|
||||
insert(Name, Type, StOther & 3, CanOmitFromDynSym, HasUnnamedAddr, File);
|
||||
insert(Name, Type, StOther & 3, CanOmitFromDynSym, File);
|
||||
if (WasInserted) {
|
||||
S->Binding = Binding;
|
||||
replaceBody<Undefined>(S, Name, StOther, Type, File);
|
||||
@ -343,11 +338,11 @@ template <class ELFT>
|
||||
Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
|
||||
uint64_t Alignment, uint8_t Binding,
|
||||
uint8_t StOther, uint8_t Type,
|
||||
bool HasUnnamedAddr, InputFile *File) {
|
||||
InputFile *File) {
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) = insert(
|
||||
N, Type, StOther & 3, /*CanOmitFromDynSym*/ false, HasUnnamedAddr, File);
|
||||
std::tie(S, WasInserted) =
|
||||
insert(N, Type, StOther & 3, /*CanOmitFromDynSym*/ false, File);
|
||||
int Cmp = compareDefined(S, WasInserted, Binding);
|
||||
if (Cmp > 0) {
|
||||
S->Binding = Binding;
|
||||
@ -386,10 +381,9 @@ Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, const Elf_Sym &Sym,
|
||||
InputSectionBase<ELFT> *Section) {
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) =
|
||||
insert(Name, Sym.getType(), Sym.getVisibility(),
|
||||
/*CanOmitFromDynSym*/ false, /*HasUnnamedAddr*/ false,
|
||||
Section ? Section->getFile() : nullptr);
|
||||
std::tie(S, WasInserted) = insert(Name, Sym.getType(), Sym.getVisibility(),
|
||||
/*CanOmitFromDynSym*/ false,
|
||||
Section ? Section->getFile() : nullptr);
|
||||
int Cmp = compareDefinedNonCommon(S, WasInserted, Sym.getBinding());
|
||||
if (Cmp > 0)
|
||||
replaceBody<DefinedRegular<ELFT>>(S, Name, Sym, Section);
|
||||
@ -403,9 +397,8 @@ Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t Binding,
|
||||
uint8_t StOther) {
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) =
|
||||
insert(Name, STT_NOTYPE, StOther & 3, /*CanOmitFromDynSym*/ false,
|
||||
/*HasUnnamedAddr*/ false, nullptr);
|
||||
std::tie(S, WasInserted) = insert(Name, STT_NOTYPE, StOther & 3,
|
||||
/*CanOmitFromDynSym*/ false, nullptr);
|
||||
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding);
|
||||
if (Cmp > 0)
|
||||
replaceBody<DefinedRegular<ELFT>>(S, Name, StOther);
|
||||
@ -421,8 +414,7 @@ Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) = insert(N, STT_NOTYPE, /*Visibility*/ StOther & 0x3,
|
||||
/*CanOmitFromDynSym*/ false,
|
||||
/*HasUnnamedAddr*/ false, nullptr);
|
||||
/*CanOmitFromDynSym*/ false, nullptr);
|
||||
int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL);
|
||||
if (Cmp > 0)
|
||||
replaceBody<DefinedSynthetic<ELFT>>(S, N, Value, Section);
|
||||
@ -441,8 +433,7 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) =
|
||||
insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true,
|
||||
/*HasUnnamedAddr*/ false, F);
|
||||
insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, F);
|
||||
// Make sure we preempt DSO symbols with default visibility.
|
||||
if (Sym.getVisibility() == STV_DEFAULT)
|
||||
S->ExportDynamic = true;
|
||||
@ -456,12 +447,11 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
|
||||
template <class ELFT>
|
||||
Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding,
|
||||
uint8_t StOther, uint8_t Type,
|
||||
bool CanOmitFromDynSym,
|
||||
bool HasUnnamedAddr, BitcodeFile *F) {
|
||||
bool CanOmitFromDynSym, BitcodeFile *F) {
|
||||
Symbol *S;
|
||||
bool WasInserted;
|
||||
std::tie(S, WasInserted) =
|
||||
insert(Name, Type, StOther & 3, CanOmitFromDynSym, HasUnnamedAddr, F);
|
||||
insert(Name, Type, StOther & 3, CanOmitFromDynSym, F);
|
||||
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding);
|
||||
if (Cmp > 0)
|
||||
replaceBody<DefinedRegular<ELFT>>(S, Name, StOther, Type, F);
|
||||
|
@ -60,8 +60,7 @@ public:
|
||||
|
||||
Symbol *addUndefined(StringRef Name);
|
||||
Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
|
||||
uint8_t Type, bool CanOmitFromDynSym,
|
||||
bool HasUnnamedAddr, InputFile *File);
|
||||
uint8_t Type, bool CanOmitFromDynSym, InputFile *File);
|
||||
|
||||
Symbol *addRegular(StringRef Name, const Elf_Sym &Sym,
|
||||
InputSectionBase<ELFT> *Section);
|
||||
@ -74,12 +73,11 @@ public:
|
||||
void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
|
||||
void addLazyObject(StringRef Name, LazyObjectFile &Obj);
|
||||
Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
|
||||
uint8_t Type, bool CanOmitFromDynSym, bool HasUnnamedAddr,
|
||||
BitcodeFile *File);
|
||||
uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
|
||||
|
||||
Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment,
|
||||
uint8_t Binding, uint8_t StOther, uint8_t Type,
|
||||
bool HasUnnamedAddr, InputFile *File);
|
||||
InputFile *File);
|
||||
|
||||
void scanUndefinedFlags();
|
||||
void scanShlibUndefined();
|
||||
@ -96,7 +94,7 @@ private:
|
||||
std::pair<Symbol *, bool> insert(StringRef &Name);
|
||||
std::pair<Symbol *, bool> insert(StringRef &Name, uint8_t Type,
|
||||
uint8_t Visibility, bool CanOmitFromDynSym,
|
||||
bool HasUnnamedAddr, InputFile *File);
|
||||
InputFile *File);
|
||||
|
||||
std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile);
|
||||
void reportDuplicate(SymbolBody *Existing, InputFile *NewFile);
|
||||
|
@ -410,9 +410,6 @@ struct Symbol {
|
||||
// observed non-DSO symbols.
|
||||
unsigned Visibility : 2;
|
||||
|
||||
// True if the symbol has unnamed_addr.
|
||||
unsigned HasUnnamedAddr : 1;
|
||||
|
||||
// True if the symbol was used for linking and thus need to be added to the
|
||||
// output file's symbol table. This is true for all symbols except for
|
||||
// unreferenced DSO symbols and bitcode symbols that are unreferenced except
|
||||
|
@ -3,12 +3,12 @@
|
||||
; RUN: llvm-as %s -o %t2.o
|
||||
|
||||
; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t3 -save-temps
|
||||
; RUN: llvm-dis %t3.lto.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s
|
||||
|
||||
; RUN: rm -f %t.a
|
||||
; RUN: llvm-ar rcs %t.a %t1.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.a %t1.o %t2.o -o %t3 -save-temps
|
||||
; RUN: llvm-dis %t3.lto.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s
|
||||
|
||||
; CHECK: define internal void @foo() {
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
; REQUIRES: x86
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t -save-temps
|
||||
; RUN: llvm-dis %t.lto.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.0.4.opt.bc -o - | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -1,7 +1,7 @@
|
||||
; RUN: llvm-as %s -o %t1.o
|
||||
; RUN: llvm-as %p/Inputs/available-externally.ll -o %t2.o
|
||||
; RUN: ld.lld %t1.o %t2.o -m elf_x86_64 -o %t.so -shared -save-temps
|
||||
; RUN: llvm-dis < %t.so.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -1,6 +1,6 @@
|
||||
; RUN: llvm-as %s -o %t1.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t1.o -o %t -shared -save-temps
|
||||
; RUN: llvm-dis < %t.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
|
||||
; RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SHARED
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -1,7 +1,7 @@
|
||||
; RUN: llvm-as %s -o %t1.o
|
||||
; RUN: llvm-as %S/Inputs/common3.ll -o %t2.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t -shared -save-temps
|
||||
; RUN: llvm-dis < %t.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -1,7 +1,7 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
|
||||
; RUN: ld.lld -m elf_x86_64 -shared -save-temps %t.o -o %t2.o
|
||||
; RUN: llvm-dis < %t2.o.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t2.o.0.0.preopt.bc | FileCheck %s
|
||||
|
||||
; CHECK: @GlobalValueName
|
||||
; CHECK: @foo(i32 %in)
|
||||
|
@ -5,5 +5,5 @@
|
||||
;
|
||||
; RUN: ld.lld -m elf_x86_64 -shared %p/Inputs/drop-debug-info.bc \
|
||||
; RUN: -disable-verify 2>&1 | FileCheck %s
|
||||
; CHECK: warning: ignoring debug info with an invalid version (1) in {{.*}}drop-debug-info.bc
|
||||
; CHECK: ignoring debug info with an invalid version (1) in {{.*}}drop-debug-info.bc
|
||||
|
||||
|
@ -5,7 +5,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
; RUN: llc %s -o %t.o -filetype=obj
|
||||
; RUN: llvm-as %p/Inputs/drop-linkage.ll -o %t2.o
|
||||
; RUN: ld.lld %t.o %t2.o -o %t.so -save-temps -shared
|
||||
; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
|
||||
|
||||
define void @foo() {
|
||||
ret void
|
||||
|
@ -1,7 +1,7 @@
|
||||
; REQUIRES: x86
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
|
||||
; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: llvm-as %p/Inputs/internalize-exportdyn.ll -o %t2.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t2 --export-dynamic -save-temps
|
||||
; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -1,7 +1,7 @@
|
||||
; REQUIRES: x86
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps
|
||||
; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: llvm-as %p/Inputs/internalize-undef.ll -o %t2.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps
|
||||
; RUN: llvm-dis < %t.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: echo "{ global: foo; local: *; };" > %t.script
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
|
||||
; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as -o %t2.bc %S/Inputs/irmover-error.ll
|
||||
; RUN: not ld.lld -m elf_x86_64 %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: failed to link module {{.*}}2.bc: linking module flags 'foo': IDs have conflicting values
|
||||
; CHECK: linking module flags 'foo': IDs have conflicting values
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as %p/Inputs/linkonce-odr.ll -o %t1.o
|
||||
; RUN: llc -relocation-model=pic %s -o %t2.o -filetype=obj
|
||||
; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
|
||||
; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as %p/Inputs/linkonce.ll -o %t1.o
|
||||
; RUN: llc -relocation-model=pic %s -o %t2.o -filetype=obj
|
||||
; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps
|
||||
; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -1,8 +1,7 @@
|
||||
; REQUIRES: x86
|
||||
; RUN: rm -f %t.so.lto.bc %t.so.lto.opt.bc %t.so.lto.o
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM
|
||||
; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -3,8 +3,8 @@
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps --lto-aa-pipeline=basic-aa \
|
||||
; RUN: --lto-newpm-passes=ipsccp -shared
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared
|
||||
; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t2.so.lto.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC
|
||||
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t2.so.0.4.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -5,9 +5,9 @@
|
||||
; RUN: llvm-as %p/Inputs/save-temps.ll -o %t2.o
|
||||
; RUN: ld.lld -shared -m elf_x86_64 %t.o %t2.o -save-temps
|
||||
; RUN: llvm-nm a.out | FileCheck %s
|
||||
; RUN: llvm-nm a.out.lto.bc | FileCheck %s
|
||||
; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s
|
||||
; RUN: llvm-nm a.out.lto.o | FileCheck %s
|
||||
; RUN: llvm-dis a.out.lto.bc
|
||||
; RUN: llvm-dis a.out.0.0.preopt.bc
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: llvm-as %p/Inputs/type-merge.ll -o %t2.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -shared -save-temps
|
||||
; RUN: llvm-dis < %t.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t.0.0.preopt.bc | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -1,7 +1,7 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: llvm-as %p/Inputs/type-merge2.ll -o %t2.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared -save-temps
|
||||
; RUN: llvm-dis %t.so.lto.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.0.preopt.bc -o - | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -1,6 +1,6 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -save-temps -shared
|
||||
; RUN: llvm-dis %t.so.lto.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -1,7 +1,7 @@
|
||||
; RUN: llvm-as %s -o %t1.o
|
||||
; RUN: llvm-as %S/Inputs/unnamed-addr-drop.ll -o %t2.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -save-temps -shared
|
||||
; RUN: llvm-dis %t.so.lto.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -3,7 +3,7 @@
|
||||
; RUN: llvm-mc %p/Inputs/unnamed-addr-lib.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux
|
||||
; RUN: ld.lld %t2.o -shared -o %t2.so
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o %t2.so -o %t.so -save-temps -shared
|
||||
; RUN: llvm-dis %t.so.lto.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s
|
||||
|
||||
; This documents a small limitation of lld's internalization logic. We decide
|
||||
; that bar should be in the symbol table because if it is it will preempt the
|
||||
@ -11,8 +11,8 @@
|
||||
; We could add one extra bit for ODR so that we know that preemption is not
|
||||
; necessary, but that is probably not worth it.
|
||||
|
||||
; CHECK: @foo = internal constant i8 42
|
||||
; CHECK: @bar = weak_odr constant i8 42
|
||||
; CHECK: @foo = internal unnamed_addr constant i8 42
|
||||
; CHECK: @bar = weak_odr unnamed_addr constant i8 42
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -1,6 +1,6 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -shared
|
||||
; RUN: llvm-dis %t.so.lto.opt.bc -o - | FileCheck %s
|
||||
; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as %s -o %t.o
|
||||
; RUN: echo "VERSION_1.0{ global: foo; local: *; }; VERSION_2.0{ global: bar; local: *; };" > %t.script
|
||||
; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps
|
||||
; RUN: llvm-dis < %t2.lto.bc | FileCheck %s
|
||||
; RUN: llvm-dis < %t2.0.0.preopt.bc | FileCheck %s
|
||||
; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
Loading…
Reference in New Issue
Block a user