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