| //===-- OutlinedHashTreeRecord.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 defines the OutlinedHashTreeRecord class. This class holds the outlined | |
| // hash tree for both serialization and deserialization processes. It utilizes | |
| // two data formats for serialization: raw binary data and YAML. | |
| // These two formats can be used interchangeably. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/CGData/OutlinedHashTreeRecord.h" | |
| #include "llvm/ObjectYAML/YAML.h" | |
| #include "llvm/Support/Endian.h" | |
| #include "llvm/Support/EndianStream.h" | |
| #define DEBUG_TYPE "outlined-hash-tree" | |
| using namespace llvm; | |
| using namespace llvm::support; | |
| namespace llvm { | |
| namespace yaml { | |
| template <> struct MappingTraits<HashNodeStable> { | |
| static void mapping(IO &io, HashNodeStable &res) { | |
| io.mapRequired("Hash", res.Hash); | |
| io.mapRequired("Terminals", res.Terminals); | |
| io.mapRequired("SuccessorIds", res.SuccessorIds); | |
| } | |
| }; | |
| template <> struct CustomMappingTraits<IdHashNodeStableMapTy> { | |
| static void inputOne(IO &io, StringRef Key, IdHashNodeStableMapTy &V) { | |
| HashNodeStable NodeStable; | |
| io.mapRequired(Key, NodeStable); | |
| unsigned Id; | |
| if (Key.getAsInteger(0, Id)) { | |
| io.setError("Id not an integer"); | |
| return; | |
| } | |
| V.insert({Id, NodeStable}); | |
| } | |
| static void output(IO &io, IdHashNodeStableMapTy &V) { | |
| for (auto Iter = V.begin(); Iter != V.end(); ++Iter) | |
| io.mapRequired(utostr(Iter->first), Iter->second); | |
| } | |
| }; | |
| } // namespace yaml | |
| } // namespace llvm | |
| void OutlinedHashTreeRecord::serialize(raw_ostream &OS) const { | |
| IdHashNodeStableMapTy IdNodeStableMap; | |
| convertToStableData(IdNodeStableMap); | |
| support::endian::Writer Writer(OS, endianness::little); | |
| Writer.write<uint32_t>(IdNodeStableMap.size()); | |
| for (const auto &[Id, NodeStable] : IdNodeStableMap) { | |
| Writer.write<uint32_t>(Id); | |
| Writer.write<uint64_t>(NodeStable.Hash); | |
| Writer.write<uint32_t>(NodeStable.Terminals); | |
| Writer.write<uint32_t>(NodeStable.SuccessorIds.size()); | |
| for (auto SuccessorId : NodeStable.SuccessorIds) | |
| Writer.write<uint32_t>(SuccessorId); | |
| } | |
| } | |
| void OutlinedHashTreeRecord::deserialize(const unsigned char *&Ptr) { | |
| IdHashNodeStableMapTy IdNodeStableMap; | |
| auto NumIdNodeStableMap = | |
| endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); | |
| for (unsigned I = 0; I < NumIdNodeStableMap; ++I) { | |
| auto Id = endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); | |
| HashNodeStable NodeStable; | |
| NodeStable.Hash = | |
| endian::readNext<uint64_t, endianness::little, unaligned>(Ptr); | |
| NodeStable.Terminals = | |
| endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); | |
| auto NumSuccessorIds = | |
| endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); | |
| for (unsigned J = 0; J < NumSuccessorIds; ++J) | |
| NodeStable.SuccessorIds.push_back( | |
| endian::readNext<uint32_t, endianness::little, unaligned>(Ptr)); | |
| IdNodeStableMap[Id] = std::move(NodeStable); | |
| } | |
| convertFromStableData(IdNodeStableMap); | |
| } | |
| void OutlinedHashTreeRecord::serializeYAML(yaml::Output &YOS) const { | |
| IdHashNodeStableMapTy IdNodeStableMap; | |
| convertToStableData(IdNodeStableMap); | |
| YOS << IdNodeStableMap; | |
| } | |
| void OutlinedHashTreeRecord::deserializeYAML(yaml::Input &YIS) { | |
| IdHashNodeStableMapTy IdNodeStableMap; | |
| YIS >> IdNodeStableMap; | |
| YIS.nextDocument(); | |
| convertFromStableData(IdNodeStableMap); | |
| } | |
| void OutlinedHashTreeRecord::convertToStableData( | |
| IdHashNodeStableMapTy &IdNodeStableMap) const { | |
| // Build NodeIdMap | |
| HashNodeIdMapTy NodeIdMap; | |
| HashTree->walkGraph( | |
| [&NodeIdMap](const HashNode *Current) { | |
| size_t Index = NodeIdMap.size(); | |
| NodeIdMap[Current] = Index; | |
| assert((Index + 1 == NodeIdMap.size()) && | |
| "Duplicate key in NodeIdMap: 'Current' should be unique."); | |
| }, | |
| /*EdgeCallbackFn=*/nullptr, /*SortedWork=*/true); | |
| // Convert NodeIdMap to NodeStableMap | |
| for (auto &P : NodeIdMap) { | |
| auto *Node = P.first; | |
| auto Id = P.second; | |
| HashNodeStable NodeStable; | |
| NodeStable.Hash = Node->Hash; | |
| NodeStable.Terminals = Node->Terminals.value_or(0); | |
| for (auto &P : Node->Successors) | |
| NodeStable.SuccessorIds.push_back(NodeIdMap[P.second.get()]); | |
| IdNodeStableMap[Id] = NodeStable; | |
| } | |
| // Sort the Successors so that they come out in the same order as in the map. | |
| for (auto &P : IdNodeStableMap) | |
| llvm::sort(P.second.SuccessorIds); | |
| } | |
| void OutlinedHashTreeRecord::convertFromStableData( | |
| const IdHashNodeStableMapTy &IdNodeStableMap) { | |
| IdHashNodeMapTy IdNodeMap; | |
| // Initialize the root node at 0. | |
| IdNodeMap[0] = HashTree->getRoot(); | |
| assert(IdNodeMap[0]->Successors.empty()); | |
| for (auto &P : IdNodeStableMap) { | |
| auto Id = P.first; | |
| const HashNodeStable &NodeStable = P.second; | |
| assert(IdNodeMap.count(Id)); | |
| HashNode *Curr = IdNodeMap[Id]; | |
| Curr->Hash = NodeStable.Hash; | |
| if (NodeStable.Terminals) | |
| Curr->Terminals = NodeStable.Terminals; | |
| auto &Successors = Curr->Successors; | |
| assert(Successors.empty()); | |
| for (auto SuccessorId : NodeStable.SuccessorIds) { | |
| auto Sucessor = std::make_unique<HashNode>(); | |
| IdNodeMap[SuccessorId] = Sucessor.get(); | |
| auto Hash = IdNodeStableMap.at(SuccessorId).Hash; | |
| Successors[Hash] = std::move(Sucessor); | |
| } | |
| } | |
| } |