diff options
Diffstat (limited to 'llvm/lib/CGData')
-rw-r--r-- | llvm/lib/CGData/CMakeLists.txt | 2 | ||||
-rw-r--r-- | llvm/lib/CGData/StableFunctionMap.cpp | 170 | ||||
-rw-r--r-- | llvm/lib/CGData/StableFunctionMapRecord.cpp | 203 |
3 files changed, 375 insertions, 0 deletions
diff --git a/llvm/lib/CGData/CMakeLists.txt b/llvm/lib/CGData/CMakeLists.txt index 157b0df..0031731 100644 --- a/llvm/lib/CGData/CMakeLists.txt +++ b/llvm/lib/CGData/CMakeLists.txt @@ -4,6 +4,8 @@ add_llvm_component_library(LLVMCGData CodeGenDataWriter.cpp OutlinedHashTree.cpp OutlinedHashTreeRecord.cpp + StableFunctionMap.cpp + StableFunctionMapRecord.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/CGData diff --git a/llvm/lib/CGData/StableFunctionMap.cpp b/llvm/lib/CGData/StableFunctionMap.cpp new file mode 100644 index 0000000..638f92d --- /dev/null +++ b/llvm/lib/CGData/StableFunctionMap.cpp @@ -0,0 +1,170 @@ +//===-- StableFunctionMap.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This implements the functionality for the StableFunctionMap class, which +// manages the mapping of stable function hashes to their metadata. It includes +// methods for inserting, merging, and finalizing function entries, as well as +// utilities for handling function names and IDs. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CGData/StableFunctionMap.h" + +#define DEBUG_TYPE "stable-function-map" + +using namespace llvm; + +unsigned StableFunctionMap::getIdOrCreateForName(StringRef Name) { + auto It = NameToId.find(Name); + if (It == NameToId.end()) { + unsigned Id = IdToName.size(); + assert(Id == NameToId.size() && "ID collision"); + IdToName.emplace_back(Name.str()); + NameToId[IdToName.back()] = Id; + return Id; + } else { + return It->second; + } +} + +std::optional<std::string> StableFunctionMap::getNameForId(unsigned Id) const { + if (Id >= IdToName.size()) + return std::nullopt; + return IdToName[Id]; +} + +void StableFunctionMap::insert(const StableFunction &Func) { + assert(!Finalized && "Cannot insert after finalization"); + auto FuncNameId = getIdOrCreateForName(Func.FunctionName); + auto ModuleNameId = getIdOrCreateForName(Func.ModuleName); + auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>(); + for (auto &[Index, Hash] : Func.IndexOperandHashes) + (*IndexOperandHashMap)[Index] = Hash; + auto FuncEntry = std::make_unique<StableFunctionEntry>( + Func.Hash, FuncNameId, ModuleNameId, Func.InstCount, + std::move(IndexOperandHashMap)); + insert(std::move(FuncEntry)); +} + +void StableFunctionMap::merge(const StableFunctionMap &OtherMap) { + assert(!Finalized && "Cannot merge after finalization"); + for (auto &[Hash, Funcs] : OtherMap.HashToFuncs) { + auto &ThisFuncs = HashToFuncs[Hash]; + for (auto &Func : Funcs) { + auto FuncNameId = + getIdOrCreateForName(*OtherMap.getNameForId(Func->FunctionNameId)); + auto ModuleNameId = + getIdOrCreateForName(*OtherMap.getNameForId(Func->ModuleNameId)); + auto ClonedIndexOperandHashMap = + std::make_unique<IndexOperandHashMapType>(*Func->IndexOperandHashMap); + ThisFuncs.emplace_back(std::make_unique<StableFunctionEntry>( + Func->Hash, FuncNameId, ModuleNameId, Func->InstCount, + std::move(ClonedIndexOperandHashMap))); + } + } +} + +size_t StableFunctionMap::size(SizeType Type) const { + switch (Type) { + case UniqueHashCount: + return HashToFuncs.size(); + case TotalFunctionCount: { + size_t Count = 0; + for (auto &Funcs : HashToFuncs) + Count += Funcs.second.size(); + return Count; + } + case MergeableFunctionCount: { + size_t Count = 0; + for (auto &[Hash, Funcs] : HashToFuncs) + if (Funcs.size() >= 2) + Count += Funcs.size(); + return Count; + } + } + return 0; +} + +using ParamLocs = SmallVector<IndexPair>; +static void removeIdenticalIndexPair( + SmallVector<std::unique_ptr<StableFunctionEntry>> &SFS) { + auto &RSF = SFS[0]; + unsigned StableFunctionCount = SFS.size(); + + SmallVector<IndexPair> ToDelete; + for (auto &[Pair, Hash] : *(RSF->IndexOperandHashMap)) { + bool Identical = true; + for (unsigned J = 1; J < StableFunctionCount; ++J) { + auto &SF = SFS[J]; + assert(SF->IndexOperandHashMap->count(Pair)); + auto SHash = (*SF->IndexOperandHashMap)[Pair]; + if (Hash != SHash) { + Identical = false; + break; + } + } + + // No need to parameterize them if the hashes are identical across stable + // functions. + if (Identical) + ToDelete.emplace_back(Pair); + } + + for (auto &Pair : ToDelete) + for (auto &SF : SFS) + SF->IndexOperandHashMap->erase(Pair); +} + +void StableFunctionMap::finalize() { + Finalized = true; + + for (auto It = HashToFuncs.begin(); It != HashToFuncs.end(); ++It) { + auto &[StableHash, SFS] = *It; + + // Group stable functions by ModuleIdentifier. + std::stable_sort(SFS.begin(), SFS.end(), + [&](const std::unique_ptr<StableFunctionEntry> &L, + const std::unique_ptr<StableFunctionEntry> &R) { + return *getNameForId(L->ModuleNameId) < + *getNameForId(R->ModuleNameId); + }); + + // Consider the first function as the root function. + auto &RSF = SFS[0]; + + bool IsValid = true; + unsigned StableFunctionCount = SFS.size(); + for (unsigned I = 1; I < StableFunctionCount; ++I) { + auto &SF = SFS[I]; + assert(RSF->Hash == SF->Hash); + if (RSF->InstCount != SF->InstCount) { + IsValid = false; + break; + } + if (RSF->IndexOperandHashMap->size() != SF->IndexOperandHashMap->size()) { + IsValid = false; + break; + } + for (auto &P : *RSF->IndexOperandHashMap) { + auto &InstOpndIndex = P.first; + if (!SF->IndexOperandHashMap->count(InstOpndIndex)) { + IsValid = false; + break; + } + } + } + if (!IsValid) { + HashToFuncs.erase(It); + continue; + } + + // Trim the index pair that has the same operand hash across + // stable functions. + removeIdenticalIndexPair(SFS); + } +} diff --git a/llvm/lib/CGData/StableFunctionMapRecord.cpp b/llvm/lib/CGData/StableFunctionMapRecord.cpp new file mode 100644 index 0000000..05c96f8 --- /dev/null +++ b/llvm/lib/CGData/StableFunctionMapRecord.cpp @@ -0,0 +1,203 @@ +//===-- StableFunctionMapRecord.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This implements the functionality for the StableFunctionMapRecord class, +// including methods for serialization and deserialization of stable function +// maps to and from raw and YAML streams. It also includes utilities for +// managing function entries and their metadata. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CGData/StableFunctionMapRecord.h" +#include "llvm/Support/EndianStream.h" + +#define DEBUG_TYPE "stable-function-map-record" + +using namespace llvm; +using namespace llvm::support; + +LLVM_YAML_IS_SEQUENCE_VECTOR(IndexPairHash) +LLVM_YAML_IS_SEQUENCE_VECTOR(StableFunction) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits<IndexPairHash> { + static void mapping(IO &IO, IndexPairHash &Key) { + IO.mapRequired("InstIndex", Key.first.first); + IO.mapRequired("OpndIndex", Key.first.second); + IO.mapRequired("OpndHash", Key.second); + } +}; + +template <> struct MappingTraits<StableFunction> { + static void mapping(IO &IO, StableFunction &Func) { + IO.mapRequired("Hash", Func.Hash); + IO.mapRequired("FunctionName", Func.FunctionName); + IO.mapRequired("ModuleName", Func.ModuleName); + IO.mapRequired("InstCount", Func.InstCount); + IO.mapRequired("IndexOperandHashes", Func.IndexOperandHashes); + } +}; + +} // namespace yaml +} // namespace llvm + +// Get a sorted vector of StableFunctionEntry pointers. +static SmallVector<const StableFunctionEntry *> +getStableFunctionEntries(const StableFunctionMap &SFM) { + SmallVector<const StableFunctionEntry *> FuncEntries; + for (const auto &P : SFM.getFunctionMap()) + for (auto &Func : P.second) + FuncEntries.emplace_back(Func.get()); + + std::stable_sort( + FuncEntries.begin(), FuncEntries.end(), [&](auto &A, auto &B) { + return std::tuple(A->Hash, SFM.getNameForId(A->ModuleNameId), + SFM.getNameForId(A->FunctionNameId)) < + std::tuple(B->Hash, SFM.getNameForId(B->ModuleNameId), + SFM.getNameForId(B->FunctionNameId)); + }); + return FuncEntries; +} + +// Get a sorted vector of IndexOperandHashes. +static IndexOperandHashVecType +getStableIndexOperandHashes(const StableFunctionEntry *FuncEntry) { + IndexOperandHashVecType IndexOperandHashes; + for (auto &[Indices, OpndHash] : *FuncEntry->IndexOperandHashMap) + IndexOperandHashes.emplace_back(Indices, OpndHash); + std::sort(IndexOperandHashes.begin(), IndexOperandHashes.end(), + [](auto &A, auto &B) { return A.first < B.first; }); + return IndexOperandHashes; +} + +void StableFunctionMapRecord::serialize(raw_ostream &OS) const { + serialize(OS, FunctionMap.get()); +} + +void StableFunctionMapRecord::serialize(raw_ostream &OS, + const StableFunctionMap *FunctionMap) { + support::endian::Writer Writer(OS, endianness::little); + + // Write Names. + auto &Names = FunctionMap->getNames(); + uint32_t ByteSize = 4; + Writer.write<uint32_t>(Names.size()); + for (auto &Name : Names) { + Writer.OS << Name << '\0'; + ByteSize += Name.size() + 1; + } + // Align ByteSize to 4 bytes. + uint32_t Padding = offsetToAlignment(ByteSize, Align(4)); + for (uint32_t I = 0; I < Padding; ++I) + Writer.OS << '\0'; + + // Write StableFunctionEntries whose pointers are sorted. + auto FuncEntries = getStableFunctionEntries(*FunctionMap); + Writer.write<uint32_t>(FuncEntries.size()); + + for (const auto *FuncRef : FuncEntries) { + Writer.write<stable_hash>(FuncRef->Hash); + Writer.write<uint32_t>(FuncRef->FunctionNameId); + Writer.write<uint32_t>(FuncRef->ModuleNameId); + Writer.write<uint32_t>(FuncRef->InstCount); + + // Emit IndexOperandHashes sorted from IndexOperandHashMap. + IndexOperandHashVecType IndexOperandHashes = + getStableIndexOperandHashes(FuncRef); + Writer.write<uint32_t>(IndexOperandHashes.size()); + for (auto &IndexOperandHash : IndexOperandHashes) { + Writer.write<uint32_t>(IndexOperandHash.first.first); + Writer.write<uint32_t>(IndexOperandHash.first.second); + Writer.write<stable_hash>(IndexOperandHash.second); + } + } +} + +void StableFunctionMapRecord::deserialize(const unsigned char *&Ptr) { + // Assert that Ptr is 4-byte aligned + assert(((uintptr_t)Ptr % 4) == 0); + // Read Names. + auto NumNames = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + // Early exit if there is no name. + if (NumNames == 0) + return; + for (unsigned I = 0; I < NumNames; ++I) { + std::string Name(reinterpret_cast<const char *>(Ptr)); + Ptr += Name.size() + 1; + FunctionMap->getIdOrCreateForName(Name); + } + // Align Ptr to 4 bytes. + Ptr = reinterpret_cast<const uint8_t *>(alignAddr(Ptr, Align(4))); + + // Read StableFunctionEntries. + auto NumFuncs = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + for (unsigned I = 0; I < NumFuncs; ++I) { + auto Hash = + endian::readNext<stable_hash, endianness::little, unaligned>(Ptr); + auto FunctionNameId = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + assert(FunctionMap->getNameForId(FunctionNameId) && + "FunctionNameId out of range"); + auto ModuleNameId = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + assert(FunctionMap->getNameForId(ModuleNameId) && + "ModuleNameId out of range"); + auto InstCount = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + + // Read IndexOperandHashes to build IndexOperandHashMap + auto NumIndexOperandHashes = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + auto IndexOperandHashMap = std::make_unique<IndexOperandHashMapType>(); + for (unsigned J = 0; J < NumIndexOperandHashes; ++J) { + auto InstIndex = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + auto OpndIndex = + endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); + auto OpndHash = + endian::readNext<stable_hash, endianness::little, unaligned>(Ptr); + assert(InstIndex < InstCount && "InstIndex out of range"); + + auto Indices = std::make_pair(InstIndex, OpndIndex); + (*IndexOperandHashMap)[Indices] = OpndHash; + } + + // Insert a new StableFunctionEntry into the map. + auto FuncEntry = std::make_unique<StableFunctionEntry>( + Hash, FunctionNameId, ModuleNameId, InstCount, + std::move(IndexOperandHashMap)); + + FunctionMap->insert(std::move(FuncEntry)); + } +} + +void StableFunctionMapRecord::serializeYAML(yaml::Output &YOS) const { + auto FuncEntries = getStableFunctionEntries(*FunctionMap); + SmallVector<StableFunction> Functions; + for (const auto *FuncEntry : FuncEntries) { + auto IndexOperandHashes = getStableIndexOperandHashes(FuncEntry); + Functions.emplace_back( + FuncEntry->Hash, *FunctionMap->getNameForId(FuncEntry->FunctionNameId), + *FunctionMap->getNameForId(FuncEntry->ModuleNameId), + FuncEntry->InstCount, std::move(IndexOperandHashes)); + } + + YOS << Functions; +} + +void StableFunctionMapRecord::deserializeYAML(yaml::Input &YIS) { + std::vector<StableFunction> Funcs; + YIS >> Funcs; + for (auto &Func : Funcs) + FunctionMap->insert(Func); + YIS.nextDocument(); +} |