1*0fca6ea1SDimitry Andric //===-- OutlinedHashTreeRecord.cpp ----------------------------------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This defines the OutlinedHashTreeRecord class. This class holds the outlined 10*0fca6ea1SDimitry Andric // hash tree for both serialization and deserialization processes. It utilizes 11*0fca6ea1SDimitry Andric // two data formats for serialization: raw binary data and YAML. 12*0fca6ea1SDimitry Andric // These two formats can be used interchangeably. 13*0fca6ea1SDimitry Andric // 14*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric #include "llvm/CodeGenData/OutlinedHashTreeRecord.h" 17*0fca6ea1SDimitry Andric #include "llvm/ObjectYAML/YAML.h" 18*0fca6ea1SDimitry Andric #include "llvm/Support/Endian.h" 19*0fca6ea1SDimitry Andric #include "llvm/Support/EndianStream.h" 20*0fca6ea1SDimitry Andric 21*0fca6ea1SDimitry Andric #define DEBUG_TYPE "outlined-hash-tree" 22*0fca6ea1SDimitry Andric 23*0fca6ea1SDimitry Andric using namespace llvm; 24*0fca6ea1SDimitry Andric using namespace llvm::support; 25*0fca6ea1SDimitry Andric 26*0fca6ea1SDimitry Andric namespace llvm { 27*0fca6ea1SDimitry Andric namespace yaml { 28*0fca6ea1SDimitry Andric 29*0fca6ea1SDimitry Andric template <> struct MappingTraits<HashNodeStable> { 30*0fca6ea1SDimitry Andric static void mapping(IO &io, HashNodeStable &res) { 31*0fca6ea1SDimitry Andric io.mapRequired("Hash", res.Hash); 32*0fca6ea1SDimitry Andric io.mapRequired("Terminals", res.Terminals); 33*0fca6ea1SDimitry Andric io.mapRequired("SuccessorIds", res.SuccessorIds); 34*0fca6ea1SDimitry Andric } 35*0fca6ea1SDimitry Andric }; 36*0fca6ea1SDimitry Andric 37*0fca6ea1SDimitry Andric template <> struct CustomMappingTraits<IdHashNodeStableMapTy> { 38*0fca6ea1SDimitry Andric static void inputOne(IO &io, StringRef Key, IdHashNodeStableMapTy &V) { 39*0fca6ea1SDimitry Andric HashNodeStable NodeStable; 40*0fca6ea1SDimitry Andric io.mapRequired(Key.str().c_str(), NodeStable); 41*0fca6ea1SDimitry Andric unsigned Id; 42*0fca6ea1SDimitry Andric if (Key.getAsInteger(0, Id)) { 43*0fca6ea1SDimitry Andric io.setError("Id not an integer"); 44*0fca6ea1SDimitry Andric return; 45*0fca6ea1SDimitry Andric } 46*0fca6ea1SDimitry Andric V.insert({Id, NodeStable}); 47*0fca6ea1SDimitry Andric } 48*0fca6ea1SDimitry Andric 49*0fca6ea1SDimitry Andric static void output(IO &io, IdHashNodeStableMapTy &V) { 50*0fca6ea1SDimitry Andric for (auto Iter = V.begin(); Iter != V.end(); ++Iter) 51*0fca6ea1SDimitry Andric io.mapRequired(utostr(Iter->first).c_str(), Iter->second); 52*0fca6ea1SDimitry Andric } 53*0fca6ea1SDimitry Andric }; 54*0fca6ea1SDimitry Andric 55*0fca6ea1SDimitry Andric } // namespace yaml 56*0fca6ea1SDimitry Andric } // namespace llvm 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric void OutlinedHashTreeRecord::serialize(raw_ostream &OS) const { 59*0fca6ea1SDimitry Andric IdHashNodeStableMapTy IdNodeStableMap; 60*0fca6ea1SDimitry Andric convertToStableData(IdNodeStableMap); 61*0fca6ea1SDimitry Andric support::endian::Writer Writer(OS, endianness::little); 62*0fca6ea1SDimitry Andric Writer.write<uint32_t>(IdNodeStableMap.size()); 63*0fca6ea1SDimitry Andric 64*0fca6ea1SDimitry Andric for (const auto &[Id, NodeStable] : IdNodeStableMap) { 65*0fca6ea1SDimitry Andric Writer.write<uint32_t>(Id); 66*0fca6ea1SDimitry Andric Writer.write<uint64_t>(NodeStable.Hash); 67*0fca6ea1SDimitry Andric Writer.write<uint32_t>(NodeStable.Terminals); 68*0fca6ea1SDimitry Andric Writer.write<uint32_t>(NodeStable.SuccessorIds.size()); 69*0fca6ea1SDimitry Andric for (auto SuccessorId : NodeStable.SuccessorIds) 70*0fca6ea1SDimitry Andric Writer.write<uint32_t>(SuccessorId); 71*0fca6ea1SDimitry Andric } 72*0fca6ea1SDimitry Andric } 73*0fca6ea1SDimitry Andric 74*0fca6ea1SDimitry Andric void OutlinedHashTreeRecord::deserialize(const unsigned char *&Ptr) { 75*0fca6ea1SDimitry Andric IdHashNodeStableMapTy IdNodeStableMap; 76*0fca6ea1SDimitry Andric auto NumIdNodeStableMap = 77*0fca6ea1SDimitry Andric endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 78*0fca6ea1SDimitry Andric 79*0fca6ea1SDimitry Andric for (unsigned I = 0; I < NumIdNodeStableMap; ++I) { 80*0fca6ea1SDimitry Andric auto Id = endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 81*0fca6ea1SDimitry Andric HashNodeStable NodeStable; 82*0fca6ea1SDimitry Andric NodeStable.Hash = 83*0fca6ea1SDimitry Andric endian::readNext<uint64_t, endianness::little, unaligned>(Ptr); 84*0fca6ea1SDimitry Andric NodeStable.Terminals = 85*0fca6ea1SDimitry Andric endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 86*0fca6ea1SDimitry Andric auto NumSuccessorIds = 87*0fca6ea1SDimitry Andric endian::readNext<uint32_t, endianness::little, unaligned>(Ptr); 88*0fca6ea1SDimitry Andric for (unsigned J = 0; J < NumSuccessorIds; ++J) 89*0fca6ea1SDimitry Andric NodeStable.SuccessorIds.push_back( 90*0fca6ea1SDimitry Andric endian::readNext<uint32_t, endianness::little, unaligned>(Ptr)); 91*0fca6ea1SDimitry Andric 92*0fca6ea1SDimitry Andric IdNodeStableMap[Id] = std::move(NodeStable); 93*0fca6ea1SDimitry Andric } 94*0fca6ea1SDimitry Andric 95*0fca6ea1SDimitry Andric convertFromStableData(IdNodeStableMap); 96*0fca6ea1SDimitry Andric } 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric void OutlinedHashTreeRecord::serializeYAML(yaml::Output &YOS) const { 99*0fca6ea1SDimitry Andric IdHashNodeStableMapTy IdNodeStableMap; 100*0fca6ea1SDimitry Andric convertToStableData(IdNodeStableMap); 101*0fca6ea1SDimitry Andric 102*0fca6ea1SDimitry Andric YOS << IdNodeStableMap; 103*0fca6ea1SDimitry Andric } 104*0fca6ea1SDimitry Andric 105*0fca6ea1SDimitry Andric void OutlinedHashTreeRecord::deserializeYAML(yaml::Input &YIS) { 106*0fca6ea1SDimitry Andric IdHashNodeStableMapTy IdNodeStableMap; 107*0fca6ea1SDimitry Andric 108*0fca6ea1SDimitry Andric YIS >> IdNodeStableMap; 109*0fca6ea1SDimitry Andric YIS.nextDocument(); 110*0fca6ea1SDimitry Andric 111*0fca6ea1SDimitry Andric convertFromStableData(IdNodeStableMap); 112*0fca6ea1SDimitry Andric } 113*0fca6ea1SDimitry Andric 114*0fca6ea1SDimitry Andric void OutlinedHashTreeRecord::convertToStableData( 115*0fca6ea1SDimitry Andric IdHashNodeStableMapTy &IdNodeStableMap) const { 116*0fca6ea1SDimitry Andric // Build NodeIdMap 117*0fca6ea1SDimitry Andric HashNodeIdMapTy NodeIdMap; 118*0fca6ea1SDimitry Andric HashTree->walkGraph( 119*0fca6ea1SDimitry Andric [&NodeIdMap](const HashNode *Current) { 120*0fca6ea1SDimitry Andric size_t Index = NodeIdMap.size(); 121*0fca6ea1SDimitry Andric NodeIdMap[Current] = Index; 122*0fca6ea1SDimitry Andric assert((Index + 1 == NodeIdMap.size()) && 123*0fca6ea1SDimitry Andric "Duplicate key in NodeIdMap: 'Current' should be unique."); 124*0fca6ea1SDimitry Andric }, 125*0fca6ea1SDimitry Andric /*EdgeCallbackFn=*/nullptr, /*SortedWork=*/true); 126*0fca6ea1SDimitry Andric 127*0fca6ea1SDimitry Andric // Convert NodeIdMap to NodeStableMap 128*0fca6ea1SDimitry Andric for (auto &P : NodeIdMap) { 129*0fca6ea1SDimitry Andric auto *Node = P.first; 130*0fca6ea1SDimitry Andric auto Id = P.second; 131*0fca6ea1SDimitry Andric HashNodeStable NodeStable; 132*0fca6ea1SDimitry Andric NodeStable.Hash = Node->Hash; 133*0fca6ea1SDimitry Andric NodeStable.Terminals = Node->Terminals ? *Node->Terminals : 0; 134*0fca6ea1SDimitry Andric for (auto &P : Node->Successors) 135*0fca6ea1SDimitry Andric NodeStable.SuccessorIds.push_back(NodeIdMap[P.second.get()]); 136*0fca6ea1SDimitry Andric IdNodeStableMap[Id] = NodeStable; 137*0fca6ea1SDimitry Andric } 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric // Sort the Successors so that they come out in the same order as in the map. 140*0fca6ea1SDimitry Andric for (auto &P : IdNodeStableMap) 141*0fca6ea1SDimitry Andric llvm::sort(P.second.SuccessorIds); 142*0fca6ea1SDimitry Andric } 143*0fca6ea1SDimitry Andric 144*0fca6ea1SDimitry Andric void OutlinedHashTreeRecord::convertFromStableData( 145*0fca6ea1SDimitry Andric const IdHashNodeStableMapTy &IdNodeStableMap) { 146*0fca6ea1SDimitry Andric IdHashNodeMapTy IdNodeMap; 147*0fca6ea1SDimitry Andric // Initialize the root node at 0. 148*0fca6ea1SDimitry Andric IdNodeMap[0] = HashTree->getRoot(); 149*0fca6ea1SDimitry Andric assert(IdNodeMap[0]->Successors.empty()); 150*0fca6ea1SDimitry Andric 151*0fca6ea1SDimitry Andric for (auto &P : IdNodeStableMap) { 152*0fca6ea1SDimitry Andric auto Id = P.first; 153*0fca6ea1SDimitry Andric const HashNodeStable &NodeStable = P.second; 154*0fca6ea1SDimitry Andric assert(IdNodeMap.count(Id)); 155*0fca6ea1SDimitry Andric HashNode *Curr = IdNodeMap[Id]; 156*0fca6ea1SDimitry Andric Curr->Hash = NodeStable.Hash; 157*0fca6ea1SDimitry Andric if (NodeStable.Terminals) 158*0fca6ea1SDimitry Andric Curr->Terminals = NodeStable.Terminals; 159*0fca6ea1SDimitry Andric auto &Successors = Curr->Successors; 160*0fca6ea1SDimitry Andric assert(Successors.empty()); 161*0fca6ea1SDimitry Andric for (auto SuccessorId : NodeStable.SuccessorIds) { 162*0fca6ea1SDimitry Andric auto Sucessor = std::make_unique<HashNode>(); 163*0fca6ea1SDimitry Andric IdNodeMap[SuccessorId] = Sucessor.get(); 164*0fca6ea1SDimitry Andric auto Hash = IdNodeStableMap.at(SuccessorId).Hash; 165*0fca6ea1SDimitry Andric Successors[Hash] = std::move(Sucessor); 166*0fca6ea1SDimitry Andric } 167*0fca6ea1SDimitry Andric } 168*0fca6ea1SDimitry Andric } 169