1 //===-- StableFunctionMap.cpp ---------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This implements the functionality for the StableFunctionMap class, which 10 // manages the mapping of stable function hashes to their metadata. It includes 11 // methods for inserting, merging, and finalizing function entries, as well as 12 // utilities for handling function names and IDs. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/CGData/StableFunctionMap.h" 17 18 #define DEBUG_TYPE "stable-function-map" 19 20 using namespace llvm; 21 22 unsigned StableFunctionMap::getIdOrCreateForName(StringRef Name) { 23 auto It = NameToId.find(Name); 24 if (It != NameToId.end()) 25 return It->second; 26 unsigned Id = IdToName.size(); 27 assert(Id == NameToId.size() && "ID collision"); 28 IdToName.emplace_back(Name.str()); 29 NameToId[IdToName.back()] = Id; 30 return Id; 31 } 32 33 std::optional<std::string> StableFunctionMap::getNameForId(unsigned Id) const { 34 if (Id >= IdToName.size()) 35 return std::nullopt; 36 return IdToName[Id]; 37 } 38 39 void StableFunctionMap::insert(const StableFunction &Func) { 40 assert(!Finalized && "Cannot insert after finalization"); 41 auto FuncNameId = getIdOrCreateForName(Func.FunctionName); 42 auto ModuleNameId = getIdOrCreateForName(Func.ModuleName); 43 auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>(); 44 for (auto &[Index, Hash] : Func.IndexOperandHashes) 45 (*IndexOperandHashMap)[Index] = Hash; 46 auto FuncEntry = std::make_unique<StableFunctionEntry>( 47 Func.Hash, FuncNameId, ModuleNameId, Func.InstCount, 48 std::move(IndexOperandHashMap)); 49 insert(std::move(FuncEntry)); 50 } 51 52 void StableFunctionMap::merge(const StableFunctionMap &OtherMap) { 53 assert(!Finalized && "Cannot merge after finalization"); 54 for (auto &[Hash, Funcs] : OtherMap.HashToFuncs) { 55 auto &ThisFuncs = HashToFuncs[Hash]; 56 for (auto &Func : Funcs) { 57 auto FuncNameId = 58 getIdOrCreateForName(*OtherMap.getNameForId(Func->FunctionNameId)); 59 auto ModuleNameId = 60 getIdOrCreateForName(*OtherMap.getNameForId(Func->ModuleNameId)); 61 auto ClonedIndexOperandHashMap = 62 std::make_unique<IndexOperandHashMapType>(*Func->IndexOperandHashMap); 63 ThisFuncs.emplace_back(std::make_unique<StableFunctionEntry>( 64 Func->Hash, FuncNameId, ModuleNameId, Func->InstCount, 65 std::move(ClonedIndexOperandHashMap))); 66 } 67 } 68 } 69 70 size_t StableFunctionMap::size(SizeType Type) const { 71 switch (Type) { 72 case UniqueHashCount: 73 return HashToFuncs.size(); 74 case TotalFunctionCount: { 75 size_t Count = 0; 76 for (auto &Funcs : HashToFuncs) 77 Count += Funcs.second.size(); 78 return Count; 79 } 80 case MergeableFunctionCount: { 81 size_t Count = 0; 82 for (auto &[Hash, Funcs] : HashToFuncs) 83 if (Funcs.size() >= 2) 84 Count += Funcs.size(); 85 return Count; 86 } 87 } 88 llvm_unreachable("Unhandled size type"); 89 } 90 91 using ParamLocs = SmallVector<IndexPair>; 92 static void removeIdenticalIndexPair( 93 SmallVector<std::unique_ptr<StableFunctionMap::StableFunctionEntry>> &SFS) { 94 auto &RSF = SFS[0]; 95 unsigned StableFunctionCount = SFS.size(); 96 97 SmallVector<IndexPair> ToDelete; 98 for (auto &[Pair, Hash] : *(RSF->IndexOperandHashMap)) { 99 bool Identical = true; 100 for (unsigned J = 1; J < StableFunctionCount; ++J) { 101 auto &SF = SFS[J]; 102 const auto &SHash = SF->IndexOperandHashMap->at(Pair); 103 if (Hash != SHash) { 104 Identical = false; 105 break; 106 } 107 } 108 109 // No need to parameterize them if the hashes are identical across stable 110 // functions. 111 if (Identical) 112 ToDelete.emplace_back(Pair); 113 } 114 115 for (auto &Pair : ToDelete) 116 for (auto &SF : SFS) 117 SF->IndexOperandHashMap->erase(Pair); 118 } 119 120 void StableFunctionMap::finalize() { 121 for (auto It = HashToFuncs.begin(); It != HashToFuncs.end(); ++It) { 122 auto &[StableHash, SFS] = *It; 123 124 // Group stable functions by ModuleIdentifier. 125 std::stable_sort(SFS.begin(), SFS.end(), 126 [&](const std::unique_ptr<StableFunctionEntry> &L, 127 const std::unique_ptr<StableFunctionEntry> &R) { 128 return *getNameForId(L->ModuleNameId) < 129 *getNameForId(R->ModuleNameId); 130 }); 131 132 // Consider the first function as the root function. 133 auto &RSF = SFS[0]; 134 135 bool Invalid = false; 136 unsigned StableFunctionCount = SFS.size(); 137 for (unsigned I = 1; I < StableFunctionCount; ++I) { 138 auto &SF = SFS[I]; 139 assert(RSF->Hash == SF->Hash); 140 if (RSF->InstCount != SF->InstCount) { 141 Invalid = true; 142 break; 143 } 144 if (RSF->IndexOperandHashMap->size() != SF->IndexOperandHashMap->size()) { 145 Invalid = true; 146 break; 147 } 148 for (auto &P : *RSF->IndexOperandHashMap) { 149 auto &InstOpndIndex = P.first; 150 if (!SF->IndexOperandHashMap->count(InstOpndIndex)) { 151 Invalid = true; 152 break; 153 } 154 } 155 } 156 if (Invalid) { 157 HashToFuncs.erase(It); 158 continue; 159 } 160 161 // Trim the index pair that has the same operand hash across 162 // stable functions. 163 removeIdenticalIndexPair(SFS); 164 } 165 166 Finalized = true; 167 } 168