diff options
Diffstat (limited to 'tools/gold/gold-plugin.cpp')
-rw-r--r-- | tools/gold/gold-plugin.cpp | 275 |
1 files changed, 171 insertions, 104 deletions
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index cfda6d2..e3a57b5 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -15,23 +15,28 @@ #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/CommandFlags.h" +#include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/Linker/Linker.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/IRObjectFile.h" -#include "llvm/PassManager.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/GlobalStatus.h" @@ -78,9 +83,14 @@ static std::vector<std::string> Cleanup; static llvm::TargetOptions TargetOpts; namespace options { - enum generate_bc { BC_NO, BC_ONLY, BC_SAVE_TEMPS }; + enum OutputType { + OT_NORMAL, + OT_DISABLE, + OT_BC_ONLY, + OT_SAVE_TEMPS + }; static bool generate_api_file = false; - static generate_bc generate_bc_file = BC_NO; + static OutputType TheOutputType = OT_NORMAL; static std::string obj_path; static std::string extra_library_path; static std::string triple; @@ -109,9 +119,11 @@ namespace options { } else if (opt.startswith("obj-path=")) { obj_path = opt.substr(strlen("obj-path=")); } else if (opt == "emit-llvm") { - generate_bc_file = BC_ONLY; + TheOutputType = OT_BC_ONLY; } else if (opt == "save-temps") { - generate_bc_file = BC_SAVE_TEMPS; + TheOutputType = OT_SAVE_TEMPS; + } else if (opt == "disable-output") { + TheOutputType = OT_DISABLE; } else { // Save this option to pass to the code generator. // ParseCommandLineOptions() expects argv[0] to be program name. Lazily @@ -253,6 +265,44 @@ static const GlobalObject *getBaseObject(const GlobalValue &GV) { return cast<GlobalObject>(&GV); } +static bool shouldSkip(uint32_t Symflags) { + if (!(Symflags & object::BasicSymbolRef::SF_Global)) + return true; + if (Symflags & object::BasicSymbolRef::SF_FormatSpecific) + return true; + return false; +} + +static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) { + if (const auto *BDI = dyn_cast<BitcodeDiagnosticInfo>(&DI)) { + std::error_code EC = BDI->getError(); + if (EC == BitcodeError::InvalidBitcodeSignature) + return; + } + + std::string ErrStorage; + { + raw_string_ostream OS(ErrStorage); + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + } + ld_plugin_level Level; + switch (DI.getSeverity()) { + case DS_Error: + message(LDPL_FATAL, "LLVM gold plugin has failed to create LTO module: %s", + ErrStorage.c_str()); + llvm_unreachable("Fatal doesn't return."); + case DS_Warning: + Level = LDPL_WARNING; + break; + case DS_Remark: + case DS_Note: + Level = LDPL_INFO; + break; + } + message(Level, "LLVM gold plugin: %s", ErrStorage.c_str()); +} + /// 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. @@ -286,11 +336,11 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, BufferRef = Buffer->getMemBufferRef(); } + Context.setDiagnosticHandler(diagnosticHandler); ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr = - object::IRObjectFile::createIRObjectFile(BufferRef, Context); + object::IRObjectFile::create(BufferRef, Context); std::error_code EC = ObjOrErr.getError(); - if (EC == BitcodeError::InvalidBitcodeSignature || - EC == object::object_error::invalid_file_type || + if (EC == object::object_error::invalid_file_type || EC == object::object_error::bitcode_section_not_found) return LDPS_OK; @@ -310,10 +360,7 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, for (auto &Sym : Obj->symbols()) { uint32_t Symflags = Sym.getFlags(); - if (!(Symflags & object::BasicSymbolRef::SF_Global)) - continue; - - if (Symflags & object::BasicSymbolRef::SF_FormatSpecific) + if (shouldSkip(Symflags)) continue; cf.syms.push_back(ld_plugin_symbol()); @@ -467,51 +514,10 @@ static const char *getResolutionName(ld_plugin_symbol_resolution R) { llvm_unreachable("Unknown resolution"); } -static GlobalObject *makeInternalReplacement(GlobalObject *GO) { - Module *M = GO->getParent(); - GlobalObject *Ret; - if (auto *F = dyn_cast<Function>(GO)) { - if (F->materialize()) - message(LDPL_FATAL, "LLVM gold plugin has failed to read a function"); - - auto *NewF = Function::Create(F->getFunctionType(), F->getLinkage(), - F->getName(), M); - - ValueToValueMapTy VM; - Function::arg_iterator NewI = NewF->arg_begin(); - for (auto &Arg : F->args()) { - NewI->setName(Arg.getName()); - VM[&Arg] = NewI; - ++NewI; - } - - NewF->getBasicBlockList().splice(NewF->end(), F->getBasicBlockList()); - for (auto &BB : *NewF) { - for (auto &Inst : BB) - RemapInstruction(&Inst, VM, RF_IgnoreMissingEntries); - } - - Ret = NewF; - F->deleteBody(); - } else { - auto *Var = cast<GlobalVariable>(GO); - Ret = new GlobalVariable( - *M, Var->getType()->getElementType(), Var->isConstant(), - Var->getLinkage(), Var->getInitializer(), Var->getName(), - nullptr, Var->getThreadLocalMode(), Var->getType()->getAddressSpace(), - Var->isExternallyInitialized()); - Var->setInitializer(nullptr); - } - Ret->copyAttributesFrom(GO); - Ret->setLinkage(GlobalValue::InternalLinkage); - Ret->setComdat(GO->getComdat()); - - return Ret; -} - namespace { class LocalValueMaterializer : public ValueMaterializer { DenseSet<GlobalValue *> &Dropped; + DenseMap<GlobalObject *, GlobalObject *> LocalVersions; public: LocalValueMaterializer(DenseSet<GlobalValue *> &Dropped) : Dropped(Dropped) {} @@ -520,13 +526,39 @@ public: } Value *LocalValueMaterializer::materializeValueFor(Value *V) { - auto *GV = dyn_cast<GlobalValue>(V); - if (!GV) + auto *GO = dyn_cast<GlobalObject>(V); + if (!GO) return nullptr; - if (!Dropped.count(GV)) + + auto I = LocalVersions.find(GO); + if (I != LocalVersions.end()) + return I->second; + + if (!Dropped.count(GO)) return nullptr; - assert(!isa<GlobalAlias>(GV) && "Found alias point to weak alias."); - return makeInternalReplacement(cast<GlobalObject>(GV)); + + 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, @@ -534,12 +566,17 @@ static Constant *mapConstantToLocalCopy(Constant *C, ValueToValueMapTy &VM, return MapValue(C, VM, RF_IgnoreMissingEntries, nullptr, Materializer); } +static void freeSymName(ld_plugin_symbol &Sym) { + free(Sym.name); + free(Sym.comdat_key); + Sym.name = nullptr; + Sym.comdat_key = nullptr; +} + static std::unique_ptr<Module> -getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, +getModuleForFile(LLVMContext &Context, claimed_file &F, + ld_plugin_input_file &Info, raw_fd_ostream *ApiFile, StringSet<> &Internalize, StringSet<> &Maybe) { - ld_plugin_input_file File; - if (get_input_file(F.handle, &File) != LDPS_OK) - message(LDPL_FATAL, "Failed to get file information"); if (get_symbols(F.handle, F.syms.size(), &F.syms[0]) != LDPS_OK) message(LDPL_FATAL, "Failed to get symbol information"); @@ -548,42 +585,45 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, if (get_view(F.handle, &View) != LDPS_OK) message(LDPL_FATAL, "Failed to get a view of file"); - llvm::ErrorOr<MemoryBufferRef> MBOrErr = - object::IRObjectFile::findBitcodeInMemBuffer( - MemoryBufferRef(StringRef((const char *)View, File.filesize), "")); - if (std::error_code EC = MBOrErr.getError()) + MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize), + Info.name); + ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr = + object::IRObjectFile::create(BufferRef, Context); + + if (std::error_code EC = ObjOrErr.getError()) message(LDPL_FATAL, "Could not read bitcode from file : %s", EC.message().c_str()); - std::unique_ptr<MemoryBuffer> Buffer = - MemoryBuffer::getMemBuffer(MBOrErr->getBuffer(), "", false); - - if (release_input_file(F.handle) != LDPS_OK) - message(LDPL_FATAL, "Failed to release file information"); - - ErrorOr<Module *> MOrErr = getLazyBitcodeModule(std::move(Buffer), Context); + object::IRObjectFile &Obj = **ObjOrErr; - if (std::error_code EC = MOrErr.getError()) - message(LDPL_FATAL, "Could not read bitcode from file : %s", - EC.message().c_str()); + Module &M = Obj.getModule(); - std::unique_ptr<Module> M(MOrErr.get()); + UpgradeDebugInfo(M); SmallPtrSet<GlobalValue *, 8> Used; - collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false); + collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); DenseSet<GlobalValue *> Drop; std::vector<GlobalAlias *> KeptAliases; - for (ld_plugin_symbol &Sym : F.syms) { + + unsigned SymNum = 0; + for (auto &ObjSym : Obj.symbols()) { + if (shouldSkip(ObjSym.getFlags())) + continue; + ld_plugin_symbol &Sym = F.syms[SymNum]; + ++SymNum; + ld_plugin_symbol_resolution Resolution = (ld_plugin_symbol_resolution)Sym.resolution; if (options::generate_api_file) *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << '\n'; - GlobalValue *GV = M->getNamedValue(Sym.name); - if (!GV) + 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 @@ -591,6 +631,7 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // 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; } @@ -601,17 +642,23 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: - case LDPR_UNDEF: assert(GV->isDeclarationForLinker()); break; + case LDPR_UNDEF: + 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. - Internalize.insert(Sym.name); + Internalize.insert(GV->getName()); } break; } @@ -624,7 +671,7 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // 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(Sym.name); + Maybe.erase(GV->getName()); // fall-through case LDPR_PREEMPTED_REG: @@ -637,16 +684,13 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // and in that module the address might be significant, but that // copy will be LDPR_PREEMPTED_IR. if (GV->hasLinkOnceODRLinkage()) - Maybe.insert(Sym.name); + Maybe.insert(GV->getName()); keepGlobalValue(*GV, KeptAliases); break; } } - free(Sym.name); - free(Sym.comdat_key); - Sym.name = nullptr; - Sym.comdat_key = nullptr; + freeSymName(Sym); } ValueToValueMapTy VM; @@ -656,26 +700,31 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // expression is being dropped. If that is the case, that GV must be copied. Constant *Aliasee = GA->getAliasee(); Constant *Replacement = mapConstantToLocalCopy(Aliasee, VM, &Materializer); - if (Aliasee != Replacement) - GA->setAliasee(Replacement); + GA->setAliasee(Replacement); } for (auto *GV : Drop) drop(*GV); - return M; + return Obj.takeModule(); } static void runLTOPasses(Module &M, TargetMachine &TM) { - PassManager passes; + if (const DataLayout *DL = TM.getDataLayout()) + M.setDataLayout(DL); + + legacy::PassManager passes; + passes.add(new DataLayoutPass()); + passes.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis())); + PassManagerBuilder PMB; - PMB.LibraryInfo = new TargetLibraryInfo(Triple(TM.getTargetTriple())); + PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple())); PMB.Inliner = createFunctionInliningPass(); PMB.VerifyInput = true; PMB.VerifyOutput = true; PMB.LoopVectorize = true; PMB.SLPVectorize = true; - PMB.populateLTOPassManager(passes, &TM); + PMB.populateLTOPassManager(passes); passes.run(M); } @@ -711,10 +760,10 @@ static void codegen(Module &M) { runLTOPasses(M, *TM); - if (options::generate_bc_file == options::BC_SAVE_TEMPS) + if (options::TheOutputType == options::OT_SAVE_TEMPS) saveBCFile(output_name + ".opt.bc", M); - PassManager CodeGenPasses; + legacy::PassManager CodeGenPasses; CodeGenPasses.add(new DataLayoutPass()); SmallString<128> Filename; @@ -760,6 +809,8 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { return LDPS_OK; LLVMContext Context; + Context.setDiagnosticHandler(diagnosticHandler); + std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context)); Linker L(Combined.get()); @@ -768,8 +819,11 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { StringSet<> Internalize; StringSet<> Maybe; for (claimed_file &F : Modules) { + ld_plugin_input_file File; + if (get_input_file(F.handle, &File) != LDPS_OK) + message(LDPL_FATAL, "Failed to get file information"); std::unique_ptr<Module> M = - getModuleForFile(Context, F, ApiFile, Internalize, Maybe); + getModuleForFile(Context, F, File, ApiFile, Internalize, Maybe); if (!options::triple.empty()) M->setTargetTriple(options::triple.c_str()); else if (M->getTargetTriple().empty()) { @@ -778,6 +832,8 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { if (L.linkInModule(M.get())) message(LDPL_FATAL, "Failed to link module"); + if (release_input_file(F.handle) != LDPS_OK) + message(LDPL_FATAL, "Failed to release file information"); } for (const auto &Name : Internalize) { @@ -795,14 +851,17 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { internalize(*GV); } - if (options::generate_bc_file != options::BC_NO) { + if (options::TheOutputType == options::OT_DISABLE) + return LDPS_OK; + + if (options::TheOutputType != options::OT_NORMAL) { std::string path; - if (options::generate_bc_file == options::BC_ONLY) + if (options::TheOutputType == options::OT_BC_ONLY) path = output_name; else path = output_name + ".bc"; saveBCFile(path, *L.getModule()); - if (options::generate_bc_file == options::BC_ONLY) + if (options::TheOutputType == options::OT_BC_ONLY) return LDPS_OK; } @@ -828,8 +887,16 @@ static ld_plugin_status all_symbols_read_hook(void) { Ret = allSymbolsReadHook(&ApiFile); } - if (options::generate_bc_file == options::BC_ONLY) + llvm_shutdown(); + + if (options::TheOutputType == options::OT_BC_ONLY || + options::TheOutputType == options::OT_DISABLE) { + if (options::TheOutputType == options::OT_DISABLE) + // Remove the output file here since ld.bfd creates the output file + // early. + sys::fs::remove(output_name); exit(0); + } return Ret; } |