1 //===-- StableFunctionMapRecord.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
22 using namespace llvm::support
;
24 LLVM_YAML_IS_SEQUENCE_VECTOR(IndexPairHash
)
25 LLVM_YAML_IS_SEQUENCE_VECTOR(StableFunction
)
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
);
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());
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
));
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
);
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
)
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);
128 endian::readNext
<uint32_t, endianness::little
, unaligned
>(Ptr
);
129 // Early exit if there is no name.
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.
142 endian::readNext
<uint32_t, endianness::little
, unaligned
>(Ptr
);
143 for (unsigned I
= 0; I
< NumFuncs
; ++I
) {
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");
151 endian::readNext
<uint32_t, endianness::little
, unaligned
>(Ptr
);
152 assert(FunctionMap
->getNameForId(ModuleNameId
) &&
153 "ModuleNameId out of range");
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
) {
163 endian::readNext
<uint32_t, endianness::little
, unaligned
>(Ptr
);
165 endian::readNext
<uint32_t, endianness::little
, unaligned
>(Ptr
);
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
));
196 void StableFunctionMapRecord::deserializeYAML(yaml::Input
&YIS
) {
197 std::vector
<StableFunction
> Funcs
;
199 for (auto &Func
: Funcs
)
200 FunctionMap
->insert(Func
);