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