xref: /llvm-project/llvm/lib/CGData/StableFunctionMapRecord.cpp (revision 7ec26b23f27f2adfe6847bc69debb84efa34ed08)
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 
16 #include "llvm/CGData/StableFunctionMapRecord.h"
17 #include "llvm/Support/EndianStream.h"
18 
19 #define DEBUG_TYPE "stable-function-map-record"
20 
21 using namespace llvm;
22 using namespace llvm::support;
23 
24 LLVM_YAML_IS_SEQUENCE_VECTOR(IndexPairHash)
25 LLVM_YAML_IS_SEQUENCE_VECTOR(StableFunction)
26 
27 namespace llvm {
28 namespace yaml {
29 
30 template <> 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 
38 template <> 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.
52 static SmallVector<const StableFunctionMap::StableFunctionEntry *>
53 getStableFunctionEntries(const StableFunctionMap &SFM) {
54   SmallVector<const StableFunctionMap::StableFunctionEntry *> FuncEntries;
55   for (const auto &P : SFM.getFunctionMap())
56     for (auto &Func : P.second)
57       FuncEntries.emplace_back(Func.get());
58 
59   std::stable_sort(
60       FuncEntries.begin(), FuncEntries.end(), [&](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.
70 static IndexOperandHashVecType getStableIndexOperandHashes(
71     const StableFunctionMap::StableFunctionEntry *FuncEntry) {
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 
80 void StableFunctionMapRecord::serialize(raw_ostream &OS) const {
81   serialize(OS, FunctionMap.get());
82 }
83 
84 void StableFunctionMapRecord::serialize(raw_ostream &OS,
85                                         const StableFunctionMap *FunctionMap) {
86   support::endian::Writer Writer(OS, endianness::little);
87 
88   // Write Names.
89   auto &Names = FunctionMap->getNames();
90   uint32_t ByteSize = 4;
91   Writer.write<uint32_t>(Names.size());
92   for (auto &Name : Names) {
93     Writer.OS << Name << '\0';
94     ByteSize += Name.size() + 1;
95   }
96   // Align ByteSize to 4 bytes.
97   uint32_t Padding = offsetToAlignment(ByteSize, Align(4));
98   for (uint32_t I = 0; I < Padding; ++I)
99     Writer.OS << '\0';
100 
101   // Write StableFunctionEntries whose pointers are sorted.
102   auto FuncEntries = getStableFunctionEntries(*FunctionMap);
103   Writer.write<uint32_t>(FuncEntries.size());
104 
105   for (const auto *FuncRef : FuncEntries) {
106     Writer.write<stable_hash>(FuncRef->Hash);
107     Writer.write<uint32_t>(FuncRef->FunctionNameId);
108     Writer.write<uint32_t>(FuncRef->ModuleNameId);
109     Writer.write<uint32_t>(FuncRef->InstCount);
110 
111     // Emit IndexOperandHashes sorted from IndexOperandHashMap.
112     IndexOperandHashVecType IndexOperandHashes =
113         getStableIndexOperandHashes(FuncRef);
114     Writer.write<uint32_t>(IndexOperandHashes.size());
115     for (auto &IndexOperandHash : IndexOperandHashes) {
116       Writer.write<uint32_t>(IndexOperandHash.first.first);
117       Writer.write<uint32_t>(IndexOperandHash.first.second);
118       Writer.write<stable_hash>(IndexOperandHash.second);
119     }
120   }
121 }
122 
123 void StableFunctionMapRecord::deserialize(const unsigned char *&Ptr) {
124   // Assert that Ptr is 4-byte aligned
125   assert(((uintptr_t)Ptr % 4) == 0);
126   // Read Names.
127   auto NumNames =
128       endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
129   // Early exit if there is no name.
130   if (NumNames == 0)
131     return;
132   for (unsigned I = 0; I < NumNames; ++I) {
133     StringRef Name(reinterpret_cast<const char *>(Ptr));
134     Ptr += Name.size() + 1;
135     FunctionMap->getIdOrCreateForName(Name);
136   }
137   // Align Ptr to 4 bytes.
138   Ptr = reinterpret_cast<const uint8_t *>(alignAddr(Ptr, Align(4)));
139 
140   // Read StableFunctionEntries.
141   auto NumFuncs =
142       endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
143   for (unsigned I = 0; I < NumFuncs; ++I) {
144     auto Hash =
145         endian::readNext<stable_hash, endianness::little, unaligned>(Ptr);
146     auto FunctionNameId =
147         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
148     assert(FunctionMap->getNameForId(FunctionNameId) &&
149            "FunctionNameId out of range");
150     auto ModuleNameId =
151         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
152     assert(FunctionMap->getNameForId(ModuleNameId) &&
153            "ModuleNameId out of range");
154     auto InstCount =
155         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
156 
157     // Read IndexOperandHashes to build IndexOperandHashMap
158     auto NumIndexOperandHashes =
159         endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
160     auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>();
161     for (unsigned J = 0; J < NumIndexOperandHashes; ++J) {
162       auto InstIndex =
163           endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
164       auto OpndIndex =
165           endian::readNext<uint32_t, endianness::little, unaligned>(Ptr);
166       auto OpndHash =
167           endian::readNext<stable_hash, endianness::little, unaligned>(Ptr);
168       assert(InstIndex < InstCount && "InstIndex out of range");
169 
170       IndexOperandHashMap->try_emplace({InstIndex, OpndIndex}, OpndHash);
171     }
172 
173     // Insert a new StableFunctionEntry into the map.
174     auto FuncEntry = std::make_unique<StableFunctionMap::StableFunctionEntry>(
175         Hash, FunctionNameId, ModuleNameId, InstCount,
176         std::move(IndexOperandHashMap));
177 
178     FunctionMap->insert(std::move(FuncEntry));
179   }
180 }
181 
182 void StableFunctionMapRecord::serializeYAML(yaml::Output &YOS) const {
183   auto FuncEntries = getStableFunctionEntries(*FunctionMap);
184   SmallVector<StableFunction> Functions;
185   for (const auto *FuncEntry : FuncEntries) {
186     auto IndexOperandHashes = getStableIndexOperandHashes(FuncEntry);
187     Functions.emplace_back(
188         FuncEntry->Hash, *FunctionMap->getNameForId(FuncEntry->FunctionNameId),
189         *FunctionMap->getNameForId(FuncEntry->ModuleNameId),
190         FuncEntry->InstCount, std::move(IndexOperandHashes));
191   }
192 
193   YOS << Functions;
194 }
195 
196 void StableFunctionMapRecord::deserializeYAML(yaml::Input &YIS) {
197   std::vector<StableFunction> Funcs;
198   YIS >> Funcs;
199   for (auto &Func : Funcs)
200     FunctionMap->insert(Func);
201   YIS.nextDocument();
202 }
203