LLVM 22.0.0git
StableFunctionMapRecord.cpp
Go to the documentation of this file.
1//===-- StableFunctionMapRecord.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 StableFunctionMapRecord class,
10// including methods for serialization and deserialization of stable function
11// maps to and from raw and YAML streams. It also includes utilities for
12// managing function entries and their metadata.
13//
14//===----------------------------------------------------------------------===//
15
18
19#define DEBUG_TYPE "stable-function-map-record"
20
21using namespace llvm;
22using namespace llvm::support;
23
26
27namespace llvm {
28namespace yaml {
29
30template <> struct MappingTraits<IndexPairHash> {
31 static void mapping(IO &IO, IndexPairHash &Key) {
32 IO.mapRequired("InstIndex", Key.first.first);
33 IO.mapRequired("OpndIndex", Key.first.second);
34 IO.mapRequired("OpndHash", Key.second);
35 }
36};
37
38template <> struct MappingTraits<StableFunction> {
39 static void mapping(IO &IO, StableFunction &Func) {
40 IO.mapRequired("Hash", Func.Hash);
41 IO.mapRequired("FunctionName", Func.FunctionName);
42 IO.mapRequired("ModuleName", Func.ModuleName);
43 IO.mapRequired("InstCount", Func.InstCount);
44 IO.mapRequired("IndexOperandHashes", Func.IndexOperandHashes);
45 }
46};
47
48} // namespace yaml
49} // namespace llvm
50
51// Get a sorted vector of StableFunctionEntry pointers.
55 for (const auto &P : SFM.getFunctionMap())
56 for (auto &Func : P.second.Entries)
57 FuncEntries.emplace_back(Func.get());
58
60 FuncEntries, [&](auto &A, auto &B) {
61 return std::tuple(A->Hash, SFM.getNameForId(A->ModuleNameId),
62 SFM.getNameForId(A->FunctionNameId)) <
63 std::tuple(B->Hash, SFM.getNameForId(B->ModuleNameId),
64 SFM.getNameForId(B->FunctionNameId));
65 });
66 return FuncEntries;
67}
68
69// Get a sorted vector of IndexOperandHashes.
72 IndexOperandHashVecType IndexOperandHashes;
73 for (auto &[Indices, OpndHash] : *FuncEntry->IndexOperandHashMap)
74 IndexOperandHashes.emplace_back(Indices, OpndHash);
75 // The indices are unique, so we can just sort by the first.
76 llvm::sort(IndexOperandHashes);
77 return IndexOperandHashes;
78}
79
81 raw_ostream &OS, std::vector<CGDataPatchItem> &PatchItems) const {
82 serialize(OS, FunctionMap.get(), PatchItems);
83}
84
86 raw_ostream &OS, const StableFunctionMap *FunctionMap,
87 std::vector<CGDataPatchItem> &PatchItems) {
89
90 // Write Names.
91 ArrayRef<std::string> Names = FunctionMap->getNames();
92 Writer.write<uint32_t>(Names.size());
93 // Remember the position, write back the total size of Names, so we can skip
94 // reading them if needed.
95 const uint64_t NamesByteSizeOffset = Writer.OS.tell();
96 Writer.write<uint64_t>(0);
97 for (auto &Name : Names)
98 Writer.OS << Name << '\0';
99 // Align current position to 4 bytes.
100 uint32_t Padding = offsetToAlignment(Writer.OS.tell(), Align(4));
101 for (uint32_t I = 0; I < Padding; ++I)
102 Writer.OS << '\0';
103 const auto NamesByteSize =
104 Writer.OS.tell() - NamesByteSizeOffset - sizeof(NamesByteSizeOffset);
105 PatchItems.emplace_back(NamesByteSizeOffset, &NamesByteSize, 1);
106
107 // Write StableFunctionEntries whose pointers are sorted.
108 auto FuncEntries = getStableFunctionEntries(*FunctionMap);
109 Writer.write<uint32_t>(FuncEntries.size());
110 for (const auto *FuncRef : FuncEntries)
111 Writer.write<stable_hash>(FuncRef->Hash);
112 std::vector<uint64_t> IndexOperandHashesOffsets;
113 IndexOperandHashesOffsets.reserve(FuncEntries.size());
114 for (const auto *FuncRef : FuncEntries) {
115 Writer.write<uint32_t>(FuncRef->FunctionNameId);
116 Writer.write<uint32_t>(FuncRef->ModuleNameId);
117 Writer.write<uint32_t>(FuncRef->InstCount);
118 const uint64_t Offset = Writer.OS.tell();
119 IndexOperandHashesOffsets.push_back(Offset);
120 Writer.write<uint64_t>(0);
121 }
122 const uint64_t IndexOperandHashesByteSizeOffset = Writer.OS.tell();
123 Writer.write<uint64_t>(0);
124 for (size_t I = 0; I < FuncEntries.size(); ++I) {
125 const uint64_t Offset = Writer.OS.tell() - IndexOperandHashesOffsets[I];
126 PatchItems.emplace_back(IndexOperandHashesOffsets[I], &Offset, 1);
127 // Emit IndexOperandHashes sorted from IndexOperandHashMap.
128 const auto *FuncRef = FuncEntries[I];
129 IndexOperandHashVecType IndexOperandHashes =
131 Writer.write<uint32_t>(IndexOperandHashes.size());
132 for (auto &IndexOperandHash : IndexOperandHashes) {
133 Writer.write<uint32_t>(IndexOperandHash.first.first);
134 Writer.write<uint32_t>(IndexOperandHash.first.second);
135 Writer.write<stable_hash>(IndexOperandHash.second);
136 }
137 }
138 // Write the total size of IndexOperandHashes.
139 const uint64_t IndexOperandHashesByteSize =
140 Writer.OS.tell() - IndexOperandHashesByteSizeOffset - sizeof(uint64_t);
141 PatchItems.emplace_back(IndexOperandHashesByteSizeOffset,
142 &IndexOperandHashesByteSize, 1);
143}
144
146 stable_hash Hash,
147 StableFunctionMap *FunctionMap) {
148 auto FunctionNameId =
149 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
150 if (FunctionMap->ReadStableFunctionMapNames)
151 assert(FunctionMap->getNameForId(FunctionNameId) &&
152 "FunctionNameId out of range");
153 auto ModuleNameId =
154 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
155 if (FunctionMap->ReadStableFunctionMapNames)
156 assert(FunctionMap->getNameForId(ModuleNameId) &&
157 "ModuleNameId out of range");
158 auto InstCount =
159 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
160
161 // Read IndexOperandHashes to build IndexOperandHashMap
162 auto CurrentPosition = reinterpret_cast<uintptr_t>(Ptr);
163 auto IndexOperandHashesOffset =
164 endian::readNext<uint64_t, endianness::little, unaligned>(Ptr);
165 auto *IndexOperandHashesPtr = reinterpret_cast<const unsigned char *>(
166 CurrentPosition + IndexOperandHashesOffset);
167 auto NumIndexOperandHashes =
168 endian::readNext<uint32_t, endianness::little, unaligned>(
169 IndexOperandHashesPtr);
170 auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
171 for (unsigned J = 0; J < NumIndexOperandHashes; ++J) {
172 auto InstIndex = endian::readNext<uint32_t, endianness::little, unaligned>(
173 IndexOperandHashesPtr);
174 auto OpndIndex = endian::readNext<uint32_t, endianness::little, unaligned>(
175 IndexOperandHashesPtr);
176 auto OpndHash =
177 endian::readNext<stable_hash, endianness::little, unaligned>(
178 IndexOperandHashesPtr);
179 assert(InstIndex < InstCount && "InstIndex out of range");
180
181 IndexOperandHashMap->try_emplace({InstIndex, OpndIndex}, OpndHash);
182 }
183
184 // Insert a new StableFunctionEntry into the map.
185 auto FuncEntry = std::make_unique<StableFunctionMap::StableFunctionEntry>(
186 Hash, FunctionNameId, ModuleNameId, InstCount,
187 std::move(IndexOperandHashMap));
188
189 FunctionMap->insert(std::move(FuncEntry));
190}
191
192void StableFunctionMapRecord::deserialize(const unsigned char *&Ptr,
193 bool Lazy) {
194 // Assert that Ptr is 4-byte aligned
195 assert(((uintptr_t)Ptr % 4) == 0);
196 // Read Names.
197 auto NumNames =
198 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
199 // Early exit if there is no name.
200 if (NumNames == 0)
201 return;
202 const auto NamesByteSize =
203 endian::readNext<uint64_t, endianness::little, unaligned>(Ptr);
204 const auto NamesOffset = reinterpret_cast<uintptr_t>(Ptr);
205 if (FunctionMap->ReadStableFunctionMapNames) {
206 for (unsigned I = 0; I < NumNames; ++I) {
207 StringRef Name(reinterpret_cast<const char *>(Ptr));
208 Ptr += Name.size() + 1;
209 FunctionMap->getIdOrCreateForName(Name);
210 }
211 // Align Ptr to 4 bytes.
212 Ptr = reinterpret_cast<const uint8_t *>(alignAddr(Ptr, Align(4)));
213 assert(reinterpret_cast<uintptr_t>(Ptr) - NamesOffset == NamesByteSize &&
214 "NamesByteSize does not match the actual size of names");
215 } else {
216 // skip reading Names by advancing the pointer.
217 Ptr = reinterpret_cast<const uint8_t *>(NamesOffset + NamesByteSize);
218 }
219
220 // Read StableFunctionEntries.
221 auto NumFuncs =
222 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
223 auto FixedSizeFieldsOffset =
224 reinterpret_cast<uintptr_t>(Ptr) + NumFuncs * sizeof(stable_hash);
225 constexpr uint32_t FixedSizeFieldsSizePerEntry =
226 // FunctionNameId
227 sizeof(uint32_t) +
228 // ModuleNameId
229 sizeof(uint32_t) +
230 // InstCount
231 sizeof(uint32_t) +
232 // Relative offset to IndexOperandHashes
233 sizeof(uint64_t);
234 for (unsigned I = 0; I < NumFuncs; ++I) {
235 auto Hash =
236 endian::readNext<stable_hash, endianness::little, unaligned>(Ptr);
237 if (Lazy) {
238 auto It = FunctionMap->HashToFuncs.try_emplace(Hash).first;
239 StableFunctionMap::EntryStorage &Storage = It->second;
240 Storage.Offsets.push_back(FixedSizeFieldsOffset);
241 } else {
243 reinterpret_cast<const unsigned char *>(FixedSizeFieldsOffset), Hash,
244 FunctionMap.get());
245 }
246 FixedSizeFieldsOffset += FixedSizeFieldsSizePerEntry;
247 }
248
249 // Update Ptr to the end of the serialized map to meet the expectation of
250 // CodeGenDataReader.
251 Ptr = reinterpret_cast<const unsigned char *>(FixedSizeFieldsOffset);
252 auto IndexOperandHashesByteSize =
253 endian::readNext<uint64_t, endianness::little, unaligned>(Ptr);
254 Ptr = reinterpret_cast<const unsigned char *>(
255 reinterpret_cast<uintptr_t>(Ptr) + IndexOperandHashesByteSize);
256}
257
258void StableFunctionMapRecord::deserialize(const unsigned char *&Ptr) {
259 deserialize(Ptr, /*Lazy=*/false);
260}
261
263 std::shared_ptr<MemoryBuffer> Buffer, uint64_t Offset) {
264 const auto *Ptr = reinterpret_cast<const unsigned char *>(
265 reinterpret_cast<uintptr_t>(Buffer->getBufferStart()) + Offset);
266 deserialize(Ptr, /*Lazy=*/true);
267 FunctionMap->Buffer = std::move(Buffer);
268}
269
270void StableFunctionMapRecord::serializeYAML(yaml::Output &YOS) const {
271 auto FuncEntries = getStableFunctionEntries(*FunctionMap);
273 for (const auto *FuncEntry : FuncEntries) {
274 auto IndexOperandHashes = getStableIndexOperandHashes(FuncEntry);
275 Functions.emplace_back(
276 FuncEntry->Hash, *FunctionMap->getNameForId(FuncEntry->FunctionNameId),
277 *FunctionMap->getNameForId(FuncEntry->ModuleNameId),
278 FuncEntry->InstCount, std::move(IndexOperandHashes));
279 }
280
281 YOS << Functions;
282}
283
285 std::vector<StableFunction> Funcs;
286 YIS >> Funcs;
287 for (auto &Func : Funcs)
288 FunctionMap->insert(Func);
289 YIS.nextDocument();
290}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
std::string Name
#define I(x, y, z)
Definition: MD5.cpp:58
#define P(N)
raw_pwrite_stream & OS
static IndexOperandHashVecType getStableIndexOperandHashes(const StableFunctionMap::StableFunctionEntry *FuncEntry)
static SmallVector< const StableFunctionMap::StableFunctionEntry * > getStableFunctionEntries(const StableFunctionMap &SFM)
#define LLVM_YAML_IS_SEQUENCE_VECTOR(type)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:147
size_t size() const
Definition: SmallVector.h:79
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:938
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:148
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
void stable_sort(R &&Range)
Definition: STLExtras.h:2077
std::pair< IndexPair, stable_hash > IndexPairHash
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1669
uint64_t offsetToAlignment(uint64_t Value, Align Alignment)
Returns the offset to the next integer (mod 2**64) that is greater than or equal to Value and is a mu...
Definition: Alignment.h:197
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
Definition: Alignment.h:187
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
static LLVM_ABI void deserializeEntry(const unsigned char *Ptr, stable_hash Hash, StableFunctionMap *FunctionMap)
A static helper function to deserialize the stable function map entry.
LLVM_ABI void deserialize(const unsigned char *&Ptr)
Deserialize the stable function map from a raw_ostream.
std::unique_ptr< StableFunctionMap > FunctionMap
static LLVM_ABI void serialize(raw_ostream &OS, const StableFunctionMap *FunctionMap, std::vector< CGDataPatchItem > &PatchItems)
A static helper function to serialize the stable function map without owning the stable function map.
LLVM_ABI void deserializeYAML(yaml::Input &YIS)
Deserialize the stable function map from a YAML stream.
LLVM_ABI void lazyDeserialize(std::shared_ptr< MemoryBuffer > Buffer, uint64_t Offset)
Lazily deserialize the stable function map from Buffer starting at Offset.
LLVM_ABI void serializeYAML(yaml::Output &YOS) const
Serialize the stable function map to a YAML stream.
In addition to the deserialized StableFunctionEntry, the struct stores the offsets of corresponding s...
An efficient form of StableFunction for fast look-up.
std::unique_ptr< IndexOperandHashMapType > IndexOperandHashMap
A map from an IndexPair to a stable_hash which was skipped.
LLVM_ABI std::optional< std::string > getNameForId(unsigned Id) const
Get the name associated with a given ID.
const HashFuncsMapType & getFunctionMap() const
Get the HashToFuncs map for serialization.
A stable function is a function with a stable hash while tracking the locations of ignored operands a...
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:67
void write(ArrayRef< value_type > Val)
Definition: EndianStream.h:71
static void mapping(IO &IO, IndexPairHash &Key)
static void mapping(IO &IO, StableFunction &Func)