1 /*
2 * Copyright 2011 Christoph Bumiller
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #ifndef __NV50_IR_GRAPH_H__
24 #define __NV50_IR_GRAPH_H__
25
26 #include "nv50_ir_util.h"
27 #include <vector>
28
29 namespace nv50_ir {
30
31 #define ITER_NODE(x) reinterpret_cast<Graph::Node *>((x).get())
32 #define ITER_EDGE(x) reinterpret_cast<Graph::Edge *>((x).get())
33
34 // A connected graph.
35 class Graph
36 {
37 public:
38 class Node;
39
40 class Edge
41 {
42 public:
43 enum Type
44 {
45 UNKNOWN,
46 TREE,
47 FORWARD,
48 BACK,
49 CROSS, // e.g. loop break
50 };
51
52 Edge(Node *dst, Node *src, Type kind);
~Edge()53 ~Edge() { unlink(); }
54
getOrigin()55 inline Node *getOrigin() const { return origin; }
getTarget()56 inline Node *getTarget() const { return target; }
57
getType()58 inline Type getType() const { return type; }
59 const char *typeStr() const;
60
61 private:
62 Node *origin;
63 Node *target;
64
65 Type type;
66 Edge *next[2]; // next edge outgoing/incident from/to origin/target
67 Edge *prev[2];
68
69 void unlink();
70
71 friend class Graph;
72 };
73
74 class EdgeIterator : public Iterator
75 {
76 public:
EdgeIterator()77 EdgeIterator() : e(0), t(0), d(0), rev(false) { }
EdgeIterator(Graph::Edge * first,int dir,bool reverse)78 EdgeIterator(Graph::Edge *first, int dir, bool reverse)
79 : d(dir), rev(reverse)
80 {
81 t = e = ((rev && first) ? first->prev[d] : first);
82 }
83
next()84 virtual void next()
85 {
86 Graph::Edge *n = (rev ? e->prev[d] : e->next[d]);
87 e = (n == t ? NULL : n);
88 }
end()89 virtual bool end() const { return !e; }
get()90 virtual void *get() const { return e; }
91
getNode()92 inline Node *getNode() const { assert(e); return d ?
93 e->origin : e->target; }
getEdge()94 inline Edge *getEdge() const { return e; }
getType()95 inline Edge::Type getType() { return e ? e->getType() : Edge::UNKNOWN; }
96
97 private:
98 Graph::Edge *e;
99 Graph::Edge *t;
100 int d;
101 bool rev;
102 };
103
104 class Node
105 {
106 public:
107 Node(void *);
~Node()108 ~Node() { cut(); }
109
110 void attach(Node *, Edge::Type);
111 bool detach(Node *);
112 void cut();
113
114 inline EdgeIterator outgoing(bool reverse = false) const;
115 inline EdgeIterator incident(bool reverse = false) const;
116
117 inline Node *parent() const; // returns NULL if count(incident edges) != 1
118
119 bool reachableBy(const Node *node, const Node *term) const;
120
121 inline bool visit(int);
122 inline int getSequence() const;
123
124 inline int incidentCountFwd() const; // count of incident non-back edges
incidentCount()125 inline int incidentCount() const { return inCount; }
outgoingCount()126 inline int outgoingCount() const { return outCount; }
127
getGraph()128 Graph *getGraph() const { return graph; }
129
130 void *data;
131
132 private:
133 Edge *in;
134 Edge *out;
135 Graph *graph;
136
137 int visited;
138
139 int16_t inCount;
140 int16_t outCount;
141 public:
142 int tag; // for temporary use
143
144 friend class Graph;
145 };
146
147 public:
148 Graph();
149 virtual ~Graph(); // does *not* free the nodes (make it an option ?)
150
getRoot()151 inline Node *getRoot() const { return root; }
152
getSize()153 inline unsigned int getSize() const { return size; }
154
155 inline int nextSequence();
156
157 void insert(Node *node); // attach to or set as root
158
159 IteratorRef iteratorDFS(bool preorder = true);
160 IteratorRef iteratorCFG();
161
162 // safe iterators are unaffected by changes to the *edges* of the graph
163 IteratorRef safeIteratorDFS(bool preorder = true);
164 IteratorRef safeIteratorCFG();
165
166 void classifyEdges();
167
168 // @weights: indexed by Node::tag
169 int findLightestPathWeight(Node *, Node *, const std::vector<int>& weights);
170
171 private:
172 void classifyDFS(Node *, int&);
173
174 private:
175 Node *root;
176 unsigned int size;
177 int sequence;
178 };
179
nextSequence()180 int Graph::nextSequence()
181 {
182 return ++sequence;
183 }
184
parent()185 Graph::Node *Graph::Node::parent() const
186 {
187 if (inCount != 1)
188 return NULL;
189 assert(in);
190 return in->origin;
191 }
192
visit(int v)193 bool Graph::Node::visit(int v)
194 {
195 if (visited == v)
196 return false;
197 visited = v;
198 return true;
199 }
200
getSequence()201 int Graph::Node::getSequence() const
202 {
203 return visited;
204 }
205
outgoing(bool reverse)206 Graph::EdgeIterator Graph::Node::outgoing(bool reverse) const
207 {
208 return EdgeIterator(out, 0, reverse);
209 }
210
incident(bool reverse)211 Graph::EdgeIterator Graph::Node::incident(bool reverse) const
212 {
213 return EdgeIterator(in, 1, reverse);
214 }
215
incidentCountFwd()216 int Graph::Node::incidentCountFwd() const
217 {
218 int n = 0;
219 for (EdgeIterator ei = incident(); !ei.end(); ei.next())
220 if (ei.getType() != Edge::BACK)
221 ++n;
222 return n;
223 }
224
225 } // namespace nv50_ir
226
227 #endif // __NV50_IR_GRAPH_H__
228