[clang] Add test for CWG190 "Layout-compatible POD-struct types" (#121668)
[llvm-project.git] / llvm / lib / CGData / StableFunctionMapRecord.cpp
blob8eb667a651ebe97d256f28e3ab5d8d03f61a0e53
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.
14 //===----------------------------------------------------------------------===//
16 #include "llvm/CGData/StableFunctionMapRecord.h"
17 #include "llvm/Support/EndianStream.h"
19 #define DEBUG_TYPE "stable-function-map-record"
21 using namespace llvm;
22 using namespace llvm::support;
24 LLVM_YAML_IS_SEQUENCE_VECTOR(IndexPairHash)
25 LLVM_YAML_IS_SEQUENCE_VECTOR(StableFunction)
27 namespace llvm {
28 namespace yaml {
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);
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);
48 } // namespace yaml
49 } // namespace llvm
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());
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;
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;
80 void StableFunctionMapRecord::serialize(raw_ostream &OS) const {
81 serialize(OS, FunctionMap.get());
84 void StableFunctionMapRecord::serialize(raw_ostream &OS,
85 const StableFunctionMap *FunctionMap) {
86 support::endian::Writer Writer(OS, endianness::little);
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;
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';
101 // Write StableFunctionEntries whose pointers are sorted.
102 auto FuncEntries = getStableFunctionEntries(*FunctionMap);
103 Writer.write<uint32_t>(FuncEntries.size());
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);
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);
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);
137 // Align Ptr to 4 bytes.
138 Ptr = reinterpret_cast<const uint8_t *>(alignAddr(Ptr, Align(4)));
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);
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");
170 IndexOperandHashMap->try_emplace({InstIndex, OpndIndex}, OpndHash);
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));
178 FunctionMap->insert(std::move(FuncEntry));
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));
193 YOS << Functions;
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();