xref: /aosp_15_r20/external/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
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