1*7c3d14c8STreehugger Robot //===-- sanitizer_bvgraph.h -------------------------------------*- C++ -*-===// 2*7c3d14c8STreehugger Robot // 3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure 4*7c3d14c8STreehugger Robot // 5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source 6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details. 7*7c3d14c8STreehugger Robot // 8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===// 9*7c3d14c8STreehugger Robot // 10*7c3d14c8STreehugger Robot // This file is a part of Sanitizer runtime. 11*7c3d14c8STreehugger Robot // BVGraph -- a directed graph. 12*7c3d14c8STreehugger Robot // 13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===// 14*7c3d14c8STreehugger Robot 15*7c3d14c8STreehugger Robot #ifndef SANITIZER_BVGRAPH_H 16*7c3d14c8STreehugger Robot #define SANITIZER_BVGRAPH_H 17*7c3d14c8STreehugger Robot 18*7c3d14c8STreehugger Robot #include "sanitizer_common.h" 19*7c3d14c8STreehugger Robot #include "sanitizer_bitvector.h" 20*7c3d14c8STreehugger Robot 21*7c3d14c8STreehugger Robot namespace __sanitizer { 22*7c3d14c8STreehugger Robot 23*7c3d14c8STreehugger Robot // Directed graph of fixed size implemented as an array of bit vectors. 24*7c3d14c8STreehugger Robot // Not thread-safe, all accesses should be protected by an external lock. 25*7c3d14c8STreehugger Robot template<class BV> 26*7c3d14c8STreehugger Robot class BVGraph { 27*7c3d14c8STreehugger Robot public: 28*7c3d14c8STreehugger Robot enum SizeEnum { kSize = BV::kSize }; size()29*7c3d14c8STreehugger Robot uptr size() const { return kSize; } 30*7c3d14c8STreehugger Robot // No CTOR. clear()31*7c3d14c8STreehugger Robot void clear() { 32*7c3d14c8STreehugger Robot for (uptr i = 0; i < size(); i++) 33*7c3d14c8STreehugger Robot v[i].clear(); 34*7c3d14c8STreehugger Robot } 35*7c3d14c8STreehugger Robot empty()36*7c3d14c8STreehugger Robot bool empty() const { 37*7c3d14c8STreehugger Robot for (uptr i = 0; i < size(); i++) 38*7c3d14c8STreehugger Robot if (!v[i].empty()) 39*7c3d14c8STreehugger Robot return false; 40*7c3d14c8STreehugger Robot return true; 41*7c3d14c8STreehugger Robot } 42*7c3d14c8STreehugger Robot 43*7c3d14c8STreehugger Robot // Returns true if a new edge was added. addEdge(uptr from,uptr to)44*7c3d14c8STreehugger Robot bool addEdge(uptr from, uptr to) { 45*7c3d14c8STreehugger Robot check(from, to); 46*7c3d14c8STreehugger Robot return v[from].setBit(to); 47*7c3d14c8STreehugger Robot } 48*7c3d14c8STreehugger Robot 49*7c3d14c8STreehugger Robot // Returns true if at least one new edge was added. addEdges(const BV & from,uptr to,uptr added_edges[],uptr max_added_edges)50*7c3d14c8STreehugger Robot uptr addEdges(const BV &from, uptr to, uptr added_edges[], 51*7c3d14c8STreehugger Robot uptr max_added_edges) { 52*7c3d14c8STreehugger Robot uptr res = 0; 53*7c3d14c8STreehugger Robot t1.copyFrom(from); 54*7c3d14c8STreehugger Robot while (!t1.empty()) { 55*7c3d14c8STreehugger Robot uptr node = t1.getAndClearFirstOne(); 56*7c3d14c8STreehugger Robot if (v[node].setBit(to)) 57*7c3d14c8STreehugger Robot if (res < max_added_edges) 58*7c3d14c8STreehugger Robot added_edges[res++] = node; 59*7c3d14c8STreehugger Robot } 60*7c3d14c8STreehugger Robot return res; 61*7c3d14c8STreehugger Robot } 62*7c3d14c8STreehugger Robot 63*7c3d14c8STreehugger Robot // *EXPERIMENTAL* 64*7c3d14c8STreehugger Robot // Returns true if an edge from=>to exist. 65*7c3d14c8STreehugger Robot // This function does not use any global state except for 'this' itself, 66*7c3d14c8STreehugger Robot // and thus can be called from different threads w/o locking. 67*7c3d14c8STreehugger Robot // This would be racy. 68*7c3d14c8STreehugger Robot // FIXME: investigate how much we can prove about this race being "benign". hasEdge(uptr from,uptr to)69*7c3d14c8STreehugger Robot bool hasEdge(uptr from, uptr to) { return v[from].getBit(to); } 70*7c3d14c8STreehugger Robot 71*7c3d14c8STreehugger Robot // Returns true if the edge from=>to was removed. removeEdge(uptr from,uptr to)72*7c3d14c8STreehugger Robot bool removeEdge(uptr from, uptr to) { 73*7c3d14c8STreehugger Robot return v[from].clearBit(to); 74*7c3d14c8STreehugger Robot } 75*7c3d14c8STreehugger Robot 76*7c3d14c8STreehugger Robot // Returns true if at least one edge *=>to was removed. removeEdgesTo(const BV & to)77*7c3d14c8STreehugger Robot bool removeEdgesTo(const BV &to) { 78*7c3d14c8STreehugger Robot bool res = 0; 79*7c3d14c8STreehugger Robot for (uptr from = 0; from < size(); from++) { 80*7c3d14c8STreehugger Robot if (v[from].setDifference(to)) 81*7c3d14c8STreehugger Robot res = true; 82*7c3d14c8STreehugger Robot } 83*7c3d14c8STreehugger Robot return res; 84*7c3d14c8STreehugger Robot } 85*7c3d14c8STreehugger Robot 86*7c3d14c8STreehugger Robot // Returns true if at least one edge from=>* was removed. removeEdgesFrom(const BV & from)87*7c3d14c8STreehugger Robot bool removeEdgesFrom(const BV &from) { 88*7c3d14c8STreehugger Robot bool res = false; 89*7c3d14c8STreehugger Robot t1.copyFrom(from); 90*7c3d14c8STreehugger Robot while (!t1.empty()) { 91*7c3d14c8STreehugger Robot uptr idx = t1.getAndClearFirstOne(); 92*7c3d14c8STreehugger Robot if (!v[idx].empty()) { 93*7c3d14c8STreehugger Robot v[idx].clear(); 94*7c3d14c8STreehugger Robot res = true; 95*7c3d14c8STreehugger Robot } 96*7c3d14c8STreehugger Robot } 97*7c3d14c8STreehugger Robot return res; 98*7c3d14c8STreehugger Robot } 99*7c3d14c8STreehugger Robot removeEdgesFrom(uptr from)100*7c3d14c8STreehugger Robot void removeEdgesFrom(uptr from) { 101*7c3d14c8STreehugger Robot return v[from].clear(); 102*7c3d14c8STreehugger Robot } 103*7c3d14c8STreehugger Robot hasEdge(uptr from,uptr to)104*7c3d14c8STreehugger Robot bool hasEdge(uptr from, uptr to) const { 105*7c3d14c8STreehugger Robot check(from, to); 106*7c3d14c8STreehugger Robot return v[from].getBit(to); 107*7c3d14c8STreehugger Robot } 108*7c3d14c8STreehugger Robot 109*7c3d14c8STreehugger Robot // Returns true if there is a path from the node 'from' 110*7c3d14c8STreehugger Robot // to any of the nodes in 'targets'. isReachable(uptr from,const BV & targets)111*7c3d14c8STreehugger Robot bool isReachable(uptr from, const BV &targets) { 112*7c3d14c8STreehugger Robot BV &to_visit = t1, 113*7c3d14c8STreehugger Robot &visited = t2; 114*7c3d14c8STreehugger Robot to_visit.copyFrom(v[from]); 115*7c3d14c8STreehugger Robot visited.clear(); 116*7c3d14c8STreehugger Robot visited.setBit(from); 117*7c3d14c8STreehugger Robot while (!to_visit.empty()) { 118*7c3d14c8STreehugger Robot uptr idx = to_visit.getAndClearFirstOne(); 119*7c3d14c8STreehugger Robot if (visited.setBit(idx)) 120*7c3d14c8STreehugger Robot to_visit.setUnion(v[idx]); 121*7c3d14c8STreehugger Robot } 122*7c3d14c8STreehugger Robot return targets.intersectsWith(visited); 123*7c3d14c8STreehugger Robot } 124*7c3d14c8STreehugger Robot 125*7c3d14c8STreehugger Robot // Finds a path from 'from' to one of the nodes in 'target', 126*7c3d14c8STreehugger Robot // stores up to 'path_size' items of the path into 'path', 127*7c3d14c8STreehugger Robot // returns the path length, or 0 if there is no path of size 'path_size'. findPath(uptr from,const BV & targets,uptr * path,uptr path_size)128*7c3d14c8STreehugger Robot uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) { 129*7c3d14c8STreehugger Robot if (path_size == 0) 130*7c3d14c8STreehugger Robot return 0; 131*7c3d14c8STreehugger Robot path[0] = from; 132*7c3d14c8STreehugger Robot if (targets.getBit(from)) 133*7c3d14c8STreehugger Robot return 1; 134*7c3d14c8STreehugger Robot // The function is recursive, so we don't want to create BV on stack. 135*7c3d14c8STreehugger Robot // Instead of a getAndClearFirstOne loop we use the slower iterator. 136*7c3d14c8STreehugger Robot for (typename BV::Iterator it(v[from]); it.hasNext(); ) { 137*7c3d14c8STreehugger Robot uptr idx = it.next(); 138*7c3d14c8STreehugger Robot if (uptr res = findPath(idx, targets, path + 1, path_size - 1)) 139*7c3d14c8STreehugger Robot return res + 1; 140*7c3d14c8STreehugger Robot } 141*7c3d14c8STreehugger Robot return 0; 142*7c3d14c8STreehugger Robot } 143*7c3d14c8STreehugger Robot 144*7c3d14c8STreehugger Robot // Same as findPath, but finds a shortest path. findShortestPath(uptr from,const BV & targets,uptr * path,uptr path_size)145*7c3d14c8STreehugger Robot uptr findShortestPath(uptr from, const BV &targets, uptr *path, 146*7c3d14c8STreehugger Robot uptr path_size) { 147*7c3d14c8STreehugger Robot for (uptr p = 1; p <= path_size; p++) 148*7c3d14c8STreehugger Robot if (findPath(from, targets, path, p) == p) 149*7c3d14c8STreehugger Robot return p; 150*7c3d14c8STreehugger Robot return 0; 151*7c3d14c8STreehugger Robot } 152*7c3d14c8STreehugger Robot 153*7c3d14c8STreehugger Robot private: check(uptr idx1,uptr idx2)154*7c3d14c8STreehugger Robot void check(uptr idx1, uptr idx2) const { 155*7c3d14c8STreehugger Robot CHECK_LT(idx1, size()); 156*7c3d14c8STreehugger Robot CHECK_LT(idx2, size()); 157*7c3d14c8STreehugger Robot } 158*7c3d14c8STreehugger Robot BV v[kSize]; 159*7c3d14c8STreehugger Robot // Keep temporary vectors here since we can not create large objects on stack. 160*7c3d14c8STreehugger Robot BV t1, t2; 161*7c3d14c8STreehugger Robot }; 162*7c3d14c8STreehugger Robot 163*7c3d14c8STreehugger Robot } // namespace __sanitizer 164*7c3d14c8STreehugger Robot 165*7c3d14c8STreehugger Robot #endif // SANITIZER_BVGRAPH_H 166