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