xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/ImmutableGraph.h (revision 0946e70a3b60dec23922cf3e0c313cb0917fee0a)
1*0946e70aSDimitry Andric //==========-- ImmutableGraph.h - A fast DAG implementation ---------=========//
2*0946e70aSDimitry Andric //
3*0946e70aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0946e70aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0946e70aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0946e70aSDimitry Andric //
7*0946e70aSDimitry Andric //===----------------------------------------------------------------------===//
8*0946e70aSDimitry Andric ///
9*0946e70aSDimitry Andric /// Description: ImmutableGraph is a fast DAG implementation that cannot be
10*0946e70aSDimitry Andric /// modified, except by creating a new ImmutableGraph. ImmutableGraph is
11*0946e70aSDimitry Andric /// implemented as two arrays: one containing nodes, and one containing edges.
12*0946e70aSDimitry Andric /// The advantages to this implementation are two-fold:
13*0946e70aSDimitry Andric /// 1. Iteration and traversal operations benefit from cache locality.
14*0946e70aSDimitry Andric /// 2. Operations on sets of nodes/edges are efficient, and representations of
15*0946e70aSDimitry Andric ///    those sets in memory are compact. For instance, a set of edges is
16*0946e70aSDimitry Andric ///    implemented as a bit vector, wherein each bit corresponds to one edge in
17*0946e70aSDimitry Andric ///    the edge array. This implies a lower bound of 64x spatial improvement
18*0946e70aSDimitry Andric ///    over, e.g., an llvm::DenseSet or llvm::SmallSet. It also means that
19*0946e70aSDimitry Andric ///    insert/erase/contains operations complete in negligible constant time:
20*0946e70aSDimitry Andric ///    insert and erase require one load and one store, and contains requires
21*0946e70aSDimitry Andric ///    just one load.
22*0946e70aSDimitry Andric ///
23*0946e70aSDimitry Andric //===----------------------------------------------------------------------===//
24*0946e70aSDimitry Andric 
25*0946e70aSDimitry Andric #ifndef LLVM_LIB_TARGET_X86_IMMUTABLEGRAPH_H
26*0946e70aSDimitry Andric #define LLVM_LIB_TARGET_X86_IMMUTABLEGRAPH_H
27*0946e70aSDimitry Andric 
28*0946e70aSDimitry Andric #include "llvm/ADT/BitVector.h"
29*0946e70aSDimitry Andric #include "llvm/ADT/GraphTraits.h"
30*0946e70aSDimitry Andric #include "llvm/ADT/STLExtras.h"
31*0946e70aSDimitry Andric #include "llvm/Support/raw_ostream.h"
32*0946e70aSDimitry Andric #include <algorithm>
33*0946e70aSDimitry Andric #include <iterator>
34*0946e70aSDimitry Andric #include <utility>
35*0946e70aSDimitry Andric #include <vector>
36*0946e70aSDimitry Andric 
37*0946e70aSDimitry Andric namespace llvm {
38*0946e70aSDimitry Andric 
39*0946e70aSDimitry Andric template <typename NodeValueT, typename EdgeValueT> class ImmutableGraph {
40*0946e70aSDimitry Andric   using Traits = GraphTraits<ImmutableGraph<NodeValueT, EdgeValueT> *>;
41*0946e70aSDimitry Andric   template <typename> friend class ImmutableGraphBuilder;
42*0946e70aSDimitry Andric 
43*0946e70aSDimitry Andric public:
44*0946e70aSDimitry Andric   using node_value_type = NodeValueT;
45*0946e70aSDimitry Andric   using edge_value_type = EdgeValueT;
46*0946e70aSDimitry Andric   using size_type = int;
47*0946e70aSDimitry Andric   class Node;
48*0946e70aSDimitry Andric   class Edge {
49*0946e70aSDimitry Andric     friend class ImmutableGraph;
50*0946e70aSDimitry Andric     template <typename> friend class ImmutableGraphBuilder;
51*0946e70aSDimitry Andric 
52*0946e70aSDimitry Andric     const Node *Dest;
53*0946e70aSDimitry Andric     edge_value_type Value;
54*0946e70aSDimitry Andric 
55*0946e70aSDimitry Andric   public:
56*0946e70aSDimitry Andric     const Node *getDest() const { return Dest; };
57*0946e70aSDimitry Andric     const edge_value_type &getValue() const { return Value; }
58*0946e70aSDimitry Andric   };
59*0946e70aSDimitry Andric   class Node {
60*0946e70aSDimitry Andric     friend class ImmutableGraph;
61*0946e70aSDimitry Andric     template <typename> friend class ImmutableGraphBuilder;
62*0946e70aSDimitry Andric 
63*0946e70aSDimitry Andric     const Edge *Edges;
64*0946e70aSDimitry Andric     node_value_type Value;
65*0946e70aSDimitry Andric 
66*0946e70aSDimitry Andric   public:
67*0946e70aSDimitry Andric     const node_value_type &getValue() const { return Value; }
68*0946e70aSDimitry Andric 
69*0946e70aSDimitry Andric     const Edge *edges_begin() const { return Edges; }
70*0946e70aSDimitry Andric     // Nodes are allocated sequentially. Edges for a node are stored together.
71*0946e70aSDimitry Andric     // The end of this Node's edges is the beginning of the next node's edges.
72*0946e70aSDimitry Andric     // An extra node was allocated to hold the end pointer for the last real
73*0946e70aSDimitry Andric     // node.
74*0946e70aSDimitry Andric     const Edge *edges_end() const { return (this + 1)->Edges; }
75*0946e70aSDimitry Andric     ArrayRef<Edge> edges() const {
76*0946e70aSDimitry Andric       return makeArrayRef(edges_begin(), edges_end());
77*0946e70aSDimitry Andric     }
78*0946e70aSDimitry Andric   };
79*0946e70aSDimitry Andric 
80*0946e70aSDimitry Andric protected:
81*0946e70aSDimitry Andric   ImmutableGraph(std::unique_ptr<Node[]> Nodes, std::unique_ptr<Edge[]> Edges,
82*0946e70aSDimitry Andric                  size_type NodesSize, size_type EdgesSize)
83*0946e70aSDimitry Andric       : Nodes(std::move(Nodes)), Edges(std::move(Edges)), NodesSize(NodesSize),
84*0946e70aSDimitry Andric         EdgesSize(EdgesSize) {}
85*0946e70aSDimitry Andric   ImmutableGraph(const ImmutableGraph &) = delete;
86*0946e70aSDimitry Andric   ImmutableGraph(ImmutableGraph &&) = delete;
87*0946e70aSDimitry Andric   ImmutableGraph &operator=(const ImmutableGraph &) = delete;
88*0946e70aSDimitry Andric   ImmutableGraph &operator=(ImmutableGraph &&) = delete;
89*0946e70aSDimitry Andric 
90*0946e70aSDimitry Andric public:
91*0946e70aSDimitry Andric   ArrayRef<Node> nodes() const { return makeArrayRef(Nodes.get(), NodesSize); }
92*0946e70aSDimitry Andric   const Node *nodes_begin() const { return nodes().begin(); }
93*0946e70aSDimitry Andric   const Node *nodes_end() const { return nodes().end(); }
94*0946e70aSDimitry Andric 
95*0946e70aSDimitry Andric   ArrayRef<Edge> edges() const { return makeArrayRef(Edges.get(), EdgesSize); }
96*0946e70aSDimitry Andric   const Edge *edges_begin() const { return edges().begin(); }
97*0946e70aSDimitry Andric   const Edge *edges_end() const { return edges().end(); }
98*0946e70aSDimitry Andric 
99*0946e70aSDimitry Andric   size_type nodes_size() const { return NodesSize; }
100*0946e70aSDimitry Andric   size_type edges_size() const { return EdgesSize; }
101*0946e70aSDimitry Andric 
102*0946e70aSDimitry Andric   // Node N must belong to this ImmutableGraph.
103*0946e70aSDimitry Andric   size_type getNodeIndex(const Node &N) const {
104*0946e70aSDimitry Andric     return std::distance(nodes_begin(), &N);
105*0946e70aSDimitry Andric   }
106*0946e70aSDimitry Andric   // Edge E must belong to this ImmutableGraph.
107*0946e70aSDimitry Andric   size_type getEdgeIndex(const Edge &E) const {
108*0946e70aSDimitry Andric     return std::distance(edges_begin(), &E);
109*0946e70aSDimitry Andric   }
110*0946e70aSDimitry Andric 
111*0946e70aSDimitry Andric   // FIXME: Could NodeSet and EdgeSet be templated to share code?
112*0946e70aSDimitry Andric   class NodeSet {
113*0946e70aSDimitry Andric     const ImmutableGraph &G;
114*0946e70aSDimitry Andric     BitVector V;
115*0946e70aSDimitry Andric 
116*0946e70aSDimitry Andric   public:
117*0946e70aSDimitry Andric     NodeSet(const ImmutableGraph &G, bool ContainsAll = false)
118*0946e70aSDimitry Andric         : G{G}, V{static_cast<unsigned>(G.nodes_size()), ContainsAll} {}
119*0946e70aSDimitry Andric     bool insert(const Node &N) {
120*0946e70aSDimitry Andric       size_type Idx = G.getNodeIndex(N);
121*0946e70aSDimitry Andric       bool AlreadyExists = V.test(Idx);
122*0946e70aSDimitry Andric       V.set(Idx);
123*0946e70aSDimitry Andric       return !AlreadyExists;
124*0946e70aSDimitry Andric     }
125*0946e70aSDimitry Andric     void erase(const Node &N) {
126*0946e70aSDimitry Andric       size_type Idx = G.getNodeIndex(N);
127*0946e70aSDimitry Andric       V.reset(Idx);
128*0946e70aSDimitry Andric     }
129*0946e70aSDimitry Andric     bool contains(const Node &N) const {
130*0946e70aSDimitry Andric       size_type Idx = G.getNodeIndex(N);
131*0946e70aSDimitry Andric       return V.test(Idx);
132*0946e70aSDimitry Andric     }
133*0946e70aSDimitry Andric     void clear() { V.reset(); }
134*0946e70aSDimitry Andric     size_type empty() const { return V.none(); }
135*0946e70aSDimitry Andric     /// Return the number of elements in the set
136*0946e70aSDimitry Andric     size_type count() const { return V.count(); }
137*0946e70aSDimitry Andric     /// Return the size of the set's domain
138*0946e70aSDimitry Andric     size_type size() const { return V.size(); }
139*0946e70aSDimitry Andric     /// Set union
140*0946e70aSDimitry Andric     NodeSet &operator|=(const NodeSet &RHS) {
141*0946e70aSDimitry Andric       assert(&this->G == &RHS.G);
142*0946e70aSDimitry Andric       V |= RHS.V;
143*0946e70aSDimitry Andric       return *this;
144*0946e70aSDimitry Andric     }
145*0946e70aSDimitry Andric     /// Set intersection
146*0946e70aSDimitry Andric     NodeSet &operator&=(const NodeSet &RHS) {
147*0946e70aSDimitry Andric       assert(&this->G == &RHS.G);
148*0946e70aSDimitry Andric       V &= RHS.V;
149*0946e70aSDimitry Andric       return *this;
150*0946e70aSDimitry Andric     }
151*0946e70aSDimitry Andric     /// Set disjoint union
152*0946e70aSDimitry Andric     NodeSet &operator^=(const NodeSet &RHS) {
153*0946e70aSDimitry Andric       assert(&this->G == &RHS.G);
154*0946e70aSDimitry Andric       V ^= RHS.V;
155*0946e70aSDimitry Andric       return *this;
156*0946e70aSDimitry Andric     }
157*0946e70aSDimitry Andric 
158*0946e70aSDimitry Andric     using index_iterator = typename BitVector::const_set_bits_iterator;
159*0946e70aSDimitry Andric     index_iterator index_begin() const { return V.set_bits_begin(); }
160*0946e70aSDimitry Andric     index_iterator index_end() const { return V.set_bits_end(); }
161*0946e70aSDimitry Andric     void set(size_type Idx) { V.set(Idx); }
162*0946e70aSDimitry Andric     void reset(size_type Idx) { V.reset(Idx); }
163*0946e70aSDimitry Andric 
164*0946e70aSDimitry Andric     class iterator {
165*0946e70aSDimitry Andric       const NodeSet &Set;
166*0946e70aSDimitry Andric       size_type Current;
167*0946e70aSDimitry Andric 
168*0946e70aSDimitry Andric       void advance() {
169*0946e70aSDimitry Andric         assert(Current != -1);
170*0946e70aSDimitry Andric         Current = Set.V.find_next(Current);
171*0946e70aSDimitry Andric       }
172*0946e70aSDimitry Andric 
173*0946e70aSDimitry Andric     public:
174*0946e70aSDimitry Andric       iterator(const NodeSet &Set, size_type Begin)
175*0946e70aSDimitry Andric           : Set{Set}, Current{Begin} {}
176*0946e70aSDimitry Andric       iterator operator++(int) {
177*0946e70aSDimitry Andric         iterator Tmp = *this;
178*0946e70aSDimitry Andric         advance();
179*0946e70aSDimitry Andric         return Tmp;
180*0946e70aSDimitry Andric       }
181*0946e70aSDimitry Andric       iterator &operator++() {
182*0946e70aSDimitry Andric         advance();
183*0946e70aSDimitry Andric         return *this;
184*0946e70aSDimitry Andric       }
185*0946e70aSDimitry Andric       Node *operator*() const {
186*0946e70aSDimitry Andric         assert(Current != -1);
187*0946e70aSDimitry Andric         return Set.G.nodes_begin() + Current;
188*0946e70aSDimitry Andric       }
189*0946e70aSDimitry Andric       bool operator==(const iterator &other) const {
190*0946e70aSDimitry Andric         assert(&this->Set == &other.Set);
191*0946e70aSDimitry Andric         return this->Current == other.Current;
192*0946e70aSDimitry Andric       }
193*0946e70aSDimitry Andric       bool operator!=(const iterator &other) const { return !(*this == other); }
194*0946e70aSDimitry Andric     };
195*0946e70aSDimitry Andric 
196*0946e70aSDimitry Andric     iterator begin() const { return iterator{*this, V.find_first()}; }
197*0946e70aSDimitry Andric     iterator end() const { return iterator{*this, -1}; }
198*0946e70aSDimitry Andric   };
199*0946e70aSDimitry Andric 
200*0946e70aSDimitry Andric   class EdgeSet {
201*0946e70aSDimitry Andric     const ImmutableGraph &G;
202*0946e70aSDimitry Andric     BitVector V;
203*0946e70aSDimitry Andric 
204*0946e70aSDimitry Andric   public:
205*0946e70aSDimitry Andric     EdgeSet(const ImmutableGraph &G, bool ContainsAll = false)
206*0946e70aSDimitry Andric         : G{G}, V{static_cast<unsigned>(G.edges_size()), ContainsAll} {}
207*0946e70aSDimitry Andric     bool insert(const Edge &E) {
208*0946e70aSDimitry Andric       size_type Idx = G.getEdgeIndex(E);
209*0946e70aSDimitry Andric       bool AlreadyExists = V.test(Idx);
210*0946e70aSDimitry Andric       V.set(Idx);
211*0946e70aSDimitry Andric       return !AlreadyExists;
212*0946e70aSDimitry Andric     }
213*0946e70aSDimitry Andric     void erase(const Edge &E) {
214*0946e70aSDimitry Andric       size_type Idx = G.getEdgeIndex(E);
215*0946e70aSDimitry Andric       V.reset(Idx);
216*0946e70aSDimitry Andric     }
217*0946e70aSDimitry Andric     bool contains(const Edge &E) const {
218*0946e70aSDimitry Andric       size_type Idx = G.getEdgeIndex(E);
219*0946e70aSDimitry Andric       return V.test(Idx);
220*0946e70aSDimitry Andric     }
221*0946e70aSDimitry Andric     void clear() { V.reset(); }
222*0946e70aSDimitry Andric     bool empty() const { return V.none(); }
223*0946e70aSDimitry Andric     /// Return the number of elements in the set
224*0946e70aSDimitry Andric     size_type count() const { return V.count(); }
225*0946e70aSDimitry Andric     /// Return the size of the set's domain
226*0946e70aSDimitry Andric     size_type size() const { return V.size(); }
227*0946e70aSDimitry Andric     /// Set union
228*0946e70aSDimitry Andric     EdgeSet &operator|=(const EdgeSet &RHS) {
229*0946e70aSDimitry Andric       assert(&this->G == &RHS.G);
230*0946e70aSDimitry Andric       V |= RHS.V;
231*0946e70aSDimitry Andric       return *this;
232*0946e70aSDimitry Andric     }
233*0946e70aSDimitry Andric     /// Set intersection
234*0946e70aSDimitry Andric     EdgeSet &operator&=(const EdgeSet &RHS) {
235*0946e70aSDimitry Andric       assert(&this->G == &RHS.G);
236*0946e70aSDimitry Andric       V &= RHS.V;
237*0946e70aSDimitry Andric       return *this;
238*0946e70aSDimitry Andric     }
239*0946e70aSDimitry Andric     /// Set disjoint union
240*0946e70aSDimitry Andric     EdgeSet &operator^=(const EdgeSet &RHS) {
241*0946e70aSDimitry Andric       assert(&this->G == &RHS.G);
242*0946e70aSDimitry Andric       V ^= RHS.V;
243*0946e70aSDimitry Andric       return *this;
244*0946e70aSDimitry Andric     }
245*0946e70aSDimitry Andric 
246*0946e70aSDimitry Andric     using index_iterator = typename BitVector::const_set_bits_iterator;
247*0946e70aSDimitry Andric     index_iterator index_begin() const { return V.set_bits_begin(); }
248*0946e70aSDimitry Andric     index_iterator index_end() const { return V.set_bits_end(); }
249*0946e70aSDimitry Andric     void set(size_type Idx) { V.set(Idx); }
250*0946e70aSDimitry Andric     void reset(size_type Idx) { V.reset(Idx); }
251*0946e70aSDimitry Andric 
252*0946e70aSDimitry Andric     class iterator {
253*0946e70aSDimitry Andric       const EdgeSet &Set;
254*0946e70aSDimitry Andric       size_type Current;
255*0946e70aSDimitry Andric 
256*0946e70aSDimitry Andric       void advance() {
257*0946e70aSDimitry Andric         assert(Current != -1);
258*0946e70aSDimitry Andric         Current = Set.V.find_next(Current);
259*0946e70aSDimitry Andric       }
260*0946e70aSDimitry Andric 
261*0946e70aSDimitry Andric     public:
262*0946e70aSDimitry Andric       iterator(const EdgeSet &Set, size_type Begin)
263*0946e70aSDimitry Andric           : Set{Set}, Current{Begin} {}
264*0946e70aSDimitry Andric       iterator operator++(int) {
265*0946e70aSDimitry Andric         iterator Tmp = *this;
266*0946e70aSDimitry Andric         advance();
267*0946e70aSDimitry Andric         return Tmp;
268*0946e70aSDimitry Andric       }
269*0946e70aSDimitry Andric       iterator &operator++() {
270*0946e70aSDimitry Andric         advance();
271*0946e70aSDimitry Andric         return *this;
272*0946e70aSDimitry Andric       }
273*0946e70aSDimitry Andric       Edge *operator*() const {
274*0946e70aSDimitry Andric         assert(Current != -1);
275*0946e70aSDimitry Andric         return Set.G.edges_begin() + Current;
276*0946e70aSDimitry Andric       }
277*0946e70aSDimitry Andric       bool operator==(const iterator &other) const {
278*0946e70aSDimitry Andric         assert(&this->Set == &other.Set);
279*0946e70aSDimitry Andric         return this->Current == other.Current;
280*0946e70aSDimitry Andric       }
281*0946e70aSDimitry Andric       bool operator!=(const iterator &other) const { return !(*this == other); }
282*0946e70aSDimitry Andric     };
283*0946e70aSDimitry Andric 
284*0946e70aSDimitry Andric     iterator begin() const { return iterator{*this, V.find_first()}; }
285*0946e70aSDimitry Andric     iterator end() const { return iterator{*this, -1}; }
286*0946e70aSDimitry Andric   };
287*0946e70aSDimitry Andric 
288*0946e70aSDimitry Andric private:
289*0946e70aSDimitry Andric   std::unique_ptr<Node[]> Nodes;
290*0946e70aSDimitry Andric   std::unique_ptr<Edge[]> Edges;
291*0946e70aSDimitry Andric   size_type NodesSize;
292*0946e70aSDimitry Andric   size_type EdgesSize;
293*0946e70aSDimitry Andric };
294*0946e70aSDimitry Andric 
295*0946e70aSDimitry Andric template <typename GraphT> class ImmutableGraphBuilder {
296*0946e70aSDimitry Andric   using node_value_type = typename GraphT::node_value_type;
297*0946e70aSDimitry Andric   using edge_value_type = typename GraphT::edge_value_type;
298*0946e70aSDimitry Andric   static_assert(
299*0946e70aSDimitry Andric       std::is_base_of<ImmutableGraph<node_value_type, edge_value_type>,
300*0946e70aSDimitry Andric                       GraphT>::value,
301*0946e70aSDimitry Andric       "Template argument to ImmutableGraphBuilder must derive from "
302*0946e70aSDimitry Andric       "ImmutableGraph<>");
303*0946e70aSDimitry Andric   using size_type = typename GraphT::size_type;
304*0946e70aSDimitry Andric   using NodeSet = typename GraphT::NodeSet;
305*0946e70aSDimitry Andric   using Node = typename GraphT::Node;
306*0946e70aSDimitry Andric   using EdgeSet = typename GraphT::EdgeSet;
307*0946e70aSDimitry Andric   using Edge = typename GraphT::Edge;
308*0946e70aSDimitry Andric   using BuilderEdge = std::pair<edge_value_type, size_type>;
309*0946e70aSDimitry Andric   using EdgeList = std::vector<BuilderEdge>;
310*0946e70aSDimitry Andric   using BuilderVertex = std::pair<node_value_type, EdgeList>;
311*0946e70aSDimitry Andric   using VertexVec = std::vector<BuilderVertex>;
312*0946e70aSDimitry Andric 
313*0946e70aSDimitry Andric public:
314*0946e70aSDimitry Andric   using BuilderNodeRef = size_type;
315*0946e70aSDimitry Andric 
316*0946e70aSDimitry Andric   BuilderNodeRef addVertex(const node_value_type &V) {
317*0946e70aSDimitry Andric     auto I = AdjList.emplace(AdjList.end(), V, EdgeList{});
318*0946e70aSDimitry Andric     return std::distance(AdjList.begin(), I);
319*0946e70aSDimitry Andric   }
320*0946e70aSDimitry Andric 
321*0946e70aSDimitry Andric   void addEdge(const edge_value_type &E, BuilderNodeRef From,
322*0946e70aSDimitry Andric                BuilderNodeRef To) {
323*0946e70aSDimitry Andric     AdjList[From].second.emplace_back(E, To);
324*0946e70aSDimitry Andric   }
325*0946e70aSDimitry Andric 
326*0946e70aSDimitry Andric   bool empty() const { return AdjList.empty(); }
327*0946e70aSDimitry Andric 
328*0946e70aSDimitry Andric   template <typename... ArgT> std::unique_ptr<GraphT> get(ArgT &&... Args) {
329*0946e70aSDimitry Andric     size_type VertexSize = AdjList.size(), EdgeSize = 0;
330*0946e70aSDimitry Andric     for (const auto &V : AdjList) {
331*0946e70aSDimitry Andric       EdgeSize += V.second.size();
332*0946e70aSDimitry Andric     }
333*0946e70aSDimitry Andric     auto VertexArray =
334*0946e70aSDimitry Andric         std::make_unique<Node[]>(VertexSize + 1 /* terminator node */);
335*0946e70aSDimitry Andric     auto EdgeArray = std::make_unique<Edge[]>(EdgeSize);
336*0946e70aSDimitry Andric     size_type VI = 0, EI = 0;
337*0946e70aSDimitry Andric     for (; VI < VertexSize; ++VI) {
338*0946e70aSDimitry Andric       VertexArray[VI].Value = std::move(AdjList[VI].first);
339*0946e70aSDimitry Andric       VertexArray[VI].Edges = &EdgeArray[EI];
340*0946e70aSDimitry Andric       auto NumEdges = static_cast<size_type>(AdjList[VI].second.size());
341*0946e70aSDimitry Andric       for (size_type VEI = 0; VEI < NumEdges; ++VEI, ++EI) {
342*0946e70aSDimitry Andric         auto &E = AdjList[VI].second[VEI];
343*0946e70aSDimitry Andric         EdgeArray[EI].Value = std::move(E.first);
344*0946e70aSDimitry Andric         EdgeArray[EI].Dest = &VertexArray[E.second];
345*0946e70aSDimitry Andric       }
346*0946e70aSDimitry Andric     }
347*0946e70aSDimitry Andric     assert(VI == VertexSize && EI == EdgeSize && "ImmutableGraph malformed");
348*0946e70aSDimitry Andric     VertexArray[VI].Edges = &EdgeArray[EdgeSize]; // terminator node
349*0946e70aSDimitry Andric     return std::make_unique<GraphT>(std::move(VertexArray),
350*0946e70aSDimitry Andric                                     std::move(EdgeArray), VertexSize, EdgeSize,
351*0946e70aSDimitry Andric                                     std::forward<ArgT>(Args)...);
352*0946e70aSDimitry Andric   }
353*0946e70aSDimitry Andric 
354*0946e70aSDimitry Andric   template <typename... ArgT>
355*0946e70aSDimitry Andric   static std::unique_ptr<GraphT> trim(const GraphT &G, const NodeSet &TrimNodes,
356*0946e70aSDimitry Andric                                       const EdgeSet &TrimEdges,
357*0946e70aSDimitry Andric                                       ArgT &&... Args) {
358*0946e70aSDimitry Andric     size_type NewVertexSize = G.nodes_size() - TrimNodes.count();
359*0946e70aSDimitry Andric     size_type NewEdgeSize = G.edges_size() - TrimEdges.count();
360*0946e70aSDimitry Andric     auto NewVertexArray =
361*0946e70aSDimitry Andric         std::make_unique<Node[]>(NewVertexSize + 1 /* terminator node */);
362*0946e70aSDimitry Andric     auto NewEdgeArray = std::make_unique<Edge[]>(NewEdgeSize);
363*0946e70aSDimitry Andric 
364*0946e70aSDimitry Andric     // Walk the nodes and determine the new index for each node.
365*0946e70aSDimitry Andric     size_type NewNodeIndex = 0;
366*0946e70aSDimitry Andric     std::vector<size_type> RemappedNodeIndex(G.nodes_size());
367*0946e70aSDimitry Andric     for (const Node &N : G.nodes()) {
368*0946e70aSDimitry Andric       if (TrimNodes.contains(N))
369*0946e70aSDimitry Andric         continue;
370*0946e70aSDimitry Andric       RemappedNodeIndex[G.getNodeIndex(N)] = NewNodeIndex++;
371*0946e70aSDimitry Andric     }
372*0946e70aSDimitry Andric     assert(NewNodeIndex == NewVertexSize &&
373*0946e70aSDimitry Andric            "Should have assigned NewVertexSize indices");
374*0946e70aSDimitry Andric 
375*0946e70aSDimitry Andric     size_type VertexI = 0, EdgeI = 0;
376*0946e70aSDimitry Andric     for (const Node &N : G.nodes()) {
377*0946e70aSDimitry Andric       if (TrimNodes.contains(N))
378*0946e70aSDimitry Andric         continue;
379*0946e70aSDimitry Andric       NewVertexArray[VertexI].Value = N.getValue();
380*0946e70aSDimitry Andric       NewVertexArray[VertexI].Edges = &NewEdgeArray[EdgeI];
381*0946e70aSDimitry Andric       for (const Edge &E : N.edges()) {
382*0946e70aSDimitry Andric         if (TrimEdges.contains(E))
383*0946e70aSDimitry Andric           continue;
384*0946e70aSDimitry Andric         NewEdgeArray[EdgeI].Value = E.getValue();
385*0946e70aSDimitry Andric         size_type DestIdx = G.getNodeIndex(*E.getDest());
386*0946e70aSDimitry Andric         size_type NewIdx = RemappedNodeIndex[DestIdx];
387*0946e70aSDimitry Andric         assert(NewIdx < NewVertexSize);
388*0946e70aSDimitry Andric         NewEdgeArray[EdgeI].Dest = &NewVertexArray[NewIdx];
389*0946e70aSDimitry Andric         ++EdgeI;
390*0946e70aSDimitry Andric       }
391*0946e70aSDimitry Andric       ++VertexI;
392*0946e70aSDimitry Andric     }
393*0946e70aSDimitry Andric     assert(VertexI == NewVertexSize && EdgeI == NewEdgeSize &&
394*0946e70aSDimitry Andric            "Gadget graph malformed");
395*0946e70aSDimitry Andric     NewVertexArray[VertexI].Edges = &NewEdgeArray[NewEdgeSize]; // terminator
396*0946e70aSDimitry Andric     return std::make_unique<GraphT>(std::move(NewVertexArray),
397*0946e70aSDimitry Andric                                     std::move(NewEdgeArray), NewVertexSize,
398*0946e70aSDimitry Andric                                     NewEdgeSize, std::forward<ArgT>(Args)...);
399*0946e70aSDimitry Andric   }
400*0946e70aSDimitry Andric 
401*0946e70aSDimitry Andric private:
402*0946e70aSDimitry Andric   VertexVec AdjList;
403*0946e70aSDimitry Andric };
404*0946e70aSDimitry Andric 
405*0946e70aSDimitry Andric template <typename NodeValueT, typename EdgeValueT>
406*0946e70aSDimitry Andric struct GraphTraits<ImmutableGraph<NodeValueT, EdgeValueT> *> {
407*0946e70aSDimitry Andric   using GraphT = ImmutableGraph<NodeValueT, EdgeValueT>;
408*0946e70aSDimitry Andric   using NodeRef = typename GraphT::Node const *;
409*0946e70aSDimitry Andric   using EdgeRef = typename GraphT::Edge const &;
410*0946e70aSDimitry Andric 
411*0946e70aSDimitry Andric   static NodeRef edge_dest(EdgeRef E) { return E.getDest(); }
412*0946e70aSDimitry Andric   using ChildIteratorType =
413*0946e70aSDimitry Andric       mapped_iterator<typename GraphT::Edge const *, decltype(&edge_dest)>;
414*0946e70aSDimitry Andric 
415*0946e70aSDimitry Andric   static NodeRef getEntryNode(GraphT *G) { return G->nodes_begin(); }
416*0946e70aSDimitry Andric   static ChildIteratorType child_begin(NodeRef N) {
417*0946e70aSDimitry Andric     return {N->edges_begin(), &edge_dest};
418*0946e70aSDimitry Andric   }
419*0946e70aSDimitry Andric   static ChildIteratorType child_end(NodeRef N) {
420*0946e70aSDimitry Andric     return {N->edges_end(), &edge_dest};
421*0946e70aSDimitry Andric   }
422*0946e70aSDimitry Andric 
423*0946e70aSDimitry Andric   static NodeRef getNode(typename GraphT::Node const &N) { return NodeRef{&N}; }
424*0946e70aSDimitry Andric   using nodes_iterator =
425*0946e70aSDimitry Andric       mapped_iterator<typename GraphT::Node const *, decltype(&getNode)>;
426*0946e70aSDimitry Andric   static nodes_iterator nodes_begin(GraphT *G) {
427*0946e70aSDimitry Andric     return {G->nodes_begin(), &getNode};
428*0946e70aSDimitry Andric   }
429*0946e70aSDimitry Andric   static nodes_iterator nodes_end(GraphT *G) {
430*0946e70aSDimitry Andric     return {G->nodes_end(), &getNode};
431*0946e70aSDimitry Andric   }
432*0946e70aSDimitry Andric 
433*0946e70aSDimitry Andric   using ChildEdgeIteratorType = typename GraphT::Edge const *;
434*0946e70aSDimitry Andric 
435*0946e70aSDimitry Andric   static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
436*0946e70aSDimitry Andric     return N->edges_begin();
437*0946e70aSDimitry Andric   }
438*0946e70aSDimitry Andric   static ChildEdgeIteratorType child_edge_end(NodeRef N) {
439*0946e70aSDimitry Andric     return N->edges_end();
440*0946e70aSDimitry Andric   }
441*0946e70aSDimitry Andric   static typename GraphT::size_type size(GraphT *G) { return G->nodes_size(); }
442*0946e70aSDimitry Andric };
443*0946e70aSDimitry Andric 
444*0946e70aSDimitry Andric } // end namespace llvm
445*0946e70aSDimitry Andric 
446*0946e70aSDimitry Andric #endif // LLVM_LIB_TARGET_X86_IMMUTABLEGRAPH_H
447