Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -571,7 +571,7 @@ } /// Get the SimilarityHash of this function. - unsigned similarityHash() { return SimilarityHash; } + unsigned similarityHash() const { return SimilarityHash; } bool hasSimilarFunction(unsigned id) { return SimilarFunctions.count(id); } @@ -580,6 +580,10 @@ return; // invalid id. if (DuplicateFunctions.count(GUID)) return; + ValueInfo VI = getValueInfo(GUID); + assert(VI.getSummaryList().size() == 1); + GlobalValueSummary *S = VI.getSummaryList()[0].get(); + assert(isa(S) && "Not a function summary!"); if (FunctionSimilarityHashes.count(GUID)) { // Erase the GUID having multiple visits in the ModuleSummaryIndex. Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -241,8 +241,25 @@ return cast(It->get()); } -namespace { +void addAllCallsAndRefs(const FunctionSummary *FS, + FunctionImporter::ExportSetTy &ExportList) { + // 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 : FS->calls()) { + auto CalleeGUID = Edge.first.getGUID(); + ExportList.insert(CalleeGUID); + } + for (auto &Ref : FS->refs()) { + auto GUID = Ref.getGUID(); + ExportList.insert(GUID); + } +} +namespace { using EdgeInfo = std::tuple; @@ -440,22 +457,8 @@ 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); - } - } + if (!PreviouslyImported) + addAllCallsAndRefs(ResolvedCalleeSummary, ExportList); } } @@ -477,6 +480,56 @@ // Insert the newly imported function to the worklist. Worklist.emplace_back(ResolvedCalleeSummary, AdjThreshold, VI.getGUID()); } + + // TODO: Do not import too many functions + // TODO: Make hashing little more strict to have higher hit rate + auto &HostSimilarFunctions = Index.getHostSimilarFunction(); + if (HostSimilarFunctions.empty()) + return; + // If the function is similar to others and is a host, then import the others + auto GUID = Summary.getOriginalName(); + auto I = HostSimilarFunctions.find(GUID); + if (I != HostSimilarFunctions.end()) { + // This Function is in the hosting module. + unsigned SimHash = Summary.similarityHash(); + auto &SimFunctionsHash = Index.getSimilarFunctionsHash(); + unsigned SimHashFromIndex = SimFunctionsHash.find(GUID)->second; + assert(SimHash == SimHashFromIndex); + auto &SimFunctions = Index.getSimilarFunctions(); + auto GUIDs = SimFunctions.find(SimHash)->second; + for (auto GUID : GUIDs) { + // Import GUIDs from outside module. + // FIXME: Import a function once ever! + // assert if a GUID is exported twice + if (!DefinedGVSummaries.count(GUID)) { + // Get the Summary from GUID to add to export summary. + if (ValueInfo VI = Index.getValueInfo(GUID)) { + if (VI.getSummaryList().size() == 1) { + GlobalValueSummary *S = VI.getSummaryList()[0].get(); + auto ExportModulePath = S->modulePath(); + auto &ProcessPair = ImportList[ExportModulePath][GUID]; + DEBUG(dbgs() << "\nImporting: " << GUID << ", with Hash: " + << SimHash << ", from: " << ExportModulePath;); + // TODO: Do not process same GUID twice! + auto &ExportList = (*ExportLists)[ExportModulePath]; + // Import other dependencies as decl only. + auto FS = cast(S); + addAllCallsAndRefs(FS, ExportList); + ExportList.insert(GUID); + // FIXME: Importing only small functions for now. + ProcessPair.first = ImportInstrLimit * 2; + ProcessPair.second = false; // Import definition. + } + } + } else { + auto *S = Index.getValueInfo(GUID).getSummaryList()[0].get(); + DEBUG(dbgs() << "\nNot importing, Already present: " << GUID + << ", with Hash: " << SimHash + << ", in: " << S->modulePath();); + } + } + } + } /// Given the list of globals defined in a module, compute the list of imports Index: lib/Transforms/IPO/MergeSimilarFunctions.cpp =================================================================== --- lib/Transforms/IPO/MergeSimilarFunctions.cpp +++ lib/Transforms/IPO/MergeSimilarFunctions.cpp @@ -1343,6 +1343,12 @@ for (auto &I : M) Registry.defer(&I); + // Populate information from each function summary to module summary index. + // create a function like computedevirtualization, like compute merge function + // that is like making decision before thinlto starts. + // use the index during the thinlto time to do function merging. + // TODO: Set the linkage type correctly such that imported function + // remains and the other one gets removed by the linker. do { unsigned InsertCount = Registry.enqueue();