10946e70aSDimitry Andric //==========-- ImmutableGraph.h - A fast DAG implementation ---------=========// 20946e70aSDimitry Andric // 30946e70aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40946e70aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50946e70aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60946e70aSDimitry Andric // 70946e70aSDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric /// \file 90946e70aSDimitry Andric /// Description: ImmutableGraph is a fast DAG implementation that cannot be 100946e70aSDimitry Andric /// modified, except by creating a new ImmutableGraph. ImmutableGraph is 110946e70aSDimitry Andric /// implemented as two arrays: one containing nodes, and one containing edges. 120946e70aSDimitry Andric /// The advantages to this implementation are two-fold: 130946e70aSDimitry Andric /// 1. Iteration and traversal operations benefit from cache locality. 140946e70aSDimitry Andric /// 2. Operations on sets of nodes/edges are efficient, and representations of 150946e70aSDimitry Andric /// those sets in memory are compact. For instance, a set of edges is 160946e70aSDimitry Andric /// implemented as a bit vector, wherein each bit corresponds to one edge in 170946e70aSDimitry Andric /// the edge array. This implies a lower bound of 64x spatial improvement 180946e70aSDimitry Andric /// over, e.g., an llvm::DenseSet or llvm::SmallSet. It also means that 190946e70aSDimitry Andric /// insert/erase/contains operations complete in negligible constant time: 200946e70aSDimitry Andric /// insert and erase require one load and one store, and contains requires 210946e70aSDimitry Andric /// just one load. 220946e70aSDimitry Andric /// 230946e70aSDimitry Andric //===----------------------------------------------------------------------===// 240946e70aSDimitry Andric 250946e70aSDimitry Andric #ifndef LLVM_LIB_TARGET_X86_IMMUTABLEGRAPH_H 260946e70aSDimitry Andric #define LLVM_LIB_TARGET_X86_IMMUTABLEGRAPH_H 270946e70aSDimitry Andric 280946e70aSDimitry Andric #include "llvm/ADT/BitVector.h" 290946e70aSDimitry Andric #include "llvm/ADT/GraphTraits.h" 300946e70aSDimitry Andric #include "llvm/ADT/STLExtras.h" 310946e70aSDimitry Andric #include <algorithm> 320946e70aSDimitry Andric #include <iterator> 330946e70aSDimitry Andric #include <utility> 340946e70aSDimitry Andric #include <vector> 350946e70aSDimitry Andric 360946e70aSDimitry Andric namespace llvm { 370946e70aSDimitry Andric 380946e70aSDimitry Andric template <typename NodeValueT, typename EdgeValueT> class ImmutableGraph { 390946e70aSDimitry Andric using Traits = GraphTraits<ImmutableGraph<NodeValueT, EdgeValueT> *>; 400946e70aSDimitry Andric template <typename> friend class ImmutableGraphBuilder; 410946e70aSDimitry Andric 420946e70aSDimitry Andric public: 430946e70aSDimitry Andric using node_value_type = NodeValueT; 440946e70aSDimitry Andric using edge_value_type = EdgeValueT; 450946e70aSDimitry Andric using size_type = int; 460946e70aSDimitry Andric class Node; 470946e70aSDimitry Andric class Edge { 480946e70aSDimitry Andric friend class ImmutableGraph; 490946e70aSDimitry Andric template <typename> friend class ImmutableGraphBuilder; 500946e70aSDimitry Andric 510946e70aSDimitry Andric const Node *Dest; 520946e70aSDimitry Andric edge_value_type Value; 530946e70aSDimitry Andric 540946e70aSDimitry Andric public: getDest()550946e70aSDimitry Andric const Node *getDest() const { return Dest; }; getValue()560946e70aSDimitry Andric const edge_value_type &getValue() const { return Value; } 570946e70aSDimitry Andric }; 580946e70aSDimitry Andric class Node { 590946e70aSDimitry Andric friend class ImmutableGraph; 600946e70aSDimitry Andric template <typename> friend class ImmutableGraphBuilder; 610946e70aSDimitry Andric 620946e70aSDimitry Andric const Edge *Edges; 630946e70aSDimitry Andric node_value_type Value; 640946e70aSDimitry Andric 650946e70aSDimitry Andric public: getValue()660946e70aSDimitry Andric const node_value_type &getValue() const { return Value; } 670946e70aSDimitry Andric edges_begin()680946e70aSDimitry Andric const Edge *edges_begin() const { return Edges; } 690946e70aSDimitry Andric // Nodes are allocated sequentially. Edges for a node are stored together. 700946e70aSDimitry Andric // The end of this Node's edges is the beginning of the next node's edges. 710946e70aSDimitry Andric // An extra node was allocated to hold the end pointer for the last real 720946e70aSDimitry Andric // node. edges_end()730946e70aSDimitry Andric const Edge *edges_end() const { return (this + 1)->Edges; } edges()740946e70aSDimitry Andric ArrayRef<Edge> edges() const { 75*bdd1243dSDimitry Andric return ArrayRef(edges_begin(), edges_end()); 760946e70aSDimitry Andric } 770946e70aSDimitry Andric }; 780946e70aSDimitry Andric 790946e70aSDimitry Andric protected: ImmutableGraph(std::unique_ptr<Node[]> Nodes,std::unique_ptr<Edge[]> Edges,size_type NodesSize,size_type EdgesSize)800946e70aSDimitry Andric ImmutableGraph(std::unique_ptr<Node[]> Nodes, std::unique_ptr<Edge[]> Edges, 810946e70aSDimitry Andric size_type NodesSize, size_type EdgesSize) 820946e70aSDimitry Andric : Nodes(std::move(Nodes)), Edges(std::move(Edges)), NodesSize(NodesSize), 830946e70aSDimitry Andric EdgesSize(EdgesSize) {} 840946e70aSDimitry Andric ImmutableGraph(const ImmutableGraph &) = delete; 850946e70aSDimitry Andric ImmutableGraph(ImmutableGraph &&) = delete; 860946e70aSDimitry Andric ImmutableGraph &operator=(const ImmutableGraph &) = delete; 870946e70aSDimitry Andric ImmutableGraph &operator=(ImmutableGraph &&) = delete; 880946e70aSDimitry Andric 890946e70aSDimitry Andric public: nodes()90*bdd1243dSDimitry Andric ArrayRef<Node> nodes() const { return ArrayRef(Nodes.get(), NodesSize); } nodes_begin()910946e70aSDimitry Andric const Node *nodes_begin() const { return nodes().begin(); } nodes_end()920946e70aSDimitry Andric const Node *nodes_end() const { return nodes().end(); } 930946e70aSDimitry Andric edges()94*bdd1243dSDimitry Andric ArrayRef<Edge> edges() const { return ArrayRef(Edges.get(), EdgesSize); } edges_begin()950946e70aSDimitry Andric const Edge *edges_begin() const { return edges().begin(); } edges_end()960946e70aSDimitry Andric const Edge *edges_end() const { return edges().end(); } 970946e70aSDimitry Andric nodes_size()980946e70aSDimitry Andric size_type nodes_size() const { return NodesSize; } edges_size()990946e70aSDimitry Andric size_type edges_size() const { return EdgesSize; } 1000946e70aSDimitry Andric 1010946e70aSDimitry Andric // Node N must belong to this ImmutableGraph. getNodeIndex(const Node & N)1020946e70aSDimitry Andric size_type getNodeIndex(const Node &N) const { 1030946e70aSDimitry Andric return std::distance(nodes_begin(), &N); 1040946e70aSDimitry Andric } 1050946e70aSDimitry Andric // Edge E must belong to this ImmutableGraph. getEdgeIndex(const Edge & E)1060946e70aSDimitry Andric size_type getEdgeIndex(const Edge &E) const { 1070946e70aSDimitry Andric return std::distance(edges_begin(), &E); 1080946e70aSDimitry Andric } 1090946e70aSDimitry Andric 1100946e70aSDimitry Andric // FIXME: Could NodeSet and EdgeSet be templated to share code? 1110946e70aSDimitry Andric class NodeSet { 1120946e70aSDimitry Andric const ImmutableGraph &G; 1130946e70aSDimitry Andric BitVector V; 1140946e70aSDimitry Andric 1150946e70aSDimitry Andric public: 1160946e70aSDimitry Andric NodeSet(const ImmutableGraph &G, bool ContainsAll = false) 1170946e70aSDimitry Andric : G{G}, V{static_cast<unsigned>(G.nodes_size()), ContainsAll} {} insert(const Node & N)1180946e70aSDimitry Andric bool insert(const Node &N) { 1190946e70aSDimitry Andric size_type Idx = G.getNodeIndex(N); 1200946e70aSDimitry Andric bool AlreadyExists = V.test(Idx); 1210946e70aSDimitry Andric V.set(Idx); 1220946e70aSDimitry Andric return !AlreadyExists; 1230946e70aSDimitry Andric } erase(const Node & N)1240946e70aSDimitry Andric void erase(const Node &N) { 1250946e70aSDimitry Andric size_type Idx = G.getNodeIndex(N); 1260946e70aSDimitry Andric V.reset(Idx); 1270946e70aSDimitry Andric } contains(const Node & N)1280946e70aSDimitry Andric bool contains(const Node &N) const { 1290946e70aSDimitry Andric size_type Idx = G.getNodeIndex(N); 1300946e70aSDimitry Andric return V.test(Idx); 1310946e70aSDimitry Andric } clear()1320946e70aSDimitry Andric void clear() { V.reset(); } empty()1330946e70aSDimitry Andric size_type empty() const { return V.none(); } 1340946e70aSDimitry Andric /// Return the number of elements in the set count()1350946e70aSDimitry Andric size_type count() const { return V.count(); } 1360946e70aSDimitry Andric /// Return the size of the set's domain size()1370946e70aSDimitry Andric size_type size() const { return V.size(); } 1380946e70aSDimitry Andric /// Set union 1390946e70aSDimitry Andric NodeSet &operator|=(const NodeSet &RHS) { 1400946e70aSDimitry Andric assert(&this->G == &RHS.G); 1410946e70aSDimitry Andric V |= RHS.V; 1420946e70aSDimitry Andric return *this; 1430946e70aSDimitry Andric } 1440946e70aSDimitry Andric /// Set intersection 1450946e70aSDimitry Andric NodeSet &operator&=(const NodeSet &RHS) { 1460946e70aSDimitry Andric assert(&this->G == &RHS.G); 1470946e70aSDimitry Andric V &= RHS.V; 1480946e70aSDimitry Andric return *this; 1490946e70aSDimitry Andric } 1500946e70aSDimitry Andric /// Set disjoint union 1510946e70aSDimitry Andric NodeSet &operator^=(const NodeSet &RHS) { 1520946e70aSDimitry Andric assert(&this->G == &RHS.G); 1530946e70aSDimitry Andric V ^= RHS.V; 1540946e70aSDimitry Andric return *this; 1550946e70aSDimitry Andric } 1560946e70aSDimitry Andric 1570946e70aSDimitry Andric using index_iterator = typename BitVector::const_set_bits_iterator; index_begin()1580946e70aSDimitry Andric index_iterator index_begin() const { return V.set_bits_begin(); } index_end()1590946e70aSDimitry Andric index_iterator index_end() const { return V.set_bits_end(); } set(size_type Idx)1600946e70aSDimitry Andric void set(size_type Idx) { V.set(Idx); } reset(size_type Idx)1610946e70aSDimitry Andric void reset(size_type Idx) { V.reset(Idx); } 1620946e70aSDimitry Andric 1630946e70aSDimitry Andric class iterator { 1640946e70aSDimitry Andric const NodeSet &Set; 1650946e70aSDimitry Andric size_type Current; 1660946e70aSDimitry Andric advance()1670946e70aSDimitry Andric void advance() { 1680946e70aSDimitry Andric assert(Current != -1); 1690946e70aSDimitry Andric Current = Set.V.find_next(Current); 1700946e70aSDimitry Andric } 1710946e70aSDimitry Andric 1720946e70aSDimitry Andric public: iterator(const NodeSet & Set,size_type Begin)1730946e70aSDimitry Andric iterator(const NodeSet &Set, size_type Begin) 1740946e70aSDimitry Andric : Set{Set}, Current{Begin} {} 1750946e70aSDimitry Andric iterator operator++(int) { 1760946e70aSDimitry Andric iterator Tmp = *this; 1770946e70aSDimitry Andric advance(); 1780946e70aSDimitry Andric return Tmp; 1790946e70aSDimitry Andric } 1800946e70aSDimitry Andric iterator &operator++() { 1810946e70aSDimitry Andric advance(); 1820946e70aSDimitry Andric return *this; 1830946e70aSDimitry Andric } 1840946e70aSDimitry Andric Node *operator*() const { 1850946e70aSDimitry Andric assert(Current != -1); 1860946e70aSDimitry Andric return Set.G.nodes_begin() + Current; 1870946e70aSDimitry Andric } 1880946e70aSDimitry Andric bool operator==(const iterator &other) const { 1890946e70aSDimitry Andric assert(&this->Set == &other.Set); 1900946e70aSDimitry Andric return this->Current == other.Current; 1910946e70aSDimitry Andric } 1920946e70aSDimitry Andric bool operator!=(const iterator &other) const { return !(*this == other); } 1930946e70aSDimitry Andric }; 1940946e70aSDimitry Andric begin()1950946e70aSDimitry Andric iterator begin() const { return iterator{*this, V.find_first()}; } end()1960946e70aSDimitry Andric iterator end() const { return iterator{*this, -1}; } 1970946e70aSDimitry Andric }; 1980946e70aSDimitry Andric 1990946e70aSDimitry Andric class EdgeSet { 2000946e70aSDimitry Andric const ImmutableGraph &G; 2010946e70aSDimitry Andric BitVector V; 2020946e70aSDimitry Andric 2030946e70aSDimitry Andric public: 2040946e70aSDimitry Andric EdgeSet(const ImmutableGraph &G, bool ContainsAll = false) 2050946e70aSDimitry Andric : G{G}, V{static_cast<unsigned>(G.edges_size()), ContainsAll} {} insert(const Edge & E)2060946e70aSDimitry Andric bool insert(const Edge &E) { 2070946e70aSDimitry Andric size_type Idx = G.getEdgeIndex(E); 2080946e70aSDimitry Andric bool AlreadyExists = V.test(Idx); 2090946e70aSDimitry Andric V.set(Idx); 2100946e70aSDimitry Andric return !AlreadyExists; 2110946e70aSDimitry Andric } erase(const Edge & E)2120946e70aSDimitry Andric void erase(const Edge &E) { 2130946e70aSDimitry Andric size_type Idx = G.getEdgeIndex(E); 2140946e70aSDimitry Andric V.reset(Idx); 2150946e70aSDimitry Andric } contains(const Edge & E)2160946e70aSDimitry Andric bool contains(const Edge &E) const { 2170946e70aSDimitry Andric size_type Idx = G.getEdgeIndex(E); 2180946e70aSDimitry Andric return V.test(Idx); 2190946e70aSDimitry Andric } clear()2200946e70aSDimitry Andric void clear() { V.reset(); } empty()2210946e70aSDimitry Andric bool empty() const { return V.none(); } 2220946e70aSDimitry Andric /// Return the number of elements in the set count()2230946e70aSDimitry Andric size_type count() const { return V.count(); } 2240946e70aSDimitry Andric /// Return the size of the set's domain size()2250946e70aSDimitry Andric size_type size() const { return V.size(); } 2260946e70aSDimitry Andric /// Set union 2270946e70aSDimitry Andric EdgeSet &operator|=(const EdgeSet &RHS) { 2280946e70aSDimitry Andric assert(&this->G == &RHS.G); 2290946e70aSDimitry Andric V |= RHS.V; 2300946e70aSDimitry Andric return *this; 2310946e70aSDimitry Andric } 2320946e70aSDimitry Andric /// Set intersection 2330946e70aSDimitry Andric EdgeSet &operator&=(const EdgeSet &RHS) { 2340946e70aSDimitry Andric assert(&this->G == &RHS.G); 2350946e70aSDimitry Andric V &= RHS.V; 2360946e70aSDimitry Andric return *this; 2370946e70aSDimitry Andric } 2380946e70aSDimitry Andric /// Set disjoint union 2390946e70aSDimitry Andric EdgeSet &operator^=(const EdgeSet &RHS) { 2400946e70aSDimitry Andric assert(&this->G == &RHS.G); 2410946e70aSDimitry Andric V ^= RHS.V; 2420946e70aSDimitry Andric return *this; 2430946e70aSDimitry Andric } 2440946e70aSDimitry Andric 2450946e70aSDimitry Andric using index_iterator = typename BitVector::const_set_bits_iterator; index_begin()2460946e70aSDimitry Andric index_iterator index_begin() const { return V.set_bits_begin(); } index_end()2470946e70aSDimitry Andric index_iterator index_end() const { return V.set_bits_end(); } set(size_type Idx)2480946e70aSDimitry Andric void set(size_type Idx) { V.set(Idx); } reset(size_type Idx)2490946e70aSDimitry Andric void reset(size_type Idx) { V.reset(Idx); } 2500946e70aSDimitry Andric 2510946e70aSDimitry Andric class iterator { 2520946e70aSDimitry Andric const EdgeSet &Set; 2530946e70aSDimitry Andric size_type Current; 2540946e70aSDimitry Andric advance()2550946e70aSDimitry Andric void advance() { 2560946e70aSDimitry Andric assert(Current != -1); 2570946e70aSDimitry Andric Current = Set.V.find_next(Current); 2580946e70aSDimitry Andric } 2590946e70aSDimitry Andric 2600946e70aSDimitry Andric public: iterator(const EdgeSet & Set,size_type Begin)2610946e70aSDimitry Andric iterator(const EdgeSet &Set, size_type Begin) 2620946e70aSDimitry Andric : Set{Set}, Current{Begin} {} 2630946e70aSDimitry Andric iterator operator++(int) { 2640946e70aSDimitry Andric iterator Tmp = *this; 2650946e70aSDimitry Andric advance(); 2660946e70aSDimitry Andric return Tmp; 2670946e70aSDimitry Andric } 2680946e70aSDimitry Andric iterator &operator++() { 2690946e70aSDimitry Andric advance(); 2700946e70aSDimitry Andric return *this; 2710946e70aSDimitry Andric } 2720946e70aSDimitry Andric Edge *operator*() const { 2730946e70aSDimitry Andric assert(Current != -1); 2740946e70aSDimitry Andric return Set.G.edges_begin() + Current; 2750946e70aSDimitry Andric } 2760946e70aSDimitry Andric bool operator==(const iterator &other) const { 2770946e70aSDimitry Andric assert(&this->Set == &other.Set); 2780946e70aSDimitry Andric return this->Current == other.Current; 2790946e70aSDimitry Andric } 2800946e70aSDimitry Andric bool operator!=(const iterator &other) const { return !(*this == other); } 2810946e70aSDimitry Andric }; 2820946e70aSDimitry Andric begin()2830946e70aSDimitry Andric iterator begin() const { return iterator{*this, V.find_first()}; } end()2840946e70aSDimitry Andric iterator end() const { return iterator{*this, -1}; } 2850946e70aSDimitry Andric }; 2860946e70aSDimitry Andric 2870946e70aSDimitry Andric private: 2880946e70aSDimitry Andric std::unique_ptr<Node[]> Nodes; 2890946e70aSDimitry Andric std::unique_ptr<Edge[]> Edges; 2900946e70aSDimitry Andric size_type NodesSize; 2910946e70aSDimitry Andric size_type EdgesSize; 2920946e70aSDimitry Andric }; 2930946e70aSDimitry Andric 2940946e70aSDimitry Andric template <typename GraphT> class ImmutableGraphBuilder { 2950946e70aSDimitry Andric using node_value_type = typename GraphT::node_value_type; 2960946e70aSDimitry Andric using edge_value_type = typename GraphT::edge_value_type; 2970946e70aSDimitry Andric static_assert( 2980946e70aSDimitry Andric std::is_base_of<ImmutableGraph<node_value_type, edge_value_type>, 2990946e70aSDimitry Andric GraphT>::value, 3000946e70aSDimitry Andric "Template argument to ImmutableGraphBuilder must derive from " 3010946e70aSDimitry Andric "ImmutableGraph<>"); 3020946e70aSDimitry Andric using size_type = typename GraphT::size_type; 3030946e70aSDimitry Andric using NodeSet = typename GraphT::NodeSet; 3040946e70aSDimitry Andric using Node = typename GraphT::Node; 3050946e70aSDimitry Andric using EdgeSet = typename GraphT::EdgeSet; 3060946e70aSDimitry Andric using Edge = typename GraphT::Edge; 3070946e70aSDimitry Andric using BuilderEdge = std::pair<edge_value_type, size_type>; 3080946e70aSDimitry Andric using EdgeList = std::vector<BuilderEdge>; 3090946e70aSDimitry Andric using BuilderVertex = std::pair<node_value_type, EdgeList>; 3100946e70aSDimitry Andric using VertexVec = std::vector<BuilderVertex>; 3110946e70aSDimitry Andric 3120946e70aSDimitry Andric public: 3130946e70aSDimitry Andric using BuilderNodeRef = size_type; 3140946e70aSDimitry Andric addVertex(const node_value_type & V)3150946e70aSDimitry Andric BuilderNodeRef addVertex(const node_value_type &V) { 3160946e70aSDimitry Andric auto I = AdjList.emplace(AdjList.end(), V, EdgeList{}); 3170946e70aSDimitry Andric return std::distance(AdjList.begin(), I); 3180946e70aSDimitry Andric } 3190946e70aSDimitry Andric addEdge(const edge_value_type & E,BuilderNodeRef From,BuilderNodeRef To)3200946e70aSDimitry Andric void addEdge(const edge_value_type &E, BuilderNodeRef From, 3210946e70aSDimitry Andric BuilderNodeRef To) { 3220946e70aSDimitry Andric AdjList[From].second.emplace_back(E, To); 3230946e70aSDimitry Andric } 3240946e70aSDimitry Andric empty()3250946e70aSDimitry Andric bool empty() const { return AdjList.empty(); } 3260946e70aSDimitry Andric get(ArgT &&...Args)3270946e70aSDimitry Andric template <typename... ArgT> std::unique_ptr<GraphT> get(ArgT &&... Args) { 3280946e70aSDimitry Andric size_type VertexSize = AdjList.size(), EdgeSize = 0; 3290946e70aSDimitry Andric for (const auto &V : AdjList) { 3300946e70aSDimitry Andric EdgeSize += V.second.size(); 3310946e70aSDimitry Andric } 3320946e70aSDimitry Andric auto VertexArray = 3330946e70aSDimitry Andric std::make_unique<Node[]>(VertexSize + 1 /* terminator node */); 3340946e70aSDimitry Andric auto EdgeArray = std::make_unique<Edge[]>(EdgeSize); 3350946e70aSDimitry Andric size_type VI = 0, EI = 0; 3360946e70aSDimitry Andric for (; VI < VertexSize; ++VI) { 3370946e70aSDimitry Andric VertexArray[VI].Value = std::move(AdjList[VI].first); 3380946e70aSDimitry Andric VertexArray[VI].Edges = &EdgeArray[EI]; 3390946e70aSDimitry Andric auto NumEdges = static_cast<size_type>(AdjList[VI].second.size()); 3400946e70aSDimitry Andric for (size_type VEI = 0; VEI < NumEdges; ++VEI, ++EI) { 3410946e70aSDimitry Andric auto &E = AdjList[VI].second[VEI]; 3420946e70aSDimitry Andric EdgeArray[EI].Value = std::move(E.first); 3430946e70aSDimitry Andric EdgeArray[EI].Dest = &VertexArray[E.second]; 3440946e70aSDimitry Andric } 3450946e70aSDimitry Andric } 3460946e70aSDimitry Andric assert(VI == VertexSize && EI == EdgeSize && "ImmutableGraph malformed"); 3470946e70aSDimitry Andric VertexArray[VI].Edges = &EdgeArray[EdgeSize]; // terminator node 3480946e70aSDimitry Andric return std::make_unique<GraphT>(std::move(VertexArray), 3490946e70aSDimitry Andric std::move(EdgeArray), VertexSize, EdgeSize, 3500946e70aSDimitry Andric std::forward<ArgT>(Args)...); 3510946e70aSDimitry Andric } 3520946e70aSDimitry Andric 3530946e70aSDimitry Andric template <typename... ArgT> trim(const GraphT & G,const NodeSet & TrimNodes,const EdgeSet & TrimEdges,ArgT &&...Args)3540946e70aSDimitry Andric static std::unique_ptr<GraphT> trim(const GraphT &G, const NodeSet &TrimNodes, 3550946e70aSDimitry Andric const EdgeSet &TrimEdges, 3560946e70aSDimitry Andric ArgT &&... Args) { 3570946e70aSDimitry Andric size_type NewVertexSize = G.nodes_size() - TrimNodes.count(); 3580946e70aSDimitry Andric size_type NewEdgeSize = G.edges_size() - TrimEdges.count(); 3590946e70aSDimitry Andric auto NewVertexArray = 3600946e70aSDimitry Andric std::make_unique<Node[]>(NewVertexSize + 1 /* terminator node */); 3610946e70aSDimitry Andric auto NewEdgeArray = std::make_unique<Edge[]>(NewEdgeSize); 3620946e70aSDimitry Andric 3630946e70aSDimitry Andric // Walk the nodes and determine the new index for each node. 3640946e70aSDimitry Andric size_type NewNodeIndex = 0; 3650946e70aSDimitry Andric std::vector<size_type> RemappedNodeIndex(G.nodes_size()); 3660946e70aSDimitry Andric for (const Node &N : G.nodes()) { 3670946e70aSDimitry Andric if (TrimNodes.contains(N)) 3680946e70aSDimitry Andric continue; 3690946e70aSDimitry Andric RemappedNodeIndex[G.getNodeIndex(N)] = NewNodeIndex++; 3700946e70aSDimitry Andric } 3710946e70aSDimitry Andric assert(NewNodeIndex == NewVertexSize && 3720946e70aSDimitry Andric "Should have assigned NewVertexSize indices"); 3730946e70aSDimitry Andric 3740946e70aSDimitry Andric size_type VertexI = 0, EdgeI = 0; 3750946e70aSDimitry Andric for (const Node &N : G.nodes()) { 3760946e70aSDimitry Andric if (TrimNodes.contains(N)) 3770946e70aSDimitry Andric continue; 3780946e70aSDimitry Andric NewVertexArray[VertexI].Value = N.getValue(); 3790946e70aSDimitry Andric NewVertexArray[VertexI].Edges = &NewEdgeArray[EdgeI]; 3800946e70aSDimitry Andric for (const Edge &E : N.edges()) { 3810946e70aSDimitry Andric if (TrimEdges.contains(E)) 3820946e70aSDimitry Andric continue; 3830946e70aSDimitry Andric NewEdgeArray[EdgeI].Value = E.getValue(); 3840946e70aSDimitry Andric size_type DestIdx = G.getNodeIndex(*E.getDest()); 3850946e70aSDimitry Andric size_type NewIdx = RemappedNodeIndex[DestIdx]; 3860946e70aSDimitry Andric assert(NewIdx < NewVertexSize); 3870946e70aSDimitry Andric NewEdgeArray[EdgeI].Dest = &NewVertexArray[NewIdx]; 3880946e70aSDimitry Andric ++EdgeI; 3890946e70aSDimitry Andric } 3900946e70aSDimitry Andric ++VertexI; 3910946e70aSDimitry Andric } 3920946e70aSDimitry Andric assert(VertexI == NewVertexSize && EdgeI == NewEdgeSize && 3930946e70aSDimitry Andric "Gadget graph malformed"); 3940946e70aSDimitry Andric NewVertexArray[VertexI].Edges = &NewEdgeArray[NewEdgeSize]; // terminator 3950946e70aSDimitry Andric return std::make_unique<GraphT>(std::move(NewVertexArray), 3960946e70aSDimitry Andric std::move(NewEdgeArray), NewVertexSize, 3970946e70aSDimitry Andric NewEdgeSize, std::forward<ArgT>(Args)...); 3980946e70aSDimitry Andric } 3990946e70aSDimitry Andric 4000946e70aSDimitry Andric private: 4010946e70aSDimitry Andric VertexVec AdjList; 4020946e70aSDimitry Andric }; 4030946e70aSDimitry Andric 4040946e70aSDimitry Andric template <typename NodeValueT, typename EdgeValueT> 4050946e70aSDimitry Andric struct GraphTraits<ImmutableGraph<NodeValueT, EdgeValueT> *> { 4060946e70aSDimitry Andric using GraphT = ImmutableGraph<NodeValueT, EdgeValueT>; 4070946e70aSDimitry Andric using NodeRef = typename GraphT::Node const *; 4080946e70aSDimitry Andric using EdgeRef = typename GraphT::Edge const &; 4090946e70aSDimitry Andric 4100946e70aSDimitry Andric static NodeRef edge_dest(EdgeRef E) { return E.getDest(); } 4110946e70aSDimitry Andric using ChildIteratorType = 4120946e70aSDimitry Andric mapped_iterator<typename GraphT::Edge const *, decltype(&edge_dest)>; 4130946e70aSDimitry Andric 4140946e70aSDimitry Andric static NodeRef getEntryNode(GraphT *G) { return G->nodes_begin(); } 4150946e70aSDimitry Andric static ChildIteratorType child_begin(NodeRef N) { 4160946e70aSDimitry Andric return {N->edges_begin(), &edge_dest}; 4170946e70aSDimitry Andric } 4180946e70aSDimitry Andric static ChildIteratorType child_end(NodeRef N) { 4190946e70aSDimitry Andric return {N->edges_end(), &edge_dest}; 4200946e70aSDimitry Andric } 4210946e70aSDimitry Andric 4220946e70aSDimitry Andric static NodeRef getNode(typename GraphT::Node const &N) { return NodeRef{&N}; } 4230946e70aSDimitry Andric using nodes_iterator = 4240946e70aSDimitry Andric mapped_iterator<typename GraphT::Node const *, decltype(&getNode)>; 4250946e70aSDimitry Andric static nodes_iterator nodes_begin(GraphT *G) { 4260946e70aSDimitry Andric return {G->nodes_begin(), &getNode}; 4270946e70aSDimitry Andric } 4280946e70aSDimitry Andric static nodes_iterator nodes_end(GraphT *G) { 4290946e70aSDimitry Andric return {G->nodes_end(), &getNode}; 4300946e70aSDimitry Andric } 4310946e70aSDimitry Andric 4320946e70aSDimitry Andric using ChildEdgeIteratorType = typename GraphT::Edge const *; 4330946e70aSDimitry Andric 4340946e70aSDimitry Andric static ChildEdgeIteratorType child_edge_begin(NodeRef N) { 4350946e70aSDimitry Andric return N->edges_begin(); 4360946e70aSDimitry Andric } 4370946e70aSDimitry Andric static ChildEdgeIteratorType child_edge_end(NodeRef N) { 4380946e70aSDimitry Andric return N->edges_end(); 4390946e70aSDimitry Andric } 4400946e70aSDimitry Andric static typename GraphT::size_type size(GraphT *G) { return G->nodes_size(); } 4410946e70aSDimitry Andric }; 4420946e70aSDimitry Andric 4430946e70aSDimitry Andric } // end namespace llvm 4440946e70aSDimitry Andric 4450946e70aSDimitry Andric #endif // LLVM_LIB_TARGET_X86_IMMUTABLEGRAPH_H 446