22#define DEBUG_TYPE "stable-function-map"
27 auto It = NameToId.find(Name);
28 if (It != NameToId.end())
30 unsigned Id = IdToName.size();
31 assert(Id == NameToId.size() &&
"ID collision");
32 IdToName.emplace_back(Name.str());
33 NameToId[IdToName.back()] = Id;
38 if (Id >= IdToName.size())
44 assert(!Finalized &&
"Cannot insert after finalization");
47 auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
48 for (
auto &[Index, Hash] : Func.IndexOperandHashes)
49 (*IndexOperandHashMap)[Index] = Hash;
50 auto FuncEntry = std::make_unique<StableFunctionEntry>(
51 Func.Hash, FuncNameId, ModuleNameId, Func.InstCount,
52 std::move(IndexOperandHashMap));
53 insert(std::move(FuncEntry));
57 assert(!Finalized &&
"Cannot merge after finalization");
58 deserializeLazyLoadingEntries();
59 for (
auto &[Hash, Funcs] : OtherMap.HashToFuncs) {
60 auto &ThisFuncs = HashToFuncs[Hash].Entries;
61 for (
auto &Func : Funcs.Entries) {
66 auto ClonedIndexOperandHashMap =
67 std::make_unique<IndexOperandHashMapType>(*Func->IndexOperandHashMap);
68 ThisFuncs.emplace_back(std::make_unique<StableFunctionEntry>(
69 Func->Hash, FuncNameId, ModuleNameId, Func->InstCount,
70 std::move(ClonedIndexOperandHashMap)));
78 return HashToFuncs.size();
80 deserializeLazyLoadingEntries();
82 for (
auto &Funcs : HashToFuncs)
83 Count += Funcs.second.Entries.size();
87 deserializeLazyLoadingEntries();
89 for (
auto &[Hash, Funcs] : HashToFuncs)
90 if (Funcs.Entries.size() >= 2)
91 Count += Funcs.Entries.size();
100 auto It = HashToFuncs.find(FunctionHash);
101 assert(It != HashToFuncs.end() &&
"FunctionHash not found!");
102 if (isLazilyLoaded())
103 deserializeLazyLoadingEntry(It);
104 return It->second.Entries;
107void StableFunctionMap::deserializeLazyLoadingEntry(
108 HashFuncsMapType::iterator It)
const {
109 assert(isLazilyLoaded() &&
"Cannot deserialize non-lazily-loaded map");
110 auto &[Hash, Storage] = *It;
111 std::call_once(Storage.LazyLoadFlag,
112 [
this, HashArg = Hash, &StorageArg = Storage]() {
113 for (auto Offset : StorageArg.Offsets)
114 StableFunctionMapRecord::deserializeEntry(
115 reinterpret_cast<const unsigned char *>(Offset),
116 HashArg, const_cast<StableFunctionMap *>(this));
120void StableFunctionMap::deserializeLazyLoadingEntries()
const {
121 if (!isLazilyLoaded())
123 for (
auto It = HashToFuncs.begin(); It != HashToFuncs.end(); ++It)
124 deserializeLazyLoadingEntry(It);
130 if (isLazilyLoaded())
131 deserializeLazyLoadingEntries();
139 unsigned StableFunctionCount = SFS.
size();
142 for (
auto &[Pair, Hash] : *(RSF->IndexOperandHashMap)) {
143 bool Identical =
true;
144 for (
unsigned J = 1; J < StableFunctionCount; ++J) {
146 const auto &SHash = SF->IndexOperandHashMap->at(Pair);
159 for (
auto &Pair : ToDelete)
161 SF->IndexOperandHashMap->
erase(Pair);
165 const CGDataOptions &Opts = CGDataOptions::Global;
166 unsigned StableFunctionCount = SFS.
size();
167 if (StableFunctionCount < Opts.global_merging_min_merges)
170 unsigned InstCount = SFS[0]->InstCount;
171 if (InstCount < Opts.global_merging_min_instrs)
176 for (
auto &SF : SFS) {
177 UniqueHashVals.
clear();
178 for (
auto &[
IndexPair, Hash] : *SF->IndexOperandHashMap)
179 UniqueHashVals.
insert(Hash);
180 unsigned ParamCount = UniqueHashVals.
size();
181 if (ParamCount > Opts.global_merging_max_params)
188 if (Opts.global_merging_skip_no_params && ParamCount == 0)
190 Cost += ParamCount * Opts.global_merging_param_overhead +
191 Opts.global_merging_call_overhead;
193 Cost += Opts.global_merging_extra_threshold;
196 InstCount * (StableFunctionCount - 1) * Opts.global_merging_inst_overhead;
197 bool Result = Benefit > Cost;
198 LLVM_DEBUG(
dbgs() <<
"isProfitable: Hash = " << SFS[0]->Hash <<
", "
199 <<
"StableFunctionCount = " << StableFunctionCount
200 <<
", InstCount = " << InstCount
201 <<
", Benefit = " << Benefit <<
", Cost = " << Cost
202 <<
", Result = " << (Result ?
"true" :
"false") <<
"\n");
207 deserializeLazyLoadingEntries();
209 for (
auto It = HashToFuncs.begin(); It != HashToFuncs.end(); ++It) {
210 auto &[StableHash, Storage] = *It;
211 auto &SFS = Storage.Entries;
215 const std::unique_ptr<StableFunctionEntry> &R) {
223 unsigned StableFunctionCount = SFS.size();
224 for (
unsigned I = 1;
I < StableFunctionCount; ++
I) {
226 assert(RSF->Hash == SF->Hash);
227 if (RSF->InstCount != SF->InstCount) {
231 if (RSF->IndexOperandHashMap->size() != SF->IndexOperandHashMap->size()) {
235 for (
auto &
P : *RSF->IndexOperandHashMap) {
236 auto &InstOpndIndex =
P.first;
237 if (!SF->IndexOperandHashMap->count(InstOpndIndex)) {
258 for (
auto It : ToDelete)
259 HashToFuncs.
erase(It);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the SmallSet class.
static bool isProfitable(const StableFunctionMap::StableFunctionEntries &SFS)
static void removeIdenticalIndexPair(StableFunctionMap::StableFunctionEntries &SFS)
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)
iterator erase(const_iterator CI)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
SmallVector< IndexPair, 4 > ParamLocs
std::pair< unsigned, unsigned > IndexPair
The pair of an instruction index and a operand index.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
std::unordered_map< stable_hash, EntryStorage > HashFuncsMapType
SmallVector< std::unique_ptr< StableFunctionEntry > > StableFunctionEntries
LLVM_ABI void finalize(bool SkipTrim=false)
Finalize the stable function map by trimming content.
LLVM_ABI size_t size(SizeType Type=UniqueHashCount) const
LLVM_ABI void insert(const StableFunction &Func)
Insert a StableFunction object into the function map.
LLVM_ABI const StableFunctionEntries & at(HashFuncsMapType::key_type FunctionHash) const
LLVM_ABI void merge(const StableFunctionMap &OtherMap)
Merge a OtherMap into this function map.
LLVM_ABI std::optional< std::string > getNameForId(unsigned Id) const
Get the name associated with a given ID.
LLVM_ABI const HashFuncsMapType & getFunctionMap() const
Get the HashToFuncs map for serialization.
LLVM_ABI 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...