xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGenData/OutlinedHashTreeRecord.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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