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 llvm::stable_sort( 60 FuncEntries, [&](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( 81 raw_ostream &OS, std::vector<CGDataPatchItem> &PatchItems) const { 82 serialize(OS, FunctionMap.get(), PatchItems); 83 } 84 85 void StableFunctionMapRecord::serialize( 86 raw_ostream &OS, const StableFunctionMap *FunctionMap, 87 std::vector<CGDataPatchItem> &PatchItems) { 88 support::endian::Writer Writer(OS, endianness::little); 89 90 // Write Names. 91 ArrayRef<std::string> Names = FunctionMap->getNames(); 92 Writer.write<uint32_t>(Names.size()); 93 // Remember the position, write back the total size of Names, so we can skip 94 // reading them if needed. 95 const uint64_t NamesByteSizeOffset = Writer.OS.tell(); 96 Writer.write<uint64_t>(0); 97 for (auto &Name : Names) 98 Writer.OS << Name << '\0'; 99 // Align current position to 4 bytes. 100 uint32_t Padding = offsetToAlignment(Writer.OS.tell(), Align(4)); 101 for (uint32_t I = 0; I < Padding; ++I) 102 Writer.OS << '\0'; 103 const auto NamesByteSize = 104 Writer.OS.tell() - NamesByteSizeOffset - sizeof(NamesByteSizeOffset); 105 PatchItems.emplace_back(NamesByteSizeOffset, &NamesByteSize, 1); 106 107 // Write StableFunctionEntries whose pointers are sorted. 108 auto FuncEntries = getStableFunctionEntries(*FunctionMap); 109 Writer.write<uint32_t>(FuncEntries.size()); 110 111 for (const auto *FuncRef : FuncEntries) { 112 Writer.write<stable_hash>(FuncRef->Hash); 113 Writer.write<uint32_t>(FuncRef->FunctionNameId); 114 Writer.write<uint32_t>(FuncRef->ModuleNameId); 115 Writer.write<uint32_t>(FuncRef->InstCount); 116 117 // Emit IndexOperandHashes sorted from IndexOperandHashMap. 118 IndexOperandHashVecType IndexOperandHashes = 119 getStableIndexOperandHashes(FuncRef); 120 Writer.write<uint32_t>(IndexOperandHashes.size()); 121 for (auto &IndexOperandHash : IndexOperandHashes) { 122 Writer.write<uint32_t>(IndexOperandHash.first.first); 123 Writer.write<uint32_t>(IndexOperandHash.first.second); 124 Writer.write<stable_hash>(IndexOperandHash.second); 125 } 126 } 127 } 128 129 void StableFunctionMapRecord::deserialize(const unsigned char *&Ptr, 130 bool ReadStableFunctionMapNames) { 131 // Assert that Ptr is 4-byte aligned 132 assert(((uintptr_t)Ptr % 4) == 0); 133 // Read Names. 134 auto NumNames = 135 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 136 // Early exit if there is no name. 137 if (NumNames == 0) 138 return; 139 const auto NamesByteSize = 140 endian::readNext<uint64_t, endianness::little, unaligned>(Ptr); 141 const auto NamesOffset = reinterpret_cast<uintptr_t>(Ptr); 142 if (ReadStableFunctionMapNames) { 143 for (unsigned I = 0; I < NumNames; ++I) { 144 StringRef Name(reinterpret_cast<const char *>(Ptr)); 145 Ptr += Name.size() + 1; 146 FunctionMap->getIdOrCreateForName(Name); 147 } 148 // Align Ptr to 4 bytes. 149 Ptr = reinterpret_cast<const uint8_t *>(alignAddr(Ptr, Align(4))); 150 assert(reinterpret_cast<uintptr_t>(Ptr) - NamesOffset == NamesByteSize && 151 "NamesByteSize does not match the actual size of names"); 152 } else { 153 // skip reading Names by advancing the pointer. 154 Ptr = reinterpret_cast<const uint8_t *>(NamesOffset + NamesByteSize); 155 } 156 157 // Read StableFunctionEntries. 158 auto NumFuncs = 159 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 160 for (unsigned I = 0; I < NumFuncs; ++I) { 161 auto Hash = 162 endian::readNext<stable_hash, endianness::little, unaligned>(Ptr); 163 auto FunctionNameId = 164 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 165 assert(FunctionMap->getNameForId(FunctionNameId) && 166 "FunctionNameId out of range"); 167 auto ModuleNameId = 168 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 169 assert(FunctionMap->getNameForId(ModuleNameId) && 170 "ModuleNameId out of range"); 171 auto InstCount = 172 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 173 174 // Read IndexOperandHashes to build IndexOperandHashMap 175 auto NumIndexOperandHashes = 176 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 177 auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>(); 178 for (unsigned J = 0; J < NumIndexOperandHashes; ++J) { 179 auto InstIndex = 180 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 181 auto OpndIndex = 182 endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 183 auto OpndHash = 184 endian::readNext<stable_hash, endianness::little, unaligned>(Ptr); 185 assert(InstIndex < InstCount && "InstIndex out of range"); 186 187 IndexOperandHashMap->try_emplace({InstIndex, OpndIndex}, OpndHash); 188 } 189 190 // Insert a new StableFunctionEntry into the map. 191 auto FuncEntry = std::make_unique<StableFunctionMap::StableFunctionEntry>( 192 Hash, FunctionNameId, ModuleNameId, InstCount, 193 std::move(IndexOperandHashMap)); 194 195 FunctionMap->insert(std::move(FuncEntry)); 196 } 197 } 198 199 void StableFunctionMapRecord::serializeYAML(yaml::Output &YOS) const { 200 auto FuncEntries = getStableFunctionEntries(*FunctionMap); 201 SmallVector<StableFunction> Functions; 202 for (const auto *FuncEntry : FuncEntries) { 203 auto IndexOperandHashes = getStableIndexOperandHashes(FuncEntry); 204 Functions.emplace_back( 205 FuncEntry->Hash, *FunctionMap->getNameForId(FuncEntry->FunctionNameId), 206 *FunctionMap->getNameForId(FuncEntry->ModuleNameId), 207 FuncEntry->InstCount, std::move(IndexOperandHashes)); 208 } 209 210 YOS << Functions; 211 } 212 213 void StableFunctionMapRecord::deserializeYAML(yaml::Input &YIS) { 214 std::vector<StableFunction> Funcs; 215 YIS >> Funcs; 216 for (auto &Func : Funcs) 217 FunctionMap->insert(Func); 218 YIS.nextDocument(); 219 } 220