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