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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * 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 DUMMY
51 };
52
53 Edge(Node *dst, Node *src, Type kind);
~Edge()54 ~Edge() { unlink(); }
55
getOrigin()56 inline Node *getOrigin() const { return origin; }
getTarget()57 inline Node *getTarget() const { return target; }
58
getType()59 inline Type getType() const { return type; }
60 const char *typeStr() const;
61
62 private:
63 Node *origin;
64 Node *target;
65
66 Type type;
67 Edge *next[2]; // next edge outgoing/incident from/to origin/target
68 Edge *prev[2];
69
70 void unlink();
71
72 friend class Graph;
73 };
74
75 class EdgeIterator : public Iterator
76 {
77 public:
EdgeIterator()78 EdgeIterator() : e(0), t(0), d(0), rev(false) { }
EdgeIterator(Graph::Edge * first,int dir,bool reverse)79 EdgeIterator(Graph::Edge *first, int dir, bool reverse)
80 : d(dir), rev(reverse)
81 {
82 t = e = ((rev && first) ? first->prev[d] : first);
83 }
84
next()85 virtual void next()
86 {
87 Graph::Edge *n = (rev ? e->prev[d] : e->next[d]);
88 e = (n == t ? NULL : n);
89 }
end()90 virtual bool end() const { return !e; }
get()91 virtual void *get() const { return e; }
92
getNode()93 inline Node *getNode() const { assert(e); return d ?
94 e->origin : e->target; }
getEdge()95 inline Edge *getEdge() const { return e; }
getType()96 inline Edge::Type getType() { return e ? e->getType() : Edge::UNKNOWN; }
97
98 private:
99 Graph::Edge *e;
100 Graph::Edge *t;
101 int d;
102 bool rev;
103 };
104
105 class Node
106 {
107 public:
108 Node(void *);
~Node()109 ~Node() { cut(); }
110
111 void attach(Node *, Edge::Type);
112 bool detach(Node *);
113 void cut();
114
115 inline EdgeIterator outgoing(bool reverse = false) const;
116 inline EdgeIterator incident(bool reverse = false) const;
117
118 inline Node *parent() const; // returns NULL if count(incident edges) != 1
119
120 bool reachableBy(const Node *node, const Node *term) const;
121
122 inline bool visit(int);
123 inline int getSequence() const;
124
125 inline int incidentCountFwd() const; // count of incident non-back edges
incidentCount()126 inline int incidentCount() const { return inCount; }
outgoingCount()127 inline int outgoingCount() const { return outCount; }
128
getGraph()129 Graph *getGraph() const { return graph; }
130
131 void *data;
132
133 private:
134 Edge *in;
135 Edge *out;
136 Graph *graph;
137
138 int visited;
139
140 int16_t inCount;
141 int16_t outCount;
142 public:
143 int tag; // for temporary use
144
145 friend class Graph;
146 };
147
148 public:
149 Graph();
150 ~Graph(); // does *not* free the nodes (make it an option ?)
151
getRoot()152 inline Node *getRoot() const { return root; }
153
getSize()154 inline unsigned int getSize() const { return size; }
155
156 inline int nextSequence();
157
158 void insert(Node *node); // attach to or set as root
159
160 IteratorRef iteratorDFS(bool preorder = true);
161 IteratorRef iteratorCFG();
162
163 // safe iterators are unaffected by changes to the *edges* of the graph
164 IteratorRef safeIteratorDFS(bool preorder = true);
165 IteratorRef safeIteratorCFG();
166
167 void classifyEdges();
168
169 // @weights: indexed by Node::tag
170 int findLightestPathWeight(Node *, Node *, const std::vector<int>& weights);
171
172 private:
173 void classifyDFS(Node *, int&);
174
175 private:
176 Node *root;
177 unsigned int size;
178 int sequence;
179 };
180
nextSequence()181 int Graph::nextSequence()
182 {
183 return ++sequence;
184 }
185
parent()186 Graph::Node *Graph::Node::parent() const
187 {
188 if (inCount != 1)
189 return NULL;
190 assert(in);
191 return in->origin;
192 }
193
visit(int v)194 bool Graph::Node::visit(int v)
195 {
196 if (visited == v)
197 return false;
198 visited = v;
199 return true;
200 }
201
getSequence()202 int Graph::Node::getSequence() const
203 {
204 return visited;
205 }
206
outgoing(bool reverse)207 Graph::EdgeIterator Graph::Node::outgoing(bool reverse) const
208 {
209 return EdgeIterator(out, 0, reverse);
210 }
211
incident(bool reverse)212 Graph::EdgeIterator Graph::Node::incident(bool reverse) const
213 {
214 return EdgeIterator(in, 1, reverse);
215 }
216
incidentCountFwd()217 int Graph::Node::incidentCountFwd() const
218 {
219 int n = 0;
220 for (EdgeIterator ei = incident(); !ei.end(); ei.next())
221 if (ei.getType() != Edge::BACK)
222 ++n;
223 return n;
224 }
225
226 } // namespace nv50_ir
227
228 #endif // __NV50_IR_GRAPH_H__
229