1//===-- StableFunctionMap.cpp ---------------------------------------------===// 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 7//===----------------------------------------------------------------------===// 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. 14//===----------------------------------------------------------------------===// 21#define DEBUG_TYPE "stable-function-map" 27cl::desc(
"Minimum number of similar functions with " 28"the same hash required for merging."),
31"global-merging-min-instrs",
32cl::desc(
"The minimum instruction count required when merging functions."),
35"global-merging-max-params",
37"The maximum number of parameters allowed when merging functions."),
40"global-merging-skip-no-params",
44"global-merging-inst-overhead",
45cl::desc(
"The overhead cost associated with each instruction when lowering " 46"to machine instruction."),
49"global-merging-param-overhead",
50cl::desc(
"The overhead cost associated with each parameter when merging " 55cl::desc(
"The overhead cost associated with each " 56"function call when merging functions."),
59"global-merging-extra-threshold",
60cl::desc(
"An additional cost threshold that must be exceeded for merging " 61"to be considered beneficial."),
66if (It != NameToId.
end())
68unsigned Id = IdToName.
size();
71 NameToId[IdToName.
back()] = Id;
76if (Id >= IdToName.
size())
82assert(!Finalized &&
"Cannot insert after finalization");
85auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
86for (
auto &[Index, Hash] : Func.IndexOperandHashes)
87 (*IndexOperandHashMap)[Index] = Hash;
88auto FuncEntry = std::make_unique<StableFunctionEntry>(
89 Func.Hash, FuncNameId, ModuleNameId, Func.InstCount,
90 std::move(IndexOperandHashMap));
91insert(std::move(FuncEntry));
95assert(!Finalized &&
"Cannot merge after finalization");
96for (
auto &[Hash, Funcs] : OtherMap.HashToFuncs) {
97auto &ThisFuncs = HashToFuncs[Hash];
98for (
auto &Func : Funcs) {
103auto ClonedIndexOperandHashMap =
104 std::make_unique<IndexOperandHashMapType>(*Func->IndexOperandHashMap);
105 ThisFuncs.emplace_back(std::make_unique<StableFunctionEntry>(
106 Func->Hash, FuncNameId, ModuleNameId, Func->InstCount,
107 std::move(ClonedIndexOperandHashMap)));
115return HashToFuncs.
size();
118for (
auto &Funcs : HashToFuncs)
119 Count += Funcs.second.size();
124for (
auto &[Hash, Funcs] : HashToFuncs)
125if (Funcs.size() >= 2)
126 Count += Funcs.size();
135SmallVector<std::unique_ptr<StableFunctionMap::StableFunctionEntry>> &SFS) {
137unsigned StableFunctionCount = SFS.size();
140for (
auto &[Pair, Hash] : *(RSF->IndexOperandHashMap)) {
142for (
unsigned J = 1; J < StableFunctionCount; ++J) {
144constauto &SHash = SF->IndexOperandHashMap->at(Pair);
151// No need to parameterize them if the hashes are identical across stable 157for (
auto &Pair : ToDelete)
159 SF->IndexOperandHashMap->erase(Pair);
163constSmallVector<std::unique_ptr<StableFunctionMap::StableFunctionEntry>>
165unsigned StableFunctionCount = SFS.size();
169unsigned InstCount = SFS[0]->InstCount;
175for (
auto &SF : SFS) {
176 UniqueHashVals.
clear();
177for (
auto &[
IndexPair, Hash] : *SF->IndexOperandHashMap)
178 UniqueHashVals.
insert(Hash);
179unsigned ParamCount = UniqueHashVals.
size();
182// Theoretically, if ParamCount is 0, it results in identical code folding 183// (ICF), which we can skip merging here since the linker already handles 184// ICF. This pass would otherwise introduce unnecessary thunks that are 185// merely direct jumps. However, enabling this could be beneficial depending 186// on downstream passes, so we provide an option for it. 195bool Result = Benefit >
Cost;
197 <<
"StableFunctionCount = " << StableFunctionCount
198 <<
", InstCount = " << InstCount
199 <<
", Benefit = " << Benefit <<
", Cost = " <<
Cost 200 <<
", Result = " << (Result ?
"true" :
"false") <<
"\n");
205for (
auto It = HashToFuncs.
begin(); It != HashToFuncs.
end(); ++It) {
206auto &[StableHash, SFS] = *It;
208// Group stable functions by ModuleIdentifier. 209 std::stable_sort(SFS.begin(), SFS.end(),
210 [&](
const std::unique_ptr<StableFunctionEntry> &L,
211const std::unique_ptr<StableFunctionEntry> &R) {
212 return *getNameForId(L->ModuleNameId) <
213 *getNameForId(R->ModuleNameId);
216// Consider the first function as the root function. 220unsigned StableFunctionCount = SFS.size();
221for (
unsignedI = 1;
I < StableFunctionCount; ++
I) {
223assert(RSF->Hash == SF->Hash);
224if (RSF->InstCount != SF->InstCount) {
228if (RSF->IndexOperandHashMap->size() != SF->IndexOperandHashMap->size()) {
232for (
auto &
P : *RSF->IndexOperandHashMap) {
233auto &InstOpndIndex =
P.first;
234if (!SF->IndexOperandHashMap->count(InstOpndIndex)) {
241 HashToFuncs.
erase(It);
248// Trim the index pair that has the same operand hash across 253 HashToFuncs.
erase(It);
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallSet class.
static bool isProfitable(const SmallVector< std::unique_ptr< StableFunctionMap::StableFunctionEntry > > &SFS)
static void removeIdenticalIndexPair(SmallVector< std::unique_ptr< StableFunctionMap::StableFunctionEntry > > &SFS)
static cl::opt< bool > GlobalMergingSkipNoParams("global-merging-skip-no-params", cl::desc("Skip merging functions with no parameters."), cl::init(true), cl::Hidden)
static cl::opt< double > GlobalMergingParamOverhead("global-merging-param-overhead", cl::desc("The overhead cost associated with each parameter when merging " "functions."), cl::init(2.0), cl::Hidden)
static cl::opt< unsigned > GlobalMergingMinMerges("global-merging-min-merges", cl::desc("Minimum number of similar functions with " "the same hash required for merging."), cl::init(2), cl::Hidden)
static cl::opt< double > GlobalMergingInstOverhead("global-merging-inst-overhead", cl::desc("The overhead cost associated with each instruction when lowering " "to machine instruction."), cl::init(1.2), cl::Hidden)
static cl::opt< double > GlobalMergingCallOverhead("global-merging-call-overhead", cl::desc("The overhead cost associated with each " "function call when merging functions."), cl::init(1.0), cl::Hidden)
static cl::opt< unsigned > GlobalMergingMaxParams("global-merging-max-params", cl::desc("The maximum number of parameters allowed when merging functions."), cl::init(std::numeric_limits< unsigned >::max()), cl::Hidden)
static cl::opt< unsigned > GlobalMergingMinInstrs("global-merging-min-instrs", cl::desc("The minimum instruction count required when merging functions."), cl::init(1), cl::Hidden)
static cl::opt< double > GlobalMergingExtraThreshold("global-merging-extra-threshold", cl::desc("An additional cost threshold that must be exceeded for merging " "to be considered beneficial."), cl::init(0.0), cl::Hidden)
bool erase(const KeyT &Val)
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
iterator find(StringRef Key)
StringRef - Represent a constant reference to a string, i.e.
The instances of the Type class are immutable: once they are created, they are never changed.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
std::pair< unsigned, unsigned > IndexPair
The pair of an instruction index and a operand index.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void finalize(bool SkipTrim=false)
Finalize the stable function map by trimming content.
size_t size(SizeType Type=UniqueHashCount) const
void insert(const StableFunction &Func)
Insert a StableFunction object into the function map.
void merge(const StableFunctionMap &OtherMap)
Merge a OtherMap into this function map.
std::optional< std::string > getNameForId(unsigned Id) const
Get the name associated with a given ID.
unsigned getIdOrCreateForName(StringRef Name)
Get an existing ID associated with the given name or create a new ID if it doesn't exist.
A stable function is a function with a stable hash while tracking the locations of ignored operands a...