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