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