diff options
Diffstat (limited to 'lib/Transforms/IPO/FunctionImport.cpp')
-rw-r--r-- | lib/Transforms/IPO/FunctionImport.cpp | 456 |
1 files changed, 314 insertions, 142 deletions
diff --git a/lib/Transforms/IPO/FunctionImport.cpp b/lib/Transforms/IPO/FunctionImport.cpp index b6d6201cd23b..15808a073894 100644 --- a/lib/Transforms/IPO/FunctionImport.cpp +++ b/lib/Transforms/IPO/FunctionImport.cpp @@ -18,8 +18,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/Constants.h" @@ -61,6 +61,7 @@ using namespace llvm; #define DEBUG_TYPE "function-import" STATISTIC(NumImportedFunctions, "Number of functions imported"); +STATISTIC(NumImportedGlobalVars, "Number of global variables imported"); STATISTIC(NumImportedModules, "Number of modules imported from"); STATISTIC(NumDeadSymbols, "Number of dead stripped symbols in index"); STATISTIC(NumLiveSymbols, "Number of live symbols in index"); @@ -70,6 +71,10 @@ static cl::opt<unsigned> ImportInstrLimit( "import-instr-limit", cl::init(100), cl::Hidden, cl::value_desc("N"), cl::desc("Only import functions with less than N instructions")); +static cl::opt<int> ImportCutoff( + "import-cutoff", cl::init(-1), cl::Hidden, cl::value_desc("N"), + cl::desc("Only import first N functions if N>=0 (default -1)")); + static cl::opt<float> ImportInstrFactor("import-instr-evolution-factor", cl::init(0.7), cl::Hidden, cl::value_desc("x"), @@ -131,7 +136,7 @@ static cl::opt<bool> static std::unique_ptr<Module> loadFile(const std::string &FileName, LLVMContext &Context) { SMDiagnostic Err; - DEBUG(dbgs() << "Loading '" << FileName << "'\n"); + LLVM_DEBUG(dbgs() << "Loading '" << FileName << "'\n"); // Metadata isn't loaded until functions are imported, to minimize // the memory overhead. std::unique_ptr<Module> Result = @@ -163,6 +168,9 @@ selectCallee(const ModuleSummaryIndex &Index, CalleeSummaryList, [&](const std::unique_ptr<GlobalValueSummary> &SummaryPtr) { auto *GVSummary = SummaryPtr.get(); + if (!Index.isGlobalValueLive(GVSummary)) + return false; + // For SamplePGO, in computeImportForFunction the OriginalId // may have been used to locate the callee summary list (See // comment there). @@ -231,10 +239,37 @@ updateValueInfoForIndirectCalls(const ModuleSummaryIndex &Index, ValueInfo VI) { // it, rather than needing to perform this mapping on each walk. auto GUID = Index.getGUIDFromOriginalID(VI.getGUID()); if (GUID == 0) - return nullptr; + return ValueInfo(); return Index.getValueInfo(GUID); } +static void computeImportForReferencedGlobals( + const FunctionSummary &Summary, const GVSummaryMapTy &DefinedGVSummaries, + FunctionImporter::ImportMapTy &ImportList, + StringMap<FunctionImporter::ExportSetTy> *ExportLists) { + for (auto &VI : Summary.refs()) { + if (DefinedGVSummaries.count(VI.getGUID())) { + LLVM_DEBUG( + dbgs() << "Ref ignored! Target already in destination module.\n"); + continue; + } + + LLVM_DEBUG(dbgs() << " ref -> " << VI << "\n"); + + for (auto &RefSummary : VI.getSummaryList()) + if (RefSummary->getSummaryKind() == GlobalValueSummary::GlobalVarKind && + // Don't try to import regular LTO summaries added to dummy module. + !RefSummary->modulePath().empty() && + !GlobalValue::isInterposableLinkage(RefSummary->linkage()) && + RefSummary->refs().empty()) { + ImportList[RefSummary->modulePath()].insert(VI.getGUID()); + if (ExportLists) + (*ExportLists)[RefSummary->modulePath()].insert(VI.getGUID()); + break; + } + } +} + /// Compute the list of functions to import for a given caller. Mark these /// imported functions and the symbols they reference in their source module as /// exported from their source module. @@ -243,18 +278,28 @@ static void computeImportForFunction( const unsigned Threshold, const GVSummaryMapTy &DefinedGVSummaries, SmallVectorImpl<EdgeInfo> &Worklist, FunctionImporter::ImportMapTy &ImportList, - StringMap<FunctionImporter::ExportSetTy> *ExportLists = nullptr) { + StringMap<FunctionImporter::ExportSetTy> *ExportLists, + FunctionImporter::ImportThresholdsTy &ImportThresholds) { + computeImportForReferencedGlobals(Summary, DefinedGVSummaries, ImportList, + ExportLists); + static int ImportCount = 0; for (auto &Edge : Summary.calls()) { ValueInfo VI = Edge.first; - DEBUG(dbgs() << " edge -> " << VI.getGUID() << " Threshold:" << Threshold - << "\n"); + LLVM_DEBUG(dbgs() << " edge -> " << VI << " Threshold:" << Threshold + << "\n"); + + if (ImportCutoff >= 0 && ImportCount >= ImportCutoff) { + LLVM_DEBUG(dbgs() << "ignored! import-cutoff value of " << ImportCutoff + << " reached.\n"); + continue; + } VI = updateValueInfoForIndirectCalls(Index, VI); if (!VI) continue; if (DefinedGVSummaries.count(VI.getGUID())) { - DEBUG(dbgs() << "ignored! Target already in destination module.\n"); + LLVM_DEBUG(dbgs() << "ignored! Target already in destination module.\n"); continue; } @@ -269,20 +314,87 @@ static void computeImportForFunction( }; const auto NewThreshold = - Threshold * GetBonusMultiplier(Edge.second.Hotness); - - auto *CalleeSummary = selectCallee(Index, VI.getSummaryList(), NewThreshold, - Summary.modulePath()); - if (!CalleeSummary) { - DEBUG(dbgs() << "ignored! No qualifying callee with summary found.\n"); - continue; - } + Threshold * GetBonusMultiplier(Edge.second.getHotness()); + + auto IT = ImportThresholds.insert( + std::make_pair(VI.getGUID(), std::make_pair(NewThreshold, nullptr))); + bool PreviouslyVisited = !IT.second; + auto &ProcessedThreshold = IT.first->second.first; + auto &CalleeSummary = IT.first->second.second; + + const FunctionSummary *ResolvedCalleeSummary = nullptr; + if (CalleeSummary) { + assert(PreviouslyVisited); + // Since the traversal of the call graph is DFS, we can revisit a function + // a second time with a higher threshold. In this case, it is added back + // to the worklist with the new threshold (so that its own callee chains + // can be considered with the higher threshold). + if (NewThreshold <= ProcessedThreshold) { + LLVM_DEBUG( + dbgs() << "ignored! Target was already imported with Threshold " + << ProcessedThreshold << "\n"); + continue; + } + // Update with new larger threshold. + ProcessedThreshold = NewThreshold; + ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary); + } else { + // If we already rejected importing a callee at the same or higher + // threshold, don't waste time calling selectCallee. + if (PreviouslyVisited && NewThreshold <= ProcessedThreshold) { + LLVM_DEBUG( + dbgs() << "ignored! Target was already rejected with Threshold " + << ProcessedThreshold << "\n"); + continue; + } - // "Resolve" the summary - const auto *ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary->getBaseObject()); + CalleeSummary = selectCallee(Index, VI.getSummaryList(), NewThreshold, + Summary.modulePath()); + if (!CalleeSummary) { + // Update with new larger threshold if this was a retry (otherwise + // we would have already inserted with NewThreshold above). + if (PreviouslyVisited) + ProcessedThreshold = NewThreshold; + LLVM_DEBUG( + dbgs() << "ignored! No qualifying callee with summary found.\n"); + continue; + } - assert(ResolvedCalleeSummary->instCount() <= NewThreshold && - "selectCallee() didn't honor the threshold"); + // "Resolve" the summary + CalleeSummary = CalleeSummary->getBaseObject(); + ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary); + + assert(ResolvedCalleeSummary->instCount() <= NewThreshold && + "selectCallee() didn't honor the threshold"); + + auto ExportModulePath = ResolvedCalleeSummary->modulePath(); + auto ILI = ImportList[ExportModulePath].insert(VI.getGUID()); + // We previously decided to import this GUID definition if it was already + // inserted in the set of imports from the exporting module. + bool PreviouslyImported = !ILI.second; + + // Make exports in the source module. + if (ExportLists) { + auto &ExportList = (*ExportLists)[ExportModulePath]; + ExportList.insert(VI.getGUID()); + if (!PreviouslyImported) { + // This is the first time this function was exported from its source + // module, so mark all functions and globals it references as exported + // to the outside if they are defined in the same source module. + // For efficiency, we unconditionally add all the referenced GUIDs + // to the ExportList for this module, and will prune out any not + // defined in the module later in a single pass. + for (auto &Edge : ResolvedCalleeSummary->calls()) { + auto CalleeGUID = Edge.first.getGUID(); + ExportList.insert(CalleeGUID); + } + for (auto &Ref : ResolvedCalleeSummary->refs()) { + auto GUID = Ref.getGUID(); + ExportList.insert(GUID); + } + } + } + } auto GetAdjustedThreshold = [](unsigned Threshold, bool IsHotCallsite) { // Adjust the threshold for next level of imported functions. @@ -293,44 +405,11 @@ static void computeImportForFunction( return Threshold * ImportInstrFactor; }; - bool IsHotCallsite = Edge.second.Hotness == CalleeInfo::HotnessType::Hot; + bool IsHotCallsite = + Edge.second.getHotness() == CalleeInfo::HotnessType::Hot; const auto AdjThreshold = GetAdjustedThreshold(Threshold, IsHotCallsite); - auto ExportModulePath = ResolvedCalleeSummary->modulePath(); - auto &ProcessedThreshold = ImportList[ExportModulePath][VI.getGUID()]; - /// Since the traversal of the call graph is DFS, we can revisit a function - /// a second time with a higher threshold. In this case, it is added back to - /// the worklist with the new threshold. - if (ProcessedThreshold && ProcessedThreshold >= AdjThreshold) { - DEBUG(dbgs() << "ignored! Target was already seen with Threshold " - << ProcessedThreshold << "\n"); - continue; - } - bool PreviouslyImported = ProcessedThreshold != 0; - // Mark this function as imported in this module, with the current Threshold - ProcessedThreshold = AdjThreshold; - - // Make exports in the source module. - if (ExportLists) { - auto &ExportList = (*ExportLists)[ExportModulePath]; - ExportList.insert(VI.getGUID()); - if (!PreviouslyImported) { - // This is the first time this function was exported from its source - // module, so mark all functions and globals it references as exported - // to the outside if they are defined in the same source module. - // For efficiency, we unconditionally add all the referenced GUIDs - // to the ExportList for this module, and will prune out any not - // defined in the module later in a single pass. - for (auto &Edge : ResolvedCalleeSummary->calls()) { - auto CalleeGUID = Edge.first.getGUID(); - ExportList.insert(CalleeGUID); - } - for (auto &Ref : ResolvedCalleeSummary->refs()) { - auto GUID = Ref.getGUID(); - ExportList.insert(GUID); - } - } - } + ImportCount++; // Insert the newly imported function to the worklist. Worklist.emplace_back(ResolvedCalleeSummary, AdjThreshold, VI.getGUID()); @@ -347,12 +426,18 @@ static void ComputeImportForModule( // Worklist contains the list of function imported in this module, for which // we will analyse the callees and may import further down the callgraph. SmallVector<EdgeInfo, 128> Worklist; + FunctionImporter::ImportThresholdsTy ImportThresholds; // Populate the worklist with the import for the functions in the current // module for (auto &GVSummary : DefinedGVSummaries) { +#ifndef NDEBUG + // FIXME: Change the GVSummaryMapTy to hold ValueInfo instead of GUID + // so this map look up (and possibly others) can be avoided. + auto VI = Index.getValueInfo(GVSummary.first); +#endif if (!Index.isGlobalValueLive(GVSummary.second)) { - DEBUG(dbgs() << "Ignores Dead GUID: " << GVSummary.first << "\n"); + LLVM_DEBUG(dbgs() << "Ignores Dead GUID: " << VI << "\n"); continue; } auto *FuncSummary = @@ -360,10 +445,10 @@ static void ComputeImportForModule( if (!FuncSummary) // Skip import for global variables continue; - DEBUG(dbgs() << "Initialize import for " << GVSummary.first << "\n"); + LLVM_DEBUG(dbgs() << "Initialize import for " << VI << "\n"); computeImportForFunction(*FuncSummary, Index, ImportInstrLimit, DefinedGVSummaries, Worklist, ImportList, - ExportLists); + ExportLists, ImportThresholds); } // Process the newly imported functions and add callees to the worklist. @@ -371,20 +456,37 @@ static void ComputeImportForModule( auto FuncInfo = Worklist.pop_back_val(); auto *Summary = std::get<0>(FuncInfo); auto Threshold = std::get<1>(FuncInfo); - auto GUID = std::get<2>(FuncInfo); - - // Check if we later added this summary with a higher threshold. - // If so, skip this entry. - auto ExportModulePath = Summary->modulePath(); - auto &LatestProcessedThreshold = ImportList[ExportModulePath][GUID]; - if (LatestProcessedThreshold > Threshold) - continue; computeImportForFunction(*Summary, Index, Threshold, DefinedGVSummaries, - Worklist, ImportList, ExportLists); + Worklist, ImportList, ExportLists, + ImportThresholds); + } +} + +#ifndef NDEBUG +static bool isGlobalVarSummary(const ModuleSummaryIndex &Index, + GlobalValue::GUID G) { + if (const auto &VI = Index.getValueInfo(G)) { + auto SL = VI.getSummaryList(); + if (!SL.empty()) + return SL[0]->getSummaryKind() == GlobalValueSummary::GlobalVarKind; } + return false; } +static GlobalValue::GUID getGUID(GlobalValue::GUID G) { return G; } + +template <class T> +static unsigned numGlobalVarSummaries(const ModuleSummaryIndex &Index, + T &Cont) { + unsigned NumGVS = 0; + for (auto &V : Cont) + if (isGlobalVarSummary(Index, getGUID(V))) + ++NumGVS; + return NumGVS; +} +#endif + /// Compute all the import and export for every module using the Index. void llvm::ComputeCrossModuleImport( const ModuleSummaryIndex &Index, @@ -394,8 +496,8 @@ void llvm::ComputeCrossModuleImport( // For each module that has function defined, compute the import/export lists. for (auto &DefinedGVSummaries : ModuleToDefinedGVSummaries) { auto &ImportList = ImportLists[DefinedGVSummaries.first()]; - DEBUG(dbgs() << "Computing import for Module '" - << DefinedGVSummaries.first() << "'\n"); + LLVM_DEBUG(dbgs() << "Computing import for Module '" + << DefinedGVSummaries.first() << "'\n"); ComputeImportForModule(DefinedGVSummaries.second, Index, ImportList, &ExportLists); } @@ -417,32 +519,41 @@ void llvm::ComputeCrossModuleImport( } #ifndef NDEBUG - DEBUG(dbgs() << "Import/Export lists for " << ImportLists.size() - << " modules:\n"); + LLVM_DEBUG(dbgs() << "Import/Export lists for " << ImportLists.size() + << " modules:\n"); for (auto &ModuleImports : ImportLists) { auto ModName = ModuleImports.first(); auto &Exports = ExportLists[ModName]; - DEBUG(dbgs() << "* Module " << ModName << " exports " << Exports.size() - << " functions. Imports from " << ModuleImports.second.size() - << " modules.\n"); + unsigned NumGVS = numGlobalVarSummaries(Index, Exports); + LLVM_DEBUG(dbgs() << "* Module " << ModName << " exports " + << Exports.size() - NumGVS << " functions and " << NumGVS + << " vars. Imports from " << ModuleImports.second.size() + << " modules.\n"); for (auto &Src : ModuleImports.second) { auto SrcModName = Src.first(); - DEBUG(dbgs() << " - " << Src.second.size() << " functions imported from " - << SrcModName << "\n"); + unsigned NumGVSPerMod = numGlobalVarSummaries(Index, Src.second); + LLVM_DEBUG(dbgs() << " - " << Src.second.size() - NumGVSPerMod + << " functions imported from " << SrcModName << "\n"); + LLVM_DEBUG(dbgs() << " - " << NumGVSPerMod + << " global vars imported from " << SrcModName << "\n"); } } #endif } #ifndef NDEBUG -static void dumpImportListForModule(StringRef ModulePath, +static void dumpImportListForModule(const ModuleSummaryIndex &Index, + StringRef ModulePath, FunctionImporter::ImportMapTy &ImportList) { - DEBUG(dbgs() << "* Module " << ModulePath << " imports from " - << ImportList.size() << " modules.\n"); + LLVM_DEBUG(dbgs() << "* Module " << ModulePath << " imports from " + << ImportList.size() << " modules.\n"); for (auto &Src : ImportList) { auto SrcModName = Src.first(); - DEBUG(dbgs() << " - " << Src.second.size() << " functions imported from " - << SrcModName << "\n"); + unsigned NumGVSPerMod = numGlobalVarSummaries(Index, Src.second); + LLVM_DEBUG(dbgs() << " - " << Src.second.size() - NumGVSPerMod + << " functions imported from " << SrcModName << "\n"); + LLVM_DEBUG(dbgs() << " - " << NumGVSPerMod << " vars imported from " + << SrcModName << "\n"); } } #endif @@ -457,11 +568,11 @@ void llvm::ComputeCrossModuleImportForModule( Index.collectDefinedFunctionsForModule(ModulePath, FunctionSummaryMap); // Compute the import list for this module. - DEBUG(dbgs() << "Computing import for Module '" << ModulePath << "'\n"); + LLVM_DEBUG(dbgs() << "Computing import for Module '" << ModulePath << "'\n"); ComputeImportForModule(FunctionSummaryMap, Index, ImportList); #ifndef NDEBUG - dumpImportListForModule(ModulePath, ImportList); + dumpImportListForModule(Index, ModulePath, ImportList); #endif } @@ -483,18 +594,18 @@ void llvm::ComputeCrossModuleImportForModuleFromIndex( // e.g. record required linkage changes. if (Summary->modulePath() == ModulePath) continue; - // Doesn't matter what value we plug in to the map, just needs an entry - // to provoke importing by thinBackend. - ImportList[Summary->modulePath()][GUID] = 1; + // Add an entry to provoke importing by thinBackend. + ImportList[Summary->modulePath()].insert(GUID); } #ifndef NDEBUG - dumpImportListForModule(ModulePath, ImportList); + dumpImportListForModule(Index, ModulePath, ImportList); #endif } void llvm::computeDeadSymbols( ModuleSummaryIndex &Index, - const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { + const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols, + function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing) { assert(!Index.withGlobalValueDeadStripping()); if (!ComputeDead) return; @@ -513,17 +624,18 @@ void llvm::computeDeadSymbols( } // Add values flagged in the index as live roots to the worklist. - for (const auto &Entry : Index) + for (const auto &Entry : Index) { + auto VI = Index.getValueInfo(Entry); for (auto &S : Entry.second.SummaryList) if (S->isLive()) { - DEBUG(dbgs() << "Live root: " << Entry.first << "\n"); - Worklist.push_back(ValueInfo(&Entry)); + LLVM_DEBUG(dbgs() << "Live root: " << VI << "\n"); + Worklist.push_back(VI); ++LiveSymbols; break; } + } // Make value live and add it to the worklist if it was not live before. - // FIXME: we should only make the prevailing copy live here auto visit = [&](ValueInfo VI) { // FIXME: If we knew which edges were created for indirect call profiles, // we could skip them here. Any that are live should be reached via @@ -539,6 +651,28 @@ void llvm::computeDeadSymbols( for (auto &S : VI.getSummaryList()) if (S->isLive()) return; + + // We only keep live symbols that are known to be non-prevailing if any are + // available_externally. Those symbols are discarded later in the + // EliminateAvailableExternally pass and setting them to not-live breaks + // downstreams users of liveness information (PR36483). + if (isPrevailing(VI.getGUID()) == PrevailingType::No) { + bool AvailableExternally = false; + bool Interposable = false; + for (auto &S : VI.getSummaryList()) { + if (S->linkage() == GlobalValue::AvailableExternallyLinkage) + AvailableExternally = true; + else if (GlobalValue::isInterposableLinkage(S->linkage())) + Interposable = true; + } + + if (!AvailableExternally) + return; + + if (Interposable) + report_fatal_error("Interposable and available_externally symbol"); + } + for (auto &S : VI.getSummaryList()) S->setLive(true); ++LiveSymbols; @@ -549,6 +683,8 @@ void llvm::computeDeadSymbols( auto VI = Worklist.pop_back_val(); for (auto &Summary : VI.getSummaryList()) { GlobalValueSummary *Base = Summary->getBaseObject(); + // Set base value live in case it is an alias. + Base->setLive(true); for (auto Ref : Base->refs()) visit(Ref); if (auto *FS = dyn_cast<FunctionSummary>(Base)) @@ -559,8 +695,8 @@ void llvm::computeDeadSymbols( Index.setWithGlobalValueDeadStripping(); unsigned DeadSymbols = Index.size() - LiveSymbols; - DEBUG(dbgs() << LiveSymbols << " symbols Live, and " << DeadSymbols - << " symbols Dead \n"); + LLVM_DEBUG(dbgs() << LiveSymbols << " symbols Live, and " << DeadSymbols + << " symbols Dead \n"); NumDeadSymbols += DeadSymbols; NumLiveSymbols += LiveSymbols; } @@ -581,47 +717,66 @@ void llvm::gatherImportedSummariesForModule( const auto &DefinedGVSummaries = ModuleToDefinedGVSummaries.lookup(ILI.first()); for (auto &GI : ILI.second) { - const auto &DS = DefinedGVSummaries.find(GI.first); + const auto &DS = DefinedGVSummaries.find(GI); assert(DS != DefinedGVSummaries.end() && "Expected a defined summary for imported global value"); - SummariesForIndex[GI.first] = DS->second; + SummariesForIndex[GI] = DS->second; } } } /// Emit the files \p ModulePath will import from into \p OutputFilename. -std::error_code -llvm::EmitImportsFiles(StringRef ModulePath, StringRef OutputFilename, - const FunctionImporter::ImportMapTy &ModuleImports) { +std::error_code llvm::EmitImportsFiles( + StringRef ModulePath, StringRef OutputFilename, + const std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex) { std::error_code EC; raw_fd_ostream ImportsOS(OutputFilename, EC, sys::fs::OpenFlags::F_None); if (EC) return EC; - for (auto &ILI : ModuleImports) - ImportsOS << ILI.first() << "\n"; + for (auto &ILI : ModuleToSummariesForIndex) + // The ModuleToSummariesForIndex map includes an entry for the current + // Module (needed for writing out the index files). We don't want to + // include it in the imports file, however, so filter it out. + if (ILI.first != ModulePath) + ImportsOS << ILI.first << "\n"; return std::error_code(); } +bool llvm::convertToDeclaration(GlobalValue &GV) { + LLVM_DEBUG(dbgs() << "Converting to a declaration: `" << GV.getName() + << "\n"); + if (Function *F = dyn_cast<Function>(&GV)) { + F->deleteBody(); + F->clearMetadata(); + F->setComdat(nullptr); + } else if (GlobalVariable *V = dyn_cast<GlobalVariable>(&GV)) { + V->setInitializer(nullptr); + V->setLinkage(GlobalValue::ExternalLinkage); + V->clearMetadata(); + V->setComdat(nullptr); + } else { + GlobalValue *NewGV; + if (GV.getValueType()->isFunctionTy()) + NewGV = + Function::Create(cast<FunctionType>(GV.getValueType()), + GlobalValue::ExternalLinkage, "", GV.getParent()); + else + NewGV = + new GlobalVariable(*GV.getParent(), GV.getValueType(), + /*isConstant*/ false, GlobalValue::ExternalLinkage, + /*init*/ nullptr, "", + /*insertbefore*/ nullptr, GV.getThreadLocalMode(), + GV.getType()->getAddressSpace()); + NewGV->takeName(&GV); + GV.replaceAllUsesWith(NewGV); + return false; + } + return true; +} + /// Fixup WeakForLinker linkages in \p TheModule based on summary analysis. void llvm::thinLTOResolveWeakForLinkerModule( Module &TheModule, const GVSummaryMapTy &DefinedGlobals) { - auto ConvertToDeclaration = [](GlobalValue &GV) { - DEBUG(dbgs() << "Converting to a declaration: `" << GV.getName() << "\n"); - if (Function *F = dyn_cast<Function>(&GV)) { - F->deleteBody(); - F->clearMetadata(); - } else if (GlobalVariable *V = dyn_cast<GlobalVariable>(&GV)) { - V->setInitializer(nullptr); - V->setLinkage(GlobalValue::ExternalLinkage); - V->clearMetadata(); - } else - // For now we don't resolve or drop aliases. Once we do we'll - // need to add support here for creating either a function or - // variable declaration, and return the new GlobalValue* for - // the caller to use. - llvm_unreachable("Expected function or variable"); - }; - auto updateLinkage = [&](GlobalValue &GV) { // See if the global summary analysis computed a new resolved linkage. const auto &GS = DefinedGlobals.find(GV.getGUID()); @@ -651,11 +806,23 @@ void llvm::thinLTOResolveWeakForLinkerModule( // interposable property and possibly get inlined. Simply drop // the definition in that case. if (GlobalValue::isAvailableExternallyLinkage(NewLinkage) && - GlobalValue::isInterposableLinkage(GV.getLinkage())) - ConvertToDeclaration(GV); - else { - DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() << "` from " - << GV.getLinkage() << " to " << NewLinkage << "\n"); + GlobalValue::isInterposableLinkage(GV.getLinkage())) { + if (!convertToDeclaration(GV)) + // FIXME: Change this to collect replaced GVs and later erase + // them from the parent module once thinLTOResolveWeakForLinkerGUID is + // changed to enable this for aliases. + llvm_unreachable("Expected GV to be converted"); + } else { + // If the original symbols has global unnamed addr and linkonce_odr linkage, + // it should be an auto hide symbol. Add hidden visibility to the symbol to + // preserve the property. + if (GV.hasLinkOnceODRLinkage() && GV.hasGlobalUnnamedAddr() && + NewLinkage == GlobalValue::WeakODRLinkage) + GV.setVisibility(GlobalValue::HiddenVisibility); + + LLVM_DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() + << "` from " << GV.getLinkage() << " to " << NewLinkage + << "\n"); GV.setLinkage(NewLinkage); } // Remove declarations from comdats, including available_externally @@ -732,9 +899,9 @@ static Function *replaceAliasWithAliasee(Module *SrcModule, GlobalAlias *GA) { // index. Expected<bool> FunctionImporter::importFunctions( Module &DestModule, const FunctionImporter::ImportMapTy &ImportList) { - DEBUG(dbgs() << "Starting import for Module " - << DestModule.getModuleIdentifier() << "\n"); - unsigned ImportedCount = 0; + LLVM_DEBUG(dbgs() << "Starting import for Module " + << DestModule.getModuleIdentifier() << "\n"); + unsigned ImportedCount = 0, ImportedGVCount = 0; IRMover Mover(DestModule); // Do the actual import of functions now, one Module at a time @@ -766,9 +933,9 @@ Expected<bool> FunctionImporter::importFunctions( continue; auto GUID = F.getGUID(); auto Import = ImportGUIDs.count(GUID); - DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing function " << GUID - << " " << F.getName() << " from " - << SrcModule->getSourceFileName() << "\n"); + LLVM_DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing function " + << GUID << " " << F.getName() << " from " + << SrcModule->getSourceFileName() << "\n"); if (Import) { if (Error Err = F.materialize()) return std::move(Err); @@ -788,13 +955,13 @@ Expected<bool> FunctionImporter::importFunctions( continue; auto GUID = GV.getGUID(); auto Import = ImportGUIDs.count(GUID); - DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing global " << GUID - << " " << GV.getName() << " from " - << SrcModule->getSourceFileName() << "\n"); + LLVM_DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing global " + << GUID << " " << GV.getName() << " from " + << SrcModule->getSourceFileName() << "\n"); if (Import) { if (Error Err = GV.materialize()) return std::move(Err); - GlobalsToImport.insert(&GV); + ImportedGVCount += GlobalsToImport.insert(&GV); } } for (GlobalAlias &GA : SrcModule->aliases()) { @@ -802,9 +969,9 @@ Expected<bool> FunctionImporter::importFunctions( continue; auto GUID = GA.getGUID(); auto Import = ImportGUIDs.count(GUID); - DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing alias " << GUID - << " " << GA.getName() << " from " - << SrcModule->getSourceFileName() << "\n"); + LLVM_DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing alias " + << GUID << " " << GA.getName() << " from " + << SrcModule->getSourceFileName() << "\n"); if (Import) { if (Error Err = GA.materialize()) return std::move(Err); @@ -813,9 +980,9 @@ Expected<bool> FunctionImporter::importFunctions( if (Error Err = Base->materialize()) return std::move(Err); auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA); - DEBUG(dbgs() << "Is importing aliasee fn " << Base->getGUID() - << " " << Base->getName() << " from " - << SrcModule->getSourceFileName() << "\n"); + LLVM_DEBUG(dbgs() << "Is importing aliasee fn " << Base->getGUID() + << " " << Base->getName() << " from " + << SrcModule->getSourceFileName() << "\n"); if (EnableImportMetadata) { // Add 'thinlto_src_module' metadata for statistics and debugging. Fn->setMetadata( @@ -851,10 +1018,15 @@ Expected<bool> FunctionImporter::importFunctions( NumImportedModules++; } - NumImportedFunctions += ImportedCount; + NumImportedFunctions += (ImportedCount - ImportedGVCount); + NumImportedGlobalVars += ImportedGVCount; - DEBUG(dbgs() << "Imported " << ImportedCount << " functions for Module " - << DestModule.getModuleIdentifier() << "\n"); + LLVM_DEBUG(dbgs() << "Imported " << ImportedCount - ImportedGVCount + << " functions for Module " + << DestModule.getModuleIdentifier() << "\n"); + LLVM_DEBUG(dbgs() << "Imported " << ImportedGVCount + << " global variables for Module " + << DestModule.getModuleIdentifier() << "\n"); return ImportedCount; } |