Index: llvm/include/llvm/LTO/LTO.h =================================================================== --- llvm/include/llvm/LTO/LTO.h +++ llvm/include/llvm/LTO/LTO.h @@ -59,7 +59,7 @@ /// must apply the changes to the Module via thinLTOInternalizeModule. void thinLTOInternalizeAndPromoteInIndex( ModuleSummaryIndex &Index, - function_ref isExported, + function_ref isExported, function_ref isPrevailing); Index: llvm/include/llvm/Transforms/IPO/FunctionImport.h =================================================================== --- llvm/include/llvm/Transforms/IPO/FunctionImport.h +++ llvm/include/llvm/Transforms/IPO/FunctionImport.h @@ -98,7 +98,7 @@ using ImportMapTy = StringMap; /// The set contains an entry for every global value the module exports. - using ExportSetTy = std::unordered_set; + using ExportSetTy = DenseSet; /// A function of this type is used to load modules referenced by the index. using ModuleLoaderTy = Index: llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h =================================================================== --- llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h +++ llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h @@ -251,7 +251,7 @@ /// devirt target names for any locals that were exported. void updateIndexWPDForExports( ModuleSummaryIndex &Summary, - function_ref isExported, + function_ref isExported, std::map> &LocalWPDTargetsMap); } // end namespace llvm Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -383,12 +383,12 @@ } static void thinLTOInternalizeAndPromoteGUID( - GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID, - function_ref isExported, + GlobalValueSummaryList &GVSummaryList, ValueInfo VI, + function_ref isExported, function_ref isPrevailing) { for (auto &S : GVSummaryList) { - if (isExported(S->modulePath(), GUID)) { + if (isExported(S->modulePath(), VI)) { if (GlobalValue::isLocalLinkage(S->linkage())) S->setLinkage(GlobalValue::ExternalLinkage); } else if (EnableLTOInternalization && @@ -396,7 +396,7 @@ // doesn't resolve them. !GlobalValue::isLocalLinkage(S->linkage()) && (!GlobalValue::isInterposableLinkage(S->linkage()) || - isPrevailing(GUID, S.get())) && + isPrevailing(VI.getGUID(), S.get())) && S->linkage() != GlobalValue::AppendingLinkage && // We can't internalize available_externally globals because this // can break function pointer equality. @@ -415,11 +415,12 @@ // as external and non-exported values as internal. void llvm::thinLTOInternalizeAndPromoteInIndex( ModuleSummaryIndex &Index, - function_ref isExported, + function_ref isExported, function_ref isPrevailing) { for (auto &I : Index) - thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, I.first, isExported, + thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, + ValueInfo(Index.haveGVs(), &I), isExported, isPrevailing); } @@ -1330,11 +1331,10 @@ ExportedGUIDs.insert( GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def))); - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { + auto isExported = [&](StringRef ModuleIdentifier, ValueInfo VI) { const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - ExportedGUIDs.count(GUID); + return (ExportList != ExportLists.end() && ExportList->second.count(VI)) || + ExportedGUIDs.count(VI.getGUID()); }; // Update local devirtualized targets that were exported by cross-module Index: llvm/lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -589,11 +589,10 @@ const DenseSet &GUIDPreservedSymbols) : ExportLists(ExportLists), GUIDPreservedSymbols(GUIDPreservedSymbols) {} - bool operator()(StringRef ModuleIdentifier, GlobalValue::GUID GUID) const { + bool operator()(StringRef ModuleIdentifier, ValueInfo VI) const { const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); + return (ExportList != ExportLists.end() && ExportList->second.count(VI)) || + GUIDPreservedSymbols.count(VI.getGUID()); } }; Index: llvm/lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionImport.cpp +++ llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -306,7 +306,7 @@ auto MarkExported = [&](const ValueInfo &VI, const GlobalValueSummary *S) { if (ExportLists) - (*ExportLists)[S->modulePath()].insert(VI.getGUID()); + (*ExportLists)[S->modulePath()].insert(VI); }; for (auto &RefSummary : VI.getSummaryList()) @@ -494,7 +494,7 @@ // Make exports in the source module. if (ExportLists) { auto &ExportList = (*ExportLists)[ExportModulePath]; - ExportList.insert(VI.getGUID()); + ExportList.insert(VI); 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 @@ -502,14 +502,11 @@ // 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); - } + for (auto &Edge : ResolvedCalleeSummary->calls()) + ExportList.insert(Edge.first); + + for (auto &Ref : ResolvedCalleeSummary->refs()) + ExportList.insert(Ref); } } } @@ -627,6 +624,37 @@ } #endif +static bool +checkVariableImport(const ModuleSummaryIndex &Index, + StringMap &ImportLists, + StringMap &ExportLists) { + + DenseSet FlattendedImports; + + for (auto &ImportPerModule : ImportLists) + for (auto &ExportPerModule : ImportPerModule.second) + for (auto GUID : ExportPerModule.second) + FlattendedImports.insert(GUID); + + // Checks that all GUIDs of read/writeonly vars we see in export lists + // are also in the import lists. Otherwise we my face linker undefs, + // because readonly and writeonly vars are internalized in their + // source modules. + auto IsReadOrWriteOnlyVar = [&](StringRef ModulePath, const ValueInfo &VI) { + auto *GVS = dyn_cast_or_null( + Index.findSummaryInModule(VI, ModulePath)); + return GVS && (Index.isReadOnly(GVS) || Index.isWriteOnly(GVS)); + }; + + for (auto &ExportPerModule : ExportLists) + for (auto &VI : ExportPerModule.second) + if (!FlattendedImports.count(VI.getGUID()) && + IsReadOrWriteOnlyVar(ExportPerModule.first(), VI)) + return false; + + return true; +} + /// Compute all the import and export for every module using the Index. void llvm::ComputeCrossModuleImport( const ModuleSummaryIndex &Index, @@ -651,14 +679,13 @@ for (auto &ELI : ExportLists) { const auto &DefinedGVSummaries = ModuleToDefinedGVSummaries.lookup(ELI.first()); - for (auto EI = ELI.second.begin(); EI != ELI.second.end();) { - if (!DefinedGVSummaries.count(*EI)) - EI = ELI.second.erase(EI); - else - ++EI; - } + std::remove_if(ELI.second.begin(), ELI.second.end(), + [&](const ValueInfo &VI) { + return !DefinedGVSummaries.count(VI.getGUID()); + }); } + assert(checkVariableImport(Index, ImportLists, ExportLists)); #ifndef NDEBUG LLVM_DEBUG(dbgs() << "Import/Export lists for " << ImportLists.size() << " modules:\n"); Index: llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp =================================================================== --- llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -709,7 +709,7 @@ void updateIndexWPDForExports( ModuleSummaryIndex &Summary, - function_ref isExported, + function_ref isExported, std::map> &LocalWPDTargetsMap) { for (auto &T : LocalWPDTargetsMap) { auto &VI = T.first; @@ -717,7 +717,7 @@ assert(VI.getSummaryList().size() == 1 && "Devirt of local target has more than one copy"); auto &S = VI.getSummaryList()[0]; - if (!isExported(S->modulePath(), VI.getGUID())) + if (!isExported(S->modulePath(), VI)) continue; // It's been exported by a cross module import.