xref: /llvm-project/llvm/lib/CGData/StableFunctionMap.cpp (revision 7ec26b23f27f2adfe6847bc69debb84efa34ed08)
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