diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2015-12-10 14:19:35 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2015-12-10 14:19:35 +0000 |
commit | da5132018f8f8648d88956ad18cc4dc10e0b5acb (patch) | |
tree | 1d2dd9bb9756bc7352da5d402ed67a183c454f82 /tools | |
parent | 079d48b39ea641d6f7dad6307de73ef51c7da1d8 (diff) |
Slit lib/Linker in two.
A linker normally has two stages: symbol resolution and "moving stuff".
In lib/Linker there is the complication of lazy linking some globals,
but it was still far more mixed than it needed to.
This splits the linker into a lower level IRMover and the linker proper.
The IRMover just takes a list of globals to move and a callback that
lets the user control what is lazy linked.
The main motivation is that now tools/gold (and soon lld) can use their
own symbol resolution to instruct IRMover what to do.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255254 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools')
-rw-r--r-- | tools/gold/gold-plugin.cpp | 254 |
1 files changed, 97 insertions, 157 deletions
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 9f8b0b20f61..d73e9492266 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -29,7 +29,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" -#include "llvm/Linker/Linker.h" +#include "llvm/Linker/IRMover.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/FunctionIndexObjectFile.h" #include "llvm/Object/IRObjectFile.h" @@ -62,6 +62,17 @@ struct claimed_file { void *handle; std::vector<ld_plugin_symbol> syms; }; + +struct ResolutionInfo { + bool IsLinkonceOdr = true; + bool UnnamedAddr = true; + GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; + bool CommonInternal = false; + bool UseCommon = false; + unsigned CommonSize = 0; + unsigned CommonAlign = 0; + claimed_file *CommonFile = nullptr; +}; } static ld_plugin_status discard_message(int level, const char *format, ...) { @@ -81,6 +92,7 @@ static ld_plugin_message message = discard_message; static Reloc::Model RelocationModel = Reloc::Default; static std::string output_name = ""; static std::list<claimed_file> Modules; +static StringMap<ResolutionInfo> ResInfo; static std::vector<std::string> Cleanup; static llvm::TargetOptions TargetOpts; @@ -332,6 +344,18 @@ static void diagnosticHandlerForContext(const DiagnosticInfo &DI, diagnosticHandler(DI); } +static GlobalValue::VisibilityTypes +getMinVisibility(GlobalValue::VisibilityTypes A, + GlobalValue::VisibilityTypes B) { + if (A == GlobalValue::HiddenVisibility) + return A; + if (B == GlobalValue::HiddenVisibility) + return B; + if (A == GlobalValue::ProtectedVisibility) + return A; + return B; +} + /// Called by gold to see whether this file is one that our plugin can handle. /// We'll try to open it and register all the symbols with add_symbol if /// possible. @@ -411,8 +435,22 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, const GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); + ResolutionInfo &Res = ResInfo[sym.name]; + sym.visibility = LDPV_DEFAULT; if (GV) { + Res.UnnamedAddr &= GV->hasUnnamedAddr(); + Res.IsLinkonceOdr &= GV->hasLinkOnceLinkage(); + if (GV->hasCommonLinkage()) { + Res.CommonAlign = std::max(Res.CommonAlign, GV->getAlignment()); + const DataLayout &DL = GV->getParent()->getDataLayout(); + uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); + if (Size >= Res.CommonSize) { + Res.CommonSize = Size; + Res.CommonFile = &cf; + } + } + Res.Visibility = getMinVisibility(Res.Visibility, GV->getVisibility()); switch (GV->getVisibility()) { case GlobalValue::DefaultVisibility: sym.visibility = LDPV_DEFAULT; @@ -466,27 +504,6 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, return LDPS_OK; } -static void keepGlobalValue(GlobalValue &GV, - std::vector<GlobalAlias *> &KeptAliases) { - assert(!GV.hasLocalLinkage()); - - if (auto *GA = dyn_cast<GlobalAlias>(&GV)) - KeptAliases.push_back(GA); - - switch (GV.getLinkage()) { - default: - break; - case GlobalValue::LinkOnceAnyLinkage: - GV.setLinkage(GlobalValue::WeakAnyLinkage); - break; - case GlobalValue::LinkOnceODRLinkage: - GV.setLinkage(GlobalValue::WeakODRLinkage); - break; - } - - assert(!GV.isDiscardableIfUnused()); -} - static void internalize(GlobalValue &GV) { if (GV.isDeclarationForLinker()) return; // We get here if there is a matching asm definition. @@ -494,33 +511,6 @@ static void internalize(GlobalValue &GV) { GV.setLinkage(GlobalValue::InternalLinkage); } -static void drop(GlobalValue &GV) { - if (auto *F = dyn_cast<Function>(&GV)) { - F->deleteBody(); - F->setComdat(nullptr); // Should deleteBody do this? - return; - } - - if (auto *Var = dyn_cast<GlobalVariable>(&GV)) { - Var->setInitializer(nullptr); - Var->setLinkage( - GlobalValue::ExternalLinkage); // Should setInitializer do this? - Var->setComdat(nullptr); // and this? - return; - } - - auto &Alias = cast<GlobalAlias>(GV); - Module &M = *Alias.getParent(); - PointerType &Ty = *cast<PointerType>(Alias.getType()); - GlobalValue::LinkageTypes L = Alias.getLinkage(); - auto *Var = - new GlobalVariable(M, Ty.getElementType(), /*isConstant*/ false, L, - /*Initializer*/ nullptr); - Var->takeName(&Alias); - Alias.replaceAllUsesWith(Var); - Alias.eraseFromParent(); -} - static const char *getResolutionName(ld_plugin_symbol_resolution R) { switch (R) { case LDPR_UNKNOWN: @@ -547,58 +537,6 @@ static const char *getResolutionName(ld_plugin_symbol_resolution R) { llvm_unreachable("Unknown resolution"); } -namespace { -class LocalValueMaterializer final : public ValueMaterializer { - DenseSet<GlobalValue *> &Dropped; - DenseMap<GlobalObject *, GlobalObject *> LocalVersions; - -public: - LocalValueMaterializer(DenseSet<GlobalValue *> &Dropped) : Dropped(Dropped) {} - Value *materializeDeclFor(Value *V) override; -}; -} - -Value *LocalValueMaterializer::materializeDeclFor(Value *V) { - auto *GO = dyn_cast<GlobalObject>(V); - if (!GO) - return nullptr; - - auto I = LocalVersions.find(GO); - if (I != LocalVersions.end()) - return I->second; - - if (!Dropped.count(GO)) - return nullptr; - - Module &M = *GO->getParent(); - GlobalValue::LinkageTypes L = GO->getLinkage(); - GlobalObject *Declaration; - if (auto *F = dyn_cast<Function>(GO)) { - Declaration = Function::Create(F->getFunctionType(), L, "", &M); - } else { - auto *Var = cast<GlobalVariable>(GO); - Declaration = new GlobalVariable(M, Var->getType()->getElementType(), - Var->isConstant(), L, - /*Initializer*/ nullptr); - } - Declaration->takeName(GO); - Declaration->copyAttributesFrom(GO); - - GO->setLinkage(GlobalValue::InternalLinkage); - GO->setName(Declaration->getName()); - Dropped.erase(GO); - GO->replaceAllUsesWith(Declaration); - - LocalVersions[Declaration] = GO; - - return GO; -} - -static Constant *mapConstantToLocalCopy(Constant *C, ValueToValueMapTy &VM, - LocalValueMaterializer *Materializer) { - return MapValue(C, VM, RF_IgnoreMissingEntries, nullptr, Materializer); -} - static void freeSymName(ld_plugin_symbol &Sym) { free(Sym.name); free(Sym.comdat_key); @@ -640,7 +578,8 @@ getFunctionIndexForFile(claimed_file &F, ld_plugin_input_file &Info) { static std::unique_ptr<Module> getModuleForFile(LLVMContext &Context, claimed_file &F, ld_plugin_input_file &Info, raw_fd_ostream *ApiFile, - StringSet<> &Internalize, StringSet<> &Maybe) { + StringSet<> &Internalize, StringSet<> &Maybe, + std::vector<GlobalValue *> &Keep) { if (get_symbols(F.handle, F.syms.size(), F.syms.data()) != LDPS_OK) message(LDPL_FATAL, "Failed to get symbol information"); @@ -668,11 +607,12 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, SmallPtrSet<GlobalValue *, 8> Used; collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); - DenseSet<GlobalValue *> Drop; - std::vector<GlobalAlias *> KeptAliases; - unsigned SymNum = 0; for (auto &ObjSym : Obj.symbols()) { + GlobalValue *GV = Obj.getSymbolGV(ObjSym.getRawDataRefImpl()); + if (GV && GV->hasAppendingLinkage()) + Keep.push_back(GV); + if (shouldSkip(ObjSym.getFlags())) continue; ld_plugin_symbol &Sym = F.syms[SymNum]; @@ -684,20 +624,37 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, if (options::generate_api_file) *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << '\n'; - GlobalValue *GV = Obj.getSymbolGV(ObjSym.getRawDataRefImpl()); if (!GV) { freeSymName(Sym); continue; // Asm symbol. } - if (Resolution != LDPR_PREVAILING_DEF_IRONLY && GV->hasCommonLinkage()) { - // Common linkage is special. There is no single symbol that wins the - // resolution. Instead we have to collect the maximum alignment and size. - // The IR linker does that for us if we just pass it every common GV. - // We still have to keep track of LDPR_PREVAILING_DEF_IRONLY so we - // internalize once the IR linker has done its job. - freeSymName(Sym); - continue; + ResolutionInfo &Res = ResInfo[Sym.name]; + if (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP && !Res.IsLinkonceOdr) + Resolution = LDPR_PREVAILING_DEF; + + GV->setUnnamedAddr(Res.UnnamedAddr); + GV->setVisibility(Res.Visibility); + + // Override gold's resolution for common symbols. We want the largest + // one to win. + if (GV->hasCommonLinkage()) { + cast<GlobalVariable>(GV)->setAlignment(Res.CommonAlign); + if (Resolution == LDPR_PREVAILING_DEF_IRONLY) + Res.CommonInternal = true; + + if (Resolution == LDPR_PREVAILING_DEF_IRONLY || + Resolution == LDPR_PREVAILING_DEF) + Res.UseCommon = true; + + if (Res.CommonFile == &F && Res.UseCommon) { + if (Res.CommonInternal) + Resolution = LDPR_PREVAILING_DEF_IRONLY; + else + Resolution = LDPR_PREVAILING_DEF; + } else { + Resolution = LDPR_PREEMPTED_IR; + } } switch (Resolution) { @@ -707,40 +664,37 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: - assert(GV->isDeclarationForLinker()); + case LDPR_PREEMPTED_IR: + case LDPR_PREEMPTED_REG: break; case LDPR_UNDEF: - if (!GV->isDeclarationForLinker()) { + if (!GV->isDeclarationForLinker()) assert(GV->hasComdat()); - Drop.insert(GV); - } break; case LDPR_PREVAILING_DEF_IRONLY: { - keepGlobalValue(*GV, KeptAliases); - if (!Used.count(GV)) { - // Since we use the regular lib/Linker, we cannot just internalize GV - // now or it will not be copied to the merged module. Instead we force - // it to be copied and then internalize it. + Keep.push_back(GV); + // The IR linker has to be able to map this value to a declaration, + // so we can only internalize after linking. + if (!Used.count(GV)) Internalize.insert(GV->getName()); - } break; } case LDPR_PREVAILING_DEF: - keepGlobalValue(*GV, KeptAliases); - break; - - case LDPR_PREEMPTED_IR: - // Gold might have selected a linkonce_odr and preempted a weak_odr. - // In that case we have to make sure we don't end up internalizing it. - if (!GV->isDiscardableIfUnused()) - Maybe.erase(GV->getName()); - - // fall-through - case LDPR_PREEMPTED_REG: - Drop.insert(GV); + Keep.push_back(GV); + // There is a non IR use, so we have to force optimizations to keep this. + switch (GV->getLinkage()) { + default: + break; + case GlobalValue::LinkOnceAnyLinkage: + GV->setLinkage(GlobalValue::WeakAnyLinkage); + break; + case GlobalValue::LinkOnceODRLinkage: + GV->setLinkage(GlobalValue::WeakODRLinkage); + break; + } break; case LDPR_PREVAILING_DEF_IRONLY_EXP: { @@ -748,9 +702,8 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, // reason is that this GV might have a copy in another module // and in that module the address might be significant, but that // copy will be LDPR_PREEMPTED_IR. - if (GV->hasLinkOnceODRLinkage()) - Maybe.insert(GV->getName()); - keepGlobalValue(*GV, KeptAliases); + Maybe.insert(GV->getName()); + Keep.push_back(GV); break; } } @@ -758,19 +711,6 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, freeSymName(Sym); } - ValueToValueMapTy VM; - LocalValueMaterializer Materializer(Drop); - for (GlobalAlias *GA : KeptAliases) { - // Gold told us to keep GA. It is possible that a GV usied in the aliasee - // expression is being dropped. If that is the case, that GV must be copied. - Constant *Aliasee = GA->getAliasee(); - Constant *Replacement = mapConstantToLocalCopy(Aliasee, VM, &Materializer); - GA->setAliasee(Replacement); - } - - for (auto *GV : Drop) - drop(*GV); - return Obj.takeModule(); } @@ -941,7 +881,7 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true); std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context)); - Linker L(*Combined, diagnosticHandler); + IRMover L(*Combined, diagnosticHandler); std::string DefaultTriple = sys::getDefaultTargetTriple(); @@ -951,15 +891,15 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { ld_plugin_input_file File; if (get_input_file(F.handle, &File) != LDPS_OK) message(LDPL_FATAL, "Failed to get file information"); + std::vector<GlobalValue *> Keep; std::unique_ptr<Module> M = - getModuleForFile(Context, F, File, ApiFile, Internalize, Maybe); + getModuleForFile(Context, F, File, ApiFile, Internalize, Maybe, Keep); if (!options::triple.empty()) M->setTargetTriple(options::triple.c_str()); - else if (M->getTargetTriple().empty()) { + else if (M->getTargetTriple().empty()) M->setTargetTriple(DefaultTriple); - } - if (L.linkInModule(*M)) + if (L.move(*M, Keep, [](GlobalValue &, IRMover::ValueAdder) {})) message(LDPL_FATAL, "Failed to link module"); if (release_input_file(F.handle) != LDPS_OK) message(LDPL_FATAL, "Failed to release file information"); |