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