xref: /llvm-project/llvm/lib/CGData/StableFunctionMap.cpp (revision d23c5c2d6566fce4380cfa31d438422db19fbce9)
17ec26b23SKyungwoo Lee //===-- StableFunctionMap.cpp ---------------------------------------------===//
27ec26b23SKyungwoo Lee //
37ec26b23SKyungwoo Lee // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47ec26b23SKyungwoo Lee // See https://llvm.org/LICENSE.txt for license information.
57ec26b23SKyungwoo Lee // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67ec26b23SKyungwoo Lee //
77ec26b23SKyungwoo Lee //===----------------------------------------------------------------------===//
87ec26b23SKyungwoo Lee //
97ec26b23SKyungwoo Lee // This implements the functionality for the StableFunctionMap class, which
107ec26b23SKyungwoo Lee // manages the mapping of stable function hashes to their metadata. It includes
117ec26b23SKyungwoo Lee // methods for inserting, merging, and finalizing function entries, as well as
127ec26b23SKyungwoo Lee // utilities for handling function names and IDs.
137ec26b23SKyungwoo Lee //
147ec26b23SKyungwoo Lee //===----------------------------------------------------------------------===//
157ec26b23SKyungwoo Lee 
167ec26b23SKyungwoo Lee #include "llvm/CGData/StableFunctionMap.h"
17*d23c5c2dSKyungwoo Lee #include "llvm/Support/CommandLine.h"
18*d23c5c2dSKyungwoo Lee #include "llvm/Support/Debug.h"
197ec26b23SKyungwoo Lee 
207ec26b23SKyungwoo Lee #define DEBUG_TYPE "stable-function-map"
217ec26b23SKyungwoo Lee 
227ec26b23SKyungwoo Lee using namespace llvm;
237ec26b23SKyungwoo Lee 
24*d23c5c2dSKyungwoo Lee static cl::opt<unsigned>
25*d23c5c2dSKyungwoo Lee     GlobalMergingMinMerges("global-merging-min-merges",
26*d23c5c2dSKyungwoo Lee                            cl::desc("Minimum number of similar functions with "
27*d23c5c2dSKyungwoo Lee                                     "the same hash required for merging."),
28*d23c5c2dSKyungwoo Lee                            cl::init(2), cl::Hidden);
29*d23c5c2dSKyungwoo Lee static cl::opt<unsigned> GlobalMergingMinInstrs(
30*d23c5c2dSKyungwoo Lee     "global-merging-min-instrs",
31*d23c5c2dSKyungwoo Lee     cl::desc("The minimum instruction count required when merging functions."),
32*d23c5c2dSKyungwoo Lee     cl::init(1), cl::Hidden);
33*d23c5c2dSKyungwoo Lee static cl::opt<unsigned> GlobalMergingMaxParams(
34*d23c5c2dSKyungwoo Lee     "global-merging-max-params",
35*d23c5c2dSKyungwoo Lee     cl::desc(
36*d23c5c2dSKyungwoo Lee         "The maximum number of parameters allowed when merging functions."),
37*d23c5c2dSKyungwoo Lee     cl::init(std::numeric_limits<unsigned>::max()), cl::Hidden);
38*d23c5c2dSKyungwoo Lee static cl::opt<unsigned> GlobalMergingParamOverhead(
39*d23c5c2dSKyungwoo Lee     "global-merging-param-overhead",
40*d23c5c2dSKyungwoo Lee     cl::desc("The overhead cost associated with each parameter when merging "
41*d23c5c2dSKyungwoo Lee              "functions."),
42*d23c5c2dSKyungwoo Lee     cl::init(2), cl::Hidden);
43*d23c5c2dSKyungwoo Lee static cl::opt<unsigned>
44*d23c5c2dSKyungwoo Lee     GlobalMergingCallOverhead("global-merging-call-overhead",
45*d23c5c2dSKyungwoo Lee                               cl::desc("The overhead cost associated with each "
46*d23c5c2dSKyungwoo Lee                                        "function call when merging functions."),
47*d23c5c2dSKyungwoo Lee                               cl::init(1), cl::Hidden);
48*d23c5c2dSKyungwoo Lee static cl::opt<unsigned> GlobalMergingExtraThreshold(
49*d23c5c2dSKyungwoo Lee     "global-merging-extra-threshold",
50*d23c5c2dSKyungwoo Lee     cl::desc("An additional cost threshold that must be exceeded for merging "
51*d23c5c2dSKyungwoo Lee              "to be considered beneficial."),
52*d23c5c2dSKyungwoo Lee     cl::init(0), cl::Hidden);
53*d23c5c2dSKyungwoo Lee 
547ec26b23SKyungwoo Lee unsigned StableFunctionMap::getIdOrCreateForName(StringRef Name) {
557ec26b23SKyungwoo Lee   auto It = NameToId.find(Name);
567ec26b23SKyungwoo Lee   if (It != NameToId.end())
577ec26b23SKyungwoo Lee     return It->second;
587ec26b23SKyungwoo Lee   unsigned Id = IdToName.size();
597ec26b23SKyungwoo Lee   assert(Id == NameToId.size() && "ID collision");
607ec26b23SKyungwoo Lee   IdToName.emplace_back(Name.str());
617ec26b23SKyungwoo Lee   NameToId[IdToName.back()] = Id;
627ec26b23SKyungwoo Lee   return Id;
637ec26b23SKyungwoo Lee }
647ec26b23SKyungwoo Lee 
657ec26b23SKyungwoo Lee std::optional<std::string> StableFunctionMap::getNameForId(unsigned Id) const {
667ec26b23SKyungwoo Lee   if (Id >= IdToName.size())
677ec26b23SKyungwoo Lee     return std::nullopt;
687ec26b23SKyungwoo Lee   return IdToName[Id];
697ec26b23SKyungwoo Lee }
707ec26b23SKyungwoo Lee 
717ec26b23SKyungwoo Lee void StableFunctionMap::insert(const StableFunction &Func) {
727ec26b23SKyungwoo Lee   assert(!Finalized && "Cannot insert after finalization");
737ec26b23SKyungwoo Lee   auto FuncNameId = getIdOrCreateForName(Func.FunctionName);
747ec26b23SKyungwoo Lee   auto ModuleNameId = getIdOrCreateForName(Func.ModuleName);
757ec26b23SKyungwoo Lee   auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
767ec26b23SKyungwoo Lee   for (auto &[Index, Hash] : Func.IndexOperandHashes)
777ec26b23SKyungwoo Lee     (*IndexOperandHashMap)[Index] = Hash;
787ec26b23SKyungwoo Lee   auto FuncEntry = std::make_unique<StableFunctionEntry>(
797ec26b23SKyungwoo Lee       Func.Hash, FuncNameId, ModuleNameId, Func.InstCount,
807ec26b23SKyungwoo Lee       std::move(IndexOperandHashMap));
817ec26b23SKyungwoo Lee   insert(std::move(FuncEntry));
827ec26b23SKyungwoo Lee }
837ec26b23SKyungwoo Lee 
847ec26b23SKyungwoo Lee void StableFunctionMap::merge(const StableFunctionMap &OtherMap) {
857ec26b23SKyungwoo Lee   assert(!Finalized && "Cannot merge after finalization");
867ec26b23SKyungwoo Lee   for (auto &[Hash, Funcs] : OtherMap.HashToFuncs) {
877ec26b23SKyungwoo Lee     auto &ThisFuncs = HashToFuncs[Hash];
887ec26b23SKyungwoo Lee     for (auto &Func : Funcs) {
897ec26b23SKyungwoo Lee       auto FuncNameId =
907ec26b23SKyungwoo Lee           getIdOrCreateForName(*OtherMap.getNameForId(Func->FunctionNameId));
917ec26b23SKyungwoo Lee       auto ModuleNameId =
927ec26b23SKyungwoo Lee           getIdOrCreateForName(*OtherMap.getNameForId(Func->ModuleNameId));
937ec26b23SKyungwoo Lee       auto ClonedIndexOperandHashMap =
947ec26b23SKyungwoo Lee           std::make_unique<IndexOperandHashMapType>(*Func->IndexOperandHashMap);
957ec26b23SKyungwoo Lee       ThisFuncs.emplace_back(std::make_unique<StableFunctionEntry>(
967ec26b23SKyungwoo Lee           Func->Hash, FuncNameId, ModuleNameId, Func->InstCount,
977ec26b23SKyungwoo Lee           std::move(ClonedIndexOperandHashMap)));
987ec26b23SKyungwoo Lee     }
997ec26b23SKyungwoo Lee   }
1007ec26b23SKyungwoo Lee }
1017ec26b23SKyungwoo Lee 
1027ec26b23SKyungwoo Lee size_t StableFunctionMap::size(SizeType Type) const {
1037ec26b23SKyungwoo Lee   switch (Type) {
1047ec26b23SKyungwoo Lee   case UniqueHashCount:
1057ec26b23SKyungwoo Lee     return HashToFuncs.size();
1067ec26b23SKyungwoo Lee   case TotalFunctionCount: {
1077ec26b23SKyungwoo Lee     size_t Count = 0;
1087ec26b23SKyungwoo Lee     for (auto &Funcs : HashToFuncs)
1097ec26b23SKyungwoo Lee       Count += Funcs.second.size();
1107ec26b23SKyungwoo Lee     return Count;
1117ec26b23SKyungwoo Lee   }
1127ec26b23SKyungwoo Lee   case MergeableFunctionCount: {
1137ec26b23SKyungwoo Lee     size_t Count = 0;
1147ec26b23SKyungwoo Lee     for (auto &[Hash, Funcs] : HashToFuncs)
1157ec26b23SKyungwoo Lee       if (Funcs.size() >= 2)
1167ec26b23SKyungwoo Lee         Count += Funcs.size();
1177ec26b23SKyungwoo Lee     return Count;
1187ec26b23SKyungwoo Lee   }
1197ec26b23SKyungwoo Lee   }
1207ec26b23SKyungwoo Lee   llvm_unreachable("Unhandled size type");
1217ec26b23SKyungwoo Lee }
1227ec26b23SKyungwoo Lee 
1237ec26b23SKyungwoo Lee using ParamLocs = SmallVector<IndexPair>;
1247ec26b23SKyungwoo Lee static void removeIdenticalIndexPair(
1257ec26b23SKyungwoo Lee     SmallVector<std::unique_ptr<StableFunctionMap::StableFunctionEntry>> &SFS) {
1267ec26b23SKyungwoo Lee   auto &RSF = SFS[0];
1277ec26b23SKyungwoo Lee   unsigned StableFunctionCount = SFS.size();
1287ec26b23SKyungwoo Lee 
1297ec26b23SKyungwoo Lee   SmallVector<IndexPair> ToDelete;
1307ec26b23SKyungwoo Lee   for (auto &[Pair, Hash] : *(RSF->IndexOperandHashMap)) {
1317ec26b23SKyungwoo Lee     bool Identical = true;
1327ec26b23SKyungwoo Lee     for (unsigned J = 1; J < StableFunctionCount; ++J) {
1337ec26b23SKyungwoo Lee       auto &SF = SFS[J];
1347ec26b23SKyungwoo Lee       const auto &SHash = SF->IndexOperandHashMap->at(Pair);
1357ec26b23SKyungwoo Lee       if (Hash != SHash) {
1367ec26b23SKyungwoo Lee         Identical = false;
1377ec26b23SKyungwoo Lee         break;
1387ec26b23SKyungwoo Lee       }
1397ec26b23SKyungwoo Lee     }
1407ec26b23SKyungwoo Lee 
1417ec26b23SKyungwoo Lee     // No need to parameterize them if the hashes are identical across stable
1427ec26b23SKyungwoo Lee     // functions.
1437ec26b23SKyungwoo Lee     if (Identical)
1447ec26b23SKyungwoo Lee       ToDelete.emplace_back(Pair);
1457ec26b23SKyungwoo Lee   }
1467ec26b23SKyungwoo Lee 
1477ec26b23SKyungwoo Lee   for (auto &Pair : ToDelete)
1487ec26b23SKyungwoo Lee     for (auto &SF : SFS)
1497ec26b23SKyungwoo Lee       SF->IndexOperandHashMap->erase(Pair);
1507ec26b23SKyungwoo Lee }
1517ec26b23SKyungwoo Lee 
152*d23c5c2dSKyungwoo Lee static bool isProfitable(
153*d23c5c2dSKyungwoo Lee     const SmallVector<std::unique_ptr<StableFunctionMap::StableFunctionEntry>>
154*d23c5c2dSKyungwoo Lee         &SFS) {
155*d23c5c2dSKyungwoo Lee   unsigned StableFunctionCount = SFS.size();
156*d23c5c2dSKyungwoo Lee   if (StableFunctionCount < GlobalMergingMinMerges)
157*d23c5c2dSKyungwoo Lee     return false;
158*d23c5c2dSKyungwoo Lee 
159*d23c5c2dSKyungwoo Lee   unsigned InstCount = SFS[0]->InstCount;
160*d23c5c2dSKyungwoo Lee   if (InstCount < GlobalMergingMinInstrs)
161*d23c5c2dSKyungwoo Lee     return false;
162*d23c5c2dSKyungwoo Lee 
163*d23c5c2dSKyungwoo Lee   unsigned ParamCount = SFS[0]->IndexOperandHashMap->size();
164*d23c5c2dSKyungwoo Lee   if (ParamCount > GlobalMergingMaxParams)
165*d23c5c2dSKyungwoo Lee     return false;
166*d23c5c2dSKyungwoo Lee 
167*d23c5c2dSKyungwoo Lee   unsigned Benefit = InstCount * (StableFunctionCount - 1);
168*d23c5c2dSKyungwoo Lee   unsigned Cost =
169*d23c5c2dSKyungwoo Lee       (GlobalMergingParamOverhead * ParamCount + GlobalMergingCallOverhead) *
170*d23c5c2dSKyungwoo Lee           StableFunctionCount +
171*d23c5c2dSKyungwoo Lee       GlobalMergingExtraThreshold;
172*d23c5c2dSKyungwoo Lee 
173*d23c5c2dSKyungwoo Lee   bool Result = Benefit > Cost;
174*d23c5c2dSKyungwoo Lee   LLVM_DEBUG(dbgs() << "isProfitable: Hash = " << SFS[0]->Hash << ", "
175*d23c5c2dSKyungwoo Lee                     << "StableFunctionCount = " << StableFunctionCount
176*d23c5c2dSKyungwoo Lee                     << ", InstCount = " << InstCount
177*d23c5c2dSKyungwoo Lee                     << ", ParamCount = " << ParamCount
178*d23c5c2dSKyungwoo Lee                     << ", Benefit = " << Benefit << ", Cost = " << Cost
179*d23c5c2dSKyungwoo Lee                     << ", Result = " << (Result ? "true" : "false") << "\n");
180*d23c5c2dSKyungwoo Lee   return Result;
181*d23c5c2dSKyungwoo Lee }
182*d23c5c2dSKyungwoo Lee 
183*d23c5c2dSKyungwoo Lee void StableFunctionMap::finalize(bool SkipTrim) {
1847ec26b23SKyungwoo Lee   for (auto It = HashToFuncs.begin(); It != HashToFuncs.end(); ++It) {
1857ec26b23SKyungwoo Lee     auto &[StableHash, SFS] = *It;
1867ec26b23SKyungwoo Lee 
1877ec26b23SKyungwoo Lee     // Group stable functions by ModuleIdentifier.
1887ec26b23SKyungwoo Lee     std::stable_sort(SFS.begin(), SFS.end(),
1897ec26b23SKyungwoo Lee                      [&](const std::unique_ptr<StableFunctionEntry> &L,
1907ec26b23SKyungwoo Lee                          const std::unique_ptr<StableFunctionEntry> &R) {
1917ec26b23SKyungwoo Lee                        return *getNameForId(L->ModuleNameId) <
1927ec26b23SKyungwoo Lee                               *getNameForId(R->ModuleNameId);
1937ec26b23SKyungwoo Lee                      });
1947ec26b23SKyungwoo Lee 
1957ec26b23SKyungwoo Lee     // Consider the first function as the root function.
1967ec26b23SKyungwoo Lee     auto &RSF = SFS[0];
1977ec26b23SKyungwoo Lee 
1987ec26b23SKyungwoo Lee     bool Invalid = false;
1997ec26b23SKyungwoo Lee     unsigned StableFunctionCount = SFS.size();
2007ec26b23SKyungwoo Lee     for (unsigned I = 1; I < StableFunctionCount; ++I) {
2017ec26b23SKyungwoo Lee       auto &SF = SFS[I];
2027ec26b23SKyungwoo Lee       assert(RSF->Hash == SF->Hash);
2037ec26b23SKyungwoo Lee       if (RSF->InstCount != SF->InstCount) {
2047ec26b23SKyungwoo Lee         Invalid = true;
2057ec26b23SKyungwoo Lee         break;
2067ec26b23SKyungwoo Lee       }
2077ec26b23SKyungwoo Lee       if (RSF->IndexOperandHashMap->size() != SF->IndexOperandHashMap->size()) {
2087ec26b23SKyungwoo Lee         Invalid = true;
2097ec26b23SKyungwoo Lee         break;
2107ec26b23SKyungwoo Lee       }
2117ec26b23SKyungwoo Lee       for (auto &P : *RSF->IndexOperandHashMap) {
2127ec26b23SKyungwoo Lee         auto &InstOpndIndex = P.first;
2137ec26b23SKyungwoo Lee         if (!SF->IndexOperandHashMap->count(InstOpndIndex)) {
2147ec26b23SKyungwoo Lee           Invalid = true;
2157ec26b23SKyungwoo Lee           break;
2167ec26b23SKyungwoo Lee         }
2177ec26b23SKyungwoo Lee       }
2187ec26b23SKyungwoo Lee     }
2197ec26b23SKyungwoo Lee     if (Invalid) {
2207ec26b23SKyungwoo Lee       HashToFuncs.erase(It);
2217ec26b23SKyungwoo Lee       continue;
2227ec26b23SKyungwoo Lee     }
2237ec26b23SKyungwoo Lee 
224*d23c5c2dSKyungwoo Lee     if (SkipTrim)
225*d23c5c2dSKyungwoo Lee       continue;
226*d23c5c2dSKyungwoo Lee 
2277ec26b23SKyungwoo Lee     // Trim the index pair that has the same operand hash across
2287ec26b23SKyungwoo Lee     // stable functions.
2297ec26b23SKyungwoo Lee     removeIdenticalIndexPair(SFS);
230*d23c5c2dSKyungwoo Lee 
231*d23c5c2dSKyungwoo Lee     if (!isProfitable(SFS))
232*d23c5c2dSKyungwoo Lee       HashToFuncs.erase(It);
2337ec26b23SKyungwoo Lee   }
2347ec26b23SKyungwoo Lee 
2357ec26b23SKyungwoo Lee   Finalized = true;
2367ec26b23SKyungwoo Lee }
237