Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -814,6 +814,20 @@ StringSaver Saver; BumpPtrAllocator Alloc; + /// Functions with hash code as a measure of structural similarity. + /// Used by MergeSimilarFunctions. The value_type is the hash code + /// computed by profileFunction. + std::map FunctionSimilarityHashes; + /// Reverse map of @var SimilarFunctionsHash to be used during thin-lto. + /// Each GUID in the vector corresponds to functions with same hash (id). + std::map> SimilarFunctions; + /// Functions having multiple entries in ModuleSummaryIndex. + std::set DuplicateFunctions; + /// All similar functions w.r.t the one in this set will be imported into + /// the module of these functions during thin-lto stage. + /// FIXME: Maybe use a vector? + std::set HostSimilarFunction; + // YAML I/O support. friend yaml::MappingTraits; @@ -898,6 +912,76 @@ return CallGraphRoot; } + bool hasSimilarFunction(unsigned id) { return SimilarFunctions.count(id); } + + void addToSimilarFunctions(unsigned id, GlobalValue::GUID GUID) { + if (id == 0) + return; // invalid id. + if (DuplicateFunctions.count(GUID)) + return; + + if (FunctionSimilarityHashes.count(GUID)) { + // Erase the GUID having multiple visits in the ModuleSummaryIndex. + FunctionSimilarityHashes.erase(GUID); + DuplicateFunctions.insert(GUID); + return; + } + + FunctionSimilarityHashes[GUID] = id; + } + + void populateReverseSimilarityHashMap() { + for (auto &p : FunctionSimilarityHashes) + SimilarFunctions[p.second].push_back(p.first); + } + + void removeSingleEntriesFromSimHashMaps() { + // Iterate over the hash to remove entries with no duplicates. + for (auto I = SimilarFunctions.begin(), E = SimilarFunctions.end(); + I != E;) { + auto Next = std::next(I); + assert(I->second.size() && "Empty Entry!"); + if (I->second.size() == 1) { + FunctionSimilarityHashes.erase(I->second[0]); + SimilarFunctions.erase(I); + } + I = Next; + } + } + + std::map> &getSimilarFunctions() { + return SimilarFunctions; + } + + const std::map> & + getSimilarFunctions() const { + return SimilarFunctions; + } + + unsigned getSimilarityHash(GlobalValue::GUID ID) const { + return FunctionSimilarityHashes.find(ID)->second; + } + + std::map &getSimilarFunctionsHash() { + return FunctionSimilarityHashes; + } + + const std::map &getSimilarFunctionsHash() const { + return FunctionSimilarityHashes; + } + + void addToHostSimilarFunction(GlobalValue::GUID ID) { + HostSimilarFunction.insert(ID); + } + + std::set &getHostSimilarFunction() { + return HostSimilarFunction; + } + + const std::set &getHostSimilarFunction() const { + return HostSimilarFunction; + } + bool withGlobalValueDeadStripping() const { return WithGlobalValueDeadStripping; } Index: include/llvm/Transforms/IPO/WholeProgramDevirt.h =================================================================== --- include/llvm/Transforms/IPO/WholeProgramDevirt.h +++ include/llvm/Transforms/IPO/WholeProgramDevirt.h @@ -229,6 +229,10 @@ PreservedAnalyses run(Module &M, ModuleAnalysisManager &); }; +/// Decide which functions to import for function merging during the thinlto. +/// Populates information from each function summary to module summary index. +void computeMergeSimilarFunctions(ModuleSummaryIndex &Index); + } // end namespace llvm #endif // LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H Index: lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- lib/LTO/ThinLTOCodeGenerator.cpp +++ lib/LTO/ThinLTOCodeGenerator.cpp @@ -72,6 +72,8 @@ extern cl::opt LTOPassRemarksWithHotness; } +extern cl::opt EnableMergeSimilarFunctions; + namespace { static cl::opt @@ -870,6 +872,9 @@ ProducedBinaryFiles.resize(Modules.size()); } + if (EnableMergeSimilarFunctions) + computeMergeSimilarFunctions(*Index); + if (CodeGenOnly) { // Perform only parallel codegen and return. ThreadPool Pool; Index: lib/Transforms/IPO/MergeSimilarFunctions.cpp =================================================================== --- lib/Transforms/IPO/MergeSimilarFunctions.cpp +++ lib/Transforms/IPO/MergeSimilarFunctions.cpp @@ -40,6 +40,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO/WholeProgramDevirt.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ValueMapper.h" @@ -1295,6 +1296,42 @@ return new MergeSimilarFunctions(S); } +void llvm::computeMergeSimilarFunctions(ModuleSummaryIndex &Index) { + assert(Index.getSimilarFunctions().empty() && "Inserting SimHash twice"); + for (auto &P : Index) { + for (auto &S : P.second.SummaryList) { + FunctionSummary *FS = dyn_cast(S.get()); + if (!FS) + continue; + LLVM_DEBUG(llvm::errs() << "\nSimilarity hash: " << FS->similarityHash()); + Index.addToSimilarFunctions(FS->similarityHash(), FS->getOriginalName()); + } + } + Index.populateReverseSimilarityHashMap(); + llvm::errs() << "\nSize SimilarFunctionsHash: " + << Index.getSimilarFunctionsHash().size(); + llvm::errs() << "\nSize SimilarFunctions: " + << Index.getSimilarFunctions().size(); + Index.removeSingleEntriesFromSimHashMaps(); + + LLVM_DEBUG(llvm::errs() << "\nSize SimilarFunctionsHash: " + << Index.getSimilarFunctionsHash().size()); + LLVM_DEBUG(llvm::errs() << "\nSize SimilarFunctions: " + << Index.getSimilarFunctions().size()); + + auto &SimFunctions = Index.getSimilarFunctions(); + // Shouldn't have entries with hash of 0, because those are placeholders. + assert(!SimFunctions.count(0)); + auto &HostSimFunction = Index.getHostSimilarFunction(); + for (auto I = SimFunctions.begin(), E = SimFunctions.end(); I != E; ++I) { + // Make the first of all similar functions as host. + HostSimFunction.insert(I->second[0]); + } + LLVM_DEBUG(llvm::errs() << "\nSize getHostSimilarFunction: " + << Index.getHostSimilarFunction().size()); + return; +} + bool MergeSimilarFunctions::runOnModule(Module &M) { if (Opt::MergeLevel == Opt::none) return false; Index: lib/Transforms/IPO/PassManagerBuilder.cpp =================================================================== --- lib/Transforms/IPO/PassManagerBuilder.cpp +++ lib/Transforms/IPO/PassManagerBuilder.cpp @@ -159,7 +159,7 @@ EnableCHR("enable-chr", cl::init(true), cl::Hidden, cl::desc("Enable control height reduction optimization (CHR)")); -static cl::opt EnableMergeSimilarFunctions( +cl::opt EnableMergeSimilarFunctions( "enable-merge-sim-functions", cl::init(false), cl::Hidden, cl::desc("Enable the Function merging pass (default = on)"));