xref: /freebsd/contrib/llvm-project/llvm/lib/CGData/StableFunctionMapRecord.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===-- StableFunctionMapRecord.cpp ---------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This implements the functionality for the StableFunctionMapRecord class,
10*700637cbSDimitry Andric // including methods for serialization and deserialization of stable function
11*700637cbSDimitry Andric // maps to and from raw and YAML streams. It also includes utilities for
12*700637cbSDimitry Andric // managing function entries and their metadata.
13*700637cbSDimitry Andric //
14*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
15*700637cbSDimitry Andric 
16*700637cbSDimitry Andric #include "llvm/CGData/StableFunctionMapRecord.h"
17*700637cbSDimitry Andric #include "llvm/Support/EndianStream.h"
18*700637cbSDimitry Andric 
19*700637cbSDimitry Andric #define DEBUG_TYPE "stable-function-map-record"
20*700637cbSDimitry Andric 
21*700637cbSDimitry Andric using namespace llvm;
22*700637cbSDimitry Andric using namespace llvm::support;
23*700637cbSDimitry Andric 
24*700637cbSDimitry Andric LLVM_YAML_IS_SEQUENCE_VECTOR(IndexPairHash)
25*700637cbSDimitry Andric LLVM_YAML_IS_SEQUENCE_VECTOR(StableFunction)
26*700637cbSDimitry Andric 
27*700637cbSDimitry Andric namespace llvm {
28*700637cbSDimitry Andric namespace yaml {
29*700637cbSDimitry Andric 
30*700637cbSDimitry Andric template <> struct MappingTraits<IndexPairHash> {
mappingllvm::yaml::MappingTraits31*700637cbSDimitry Andric   static void mapping(IO &IO, IndexPairHash &Key) {
32*700637cbSDimitry Andric     IO.mapRequired("InstIndex", Key.first.first);
33*700637cbSDimitry Andric     IO.mapRequired("OpndIndex", Key.first.second);
34*700637cbSDimitry Andric     IO.mapRequired("OpndHash", Key.second);
35*700637cbSDimitry Andric   }
36*700637cbSDimitry Andric };
37*700637cbSDimitry Andric 
38*700637cbSDimitry Andric template <> struct MappingTraits<StableFunction> {
mappingllvm::yaml::MappingTraits39*700637cbSDimitry Andric   static void mapping(IO &IO, StableFunction &Func) {
40*700637cbSDimitry Andric     IO.mapRequired("Hash", Func.Hash);
41*700637cbSDimitry Andric     IO.mapRequired("FunctionName", Func.FunctionName);
42*700637cbSDimitry Andric     IO.mapRequired("ModuleName", Func.ModuleName);
43*700637cbSDimitry Andric     IO.mapRequired("InstCount", Func.InstCount);
44*700637cbSDimitry Andric     IO.mapRequired("IndexOperandHashes", Func.IndexOperandHashes);
45*700637cbSDimitry Andric   }
46*700637cbSDimitry Andric };
47*700637cbSDimitry Andric 
48*700637cbSDimitry Andric } // namespace yaml
49*700637cbSDimitry Andric } // namespace llvm
50*700637cbSDimitry Andric 
51*700637cbSDimitry Andric // Get a sorted vector of StableFunctionEntry pointers.
52*700637cbSDimitry Andric static SmallVector<const StableFunctionMap::StableFunctionEntry *>
getStableFunctionEntries(const StableFunctionMap & SFM)53*700637cbSDimitry Andric getStableFunctionEntries(const StableFunctionMap &SFM) {
54*700637cbSDimitry Andric   SmallVector<const StableFunctionMap::StableFunctionEntry *> FuncEntries;
55*700637cbSDimitry Andric   for (const auto &P : SFM.getFunctionMap())
56*700637cbSDimitry Andric     for (auto &Func : P.second)
57*700637cbSDimitry Andric       FuncEntries.emplace_back(Func.get());
58*700637cbSDimitry Andric 
59*700637cbSDimitry Andric   llvm::stable_sort(
60*700637cbSDimitry Andric       FuncEntries, [&](auto &A, auto &B) {
61*700637cbSDimitry Andric         return std::tuple(A->Hash, SFM.getNameForId(A->ModuleNameId),
62*700637cbSDimitry Andric                           SFM.getNameForId(A->FunctionNameId)) <
63*700637cbSDimitry Andric                std::tuple(B->Hash, SFM.getNameForId(B->ModuleNameId),
64*700637cbSDimitry Andric                           SFM.getNameForId(B->FunctionNameId));
65*700637cbSDimitry Andric       });
66*700637cbSDimitry Andric   return FuncEntries;
67*700637cbSDimitry Andric }
68*700637cbSDimitry Andric 
69*700637cbSDimitry Andric // Get a sorted vector of IndexOperandHashes.
getStableIndexOperandHashes(const StableFunctionMap::StableFunctionEntry * FuncEntry)70*700637cbSDimitry Andric static IndexOperandHashVecType getStableIndexOperandHashes(
71*700637cbSDimitry Andric     const StableFunctionMap::StableFunctionEntry *FuncEntry) {
72*700637cbSDimitry Andric   IndexOperandHashVecType IndexOperandHashes;
73*700637cbSDimitry Andric   for (auto &[Indices, OpndHash] : *FuncEntry->IndexOperandHashMap)
74*700637cbSDimitry Andric     IndexOperandHashes.emplace_back(Indices, OpndHash);
75*700637cbSDimitry Andric   // The indices are unique, so we can just sort by the first.
76*700637cbSDimitry Andric   llvm::sort(IndexOperandHashes);
77*700637cbSDimitry Andric   return IndexOperandHashes;
78*700637cbSDimitry Andric }
79*700637cbSDimitry Andric 
serialize(raw_ostream & OS,std::vector<CGDataPatchItem> & PatchItems) const80*700637cbSDimitry Andric void StableFunctionMapRecord::serialize(
81*700637cbSDimitry Andric     raw_ostream &OS, std::vector<CGDataPatchItem> &PatchItems) const {
82*700637cbSDimitry Andric   serialize(OS, FunctionMap.get(), PatchItems);
83*700637cbSDimitry Andric }
84*700637cbSDimitry Andric 
serialize(raw_ostream & OS,const StableFunctionMap * FunctionMap,std::vector<CGDataPatchItem> & PatchItems)85*700637cbSDimitry Andric void StableFunctionMapRecord::serialize(
86*700637cbSDimitry Andric     raw_ostream &OS, const StableFunctionMap *FunctionMap,
87*700637cbSDimitry Andric     std::vector<CGDataPatchItem> &PatchItems) {
88*700637cbSDimitry Andric   support::endian::Writer Writer(OS, endianness::little);
89*700637cbSDimitry Andric 
90*700637cbSDimitry Andric   // Write Names.
91*700637cbSDimitry Andric   ArrayRef<std::string> Names = FunctionMap->getNames();
92*700637cbSDimitry Andric   Writer.write<uint32_t>(Names.size());
93*700637cbSDimitry Andric   // Remember the position, write back the total size of Names, so we can skip
94*700637cbSDimitry Andric   // reading them if needed.
95*700637cbSDimitry Andric   const uint64_t NamesByteSizeOffset = Writer.OS.tell();
96*700637cbSDimitry Andric   Writer.write<uint64_t>(0);
97*700637cbSDimitry Andric   for (auto &Name : Names)
98*700637cbSDimitry Andric     Writer.OS << Name << '\0';
99*700637cbSDimitry Andric   // Align current position to 4 bytes.
100*700637cbSDimitry Andric   uint32_t Padding = offsetToAlignment(Writer.OS.tell(), Align(4));
101*700637cbSDimitry Andric   for (uint32_t I = 0; I < Padding; ++I)
102*700637cbSDimitry Andric     Writer.OS << '\0';
103*700637cbSDimitry Andric   const auto NamesByteSize =
104*700637cbSDimitry Andric       Writer.OS.tell() - NamesByteSizeOffset - sizeof(NamesByteSizeOffset);
105*700637cbSDimitry Andric   PatchItems.emplace_back(NamesByteSizeOffset, &NamesByteSize, 1);
106*700637cbSDimitry Andric 
107*700637cbSDimitry Andric   // Write StableFunctionEntries whose pointers are sorted.
108*700637cbSDimitry Andric   auto FuncEntries = getStableFunctionEntries(*FunctionMap);
109*700637cbSDimitry Andric   Writer.write<uint32_t>(FuncEntries.size());
110*700637cbSDimitry Andric 
111*700637cbSDimitry Andric   for (const auto *FuncRef : FuncEntries) {
112*700637cbSDimitry Andric     Writer.write<stable_hash>(FuncRef->Hash);
113*700637cbSDimitry Andric     Writer.write<uint32_t>(FuncRef->FunctionNameId);
114*700637cbSDimitry Andric     Writer.write<uint32_t>(FuncRef->ModuleNameId);
115*700637cbSDimitry Andric     Writer.write<uint32_t>(FuncRef->InstCount);
116*700637cbSDimitry Andric 
117*700637cbSDimitry Andric     // Emit IndexOperandHashes sorted from IndexOperandHashMap.
118*700637cbSDimitry Andric     IndexOperandHashVecType IndexOperandHashes =
119*700637cbSDimitry Andric         getStableIndexOperandHashes(FuncRef);
120*700637cbSDimitry Andric     Writer.write<uint32_t>(IndexOperandHashes.size());
121*700637cbSDimitry Andric     for (auto &IndexOperandHash : IndexOperandHashes) {
122*700637cbSDimitry Andric       Writer.write<uint32_t>(IndexOperandHash.first.first);
123*700637cbSDimitry Andric       Writer.write<uint32_t>(IndexOperandHash.first.second);
124*700637cbSDimitry Andric       Writer.write<stable_hash>(IndexOperandHash.second);
125*700637cbSDimitry Andric     }
126*700637cbSDimitry Andric   }
127*700637cbSDimitry Andric }
128*700637cbSDimitry Andric 
deserialize(const unsigned char * & Ptr,bool ReadStableFunctionMapNames)129*700637cbSDimitry Andric void StableFunctionMapRecord::deserialize(const unsigned char *&Ptr,
130*700637cbSDimitry Andric                                           bool ReadStableFunctionMapNames) {
131*700637cbSDimitry Andric   // Assert that Ptr is 4-byte aligned
132*700637cbSDimitry Andric   assert(((uintptr_t)Ptr % 4) == 0);
133*700637cbSDimitry Andric   // Read Names.
134*700637cbSDimitry Andric   auto NumNames =
135*700637cbSDimitry Andric       endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
136*700637cbSDimitry Andric   // Early exit if there is no name.
137*700637cbSDimitry Andric   if (NumNames == 0)
138*700637cbSDimitry Andric     return;
139*700637cbSDimitry Andric   const auto NamesByteSize =
140*700637cbSDimitry Andric       endian::readNext<uint64_t, endianness::little, unaligned>(Ptr);
141*700637cbSDimitry Andric   const auto NamesOffset = reinterpret_cast<uintptr_t>(Ptr);
142*700637cbSDimitry Andric   if (ReadStableFunctionMapNames) {
143*700637cbSDimitry Andric     for (unsigned I = 0; I < NumNames; ++I) {
144*700637cbSDimitry Andric       StringRef Name(reinterpret_cast<const char *>(Ptr));
145*700637cbSDimitry Andric       Ptr += Name.size() + 1;
146*700637cbSDimitry Andric       FunctionMap->getIdOrCreateForName(Name);
147*700637cbSDimitry Andric     }
148*700637cbSDimitry Andric     // Align Ptr to 4 bytes.
149*700637cbSDimitry Andric     Ptr = reinterpret_cast<const uint8_t *>(alignAddr(Ptr, Align(4)));
150*700637cbSDimitry Andric     assert(reinterpret_cast<uintptr_t>(Ptr) - NamesOffset == NamesByteSize &&
151*700637cbSDimitry Andric            "NamesByteSize does not match the actual size of names");
152*700637cbSDimitry Andric   } else {
153*700637cbSDimitry Andric     // skip reading Names by advancing the pointer.
154*700637cbSDimitry Andric     Ptr = reinterpret_cast<const uint8_t *>(NamesOffset + NamesByteSize);
155*700637cbSDimitry Andric   }
156*700637cbSDimitry Andric 
157*700637cbSDimitry Andric   // Read StableFunctionEntries.
158*700637cbSDimitry Andric   auto NumFuncs =
159*700637cbSDimitry Andric       endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
160*700637cbSDimitry Andric   for (unsigned I = 0; I < NumFuncs; ++I) {
161*700637cbSDimitry Andric     auto Hash =
162*700637cbSDimitry Andric         endian::readNext<stable_hash, endianness::little, unaligned>(Ptr);
163*700637cbSDimitry Andric     auto FunctionNameId =
164*700637cbSDimitry Andric         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
165*700637cbSDimitry Andric     assert(FunctionMap->getNameForId(FunctionNameId) &&
166*700637cbSDimitry Andric            "FunctionNameId out of range");
167*700637cbSDimitry Andric     auto ModuleNameId =
168*700637cbSDimitry Andric         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
169*700637cbSDimitry Andric     assert(FunctionMap->getNameForId(ModuleNameId) &&
170*700637cbSDimitry Andric            "ModuleNameId out of range");
171*700637cbSDimitry Andric     auto InstCount =
172*700637cbSDimitry Andric         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
173*700637cbSDimitry Andric 
174*700637cbSDimitry Andric     // Read IndexOperandHashes to build IndexOperandHashMap
175*700637cbSDimitry Andric     auto NumIndexOperandHashes =
176*700637cbSDimitry Andric         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
177*700637cbSDimitry Andric     auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
178*700637cbSDimitry Andric     for (unsigned J = 0; J < NumIndexOperandHashes; ++J) {
179*700637cbSDimitry Andric       auto InstIndex =
180*700637cbSDimitry Andric           endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
181*700637cbSDimitry Andric       auto OpndIndex =
182*700637cbSDimitry Andric           endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
183*700637cbSDimitry Andric       auto OpndHash =
184*700637cbSDimitry Andric           endian::readNext<stable_hash, endianness::little, unaligned>(Ptr);
185*700637cbSDimitry Andric       assert(InstIndex < InstCount && "InstIndex out of range");
186*700637cbSDimitry Andric 
187*700637cbSDimitry Andric       IndexOperandHashMap->try_emplace({InstIndex, OpndIndex}, OpndHash);
188*700637cbSDimitry Andric     }
189*700637cbSDimitry Andric 
190*700637cbSDimitry Andric     // Insert a new StableFunctionEntry into the map.
191*700637cbSDimitry Andric     auto FuncEntry = std::make_unique<StableFunctionMap::StableFunctionEntry>(
192*700637cbSDimitry Andric         Hash, FunctionNameId, ModuleNameId, InstCount,
193*700637cbSDimitry Andric         std::move(IndexOperandHashMap));
194*700637cbSDimitry Andric 
195*700637cbSDimitry Andric     FunctionMap->insert(std::move(FuncEntry));
196*700637cbSDimitry Andric   }
197*700637cbSDimitry Andric }
198*700637cbSDimitry Andric 
serializeYAML(yaml::Output & YOS) const199*700637cbSDimitry Andric void StableFunctionMapRecord::serializeYAML(yaml::Output &YOS) const {
200*700637cbSDimitry Andric   auto FuncEntries = getStableFunctionEntries(*FunctionMap);
201*700637cbSDimitry Andric   SmallVector<StableFunction> Functions;
202*700637cbSDimitry Andric   for (const auto *FuncEntry : FuncEntries) {
203*700637cbSDimitry Andric     auto IndexOperandHashes = getStableIndexOperandHashes(FuncEntry);
204*700637cbSDimitry Andric     Functions.emplace_back(
205*700637cbSDimitry Andric         FuncEntry->Hash, *FunctionMap->getNameForId(FuncEntry->FunctionNameId),
206*700637cbSDimitry Andric         *FunctionMap->getNameForId(FuncEntry->ModuleNameId),
207*700637cbSDimitry Andric         FuncEntry->InstCount, std::move(IndexOperandHashes));
208*700637cbSDimitry Andric   }
209*700637cbSDimitry Andric 
210*700637cbSDimitry Andric   YOS << Functions;
211*700637cbSDimitry Andric }
212*700637cbSDimitry Andric 
deserializeYAML(yaml::Input & YIS)213*700637cbSDimitry Andric void StableFunctionMapRecord::deserializeYAML(yaml::Input &YIS) {
214*700637cbSDimitry Andric   std::vector<StableFunction> Funcs;
215*700637cbSDimitry Andric   YIS >> Funcs;
216*700637cbSDimitry Andric   for (auto &Func : Funcs)
217*700637cbSDimitry Andric     FunctionMap->insert(Func);
218*700637cbSDimitry Andric   YIS.nextDocument();
219*700637cbSDimitry Andric }
220