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 #include "codegen/nv50_ir_graph.h"
24 #include <limits>
25 #include <list>
26 #include <stack>
27 #include "codegen/nv50_ir.h"
28
29 namespace nv50_ir {
30
Graph()31 Graph::Graph()
32 {
33 root = NULL;
34 size = 0;
35 sequence = 0;
36 }
37
~Graph()38 Graph::~Graph()
39 {
40 for (IteratorRef it = safeIteratorDFS(); !it->end(); it->next())
41 reinterpret_cast<Node *>(it->get())->cut();
42 }
43
insert(Node * node)44 void Graph::insert(Node *node)
45 {
46 if (!root)
47 root = node;
48
49 node->graph = this;
50 size++;
51 }
52
unlink()53 void Graph::Edge::unlink()
54 {
55 if (origin) {
56 prev[0]->next[0] = next[0];
57 next[0]->prev[0] = prev[0];
58 if (origin->out == this)
59 origin->out = (next[0] == this) ? NULL : next[0];
60
61 --origin->outCount;
62 }
63 if (target) {
64 prev[1]->next[1] = next[1];
65 next[1]->prev[1] = prev[1];
66 if (target->in == this)
67 target->in = (next[1] == this) ? NULL : next[1];
68
69 --target->inCount;
70 }
71 }
72
typeStr() const73 const char *Graph::Edge::typeStr() const
74 {
75 switch (type) {
76 case TREE: return "tree";
77 case FORWARD: return "forward";
78 case BACK: return "back";
79 case CROSS: return "cross";
80 case UNKNOWN:
81 default:
82 return "unk";
83 }
84 }
85
Node(void * priv)86 Graph::Node::Node(void *priv) : data(priv),
87 in(0), out(0), graph(0),
88 visited(0),
89 inCount(0), outCount(0)
90 {
91 // nothing to do
92 }
93
attach(Node * node,Edge::Type kind)94 void Graph::Node::attach(Node *node, Edge::Type kind)
95 {
96 Edge *edge = new Edge(this, node, kind);
97
98 // insert head
99 if (this->out) {
100 edge->next[0] = this->out;
101 edge->prev[0] = this->out->prev[0];
102 edge->prev[0]->next[0] = edge;
103 this->out->prev[0] = edge;
104 }
105 this->out = edge;
106
107 if (node->in) {
108 edge->next[1] = node->in;
109 edge->prev[1] = node->in->prev[1];
110 edge->prev[1]->next[1] = edge;
111 node->in->prev[1] = edge;
112 }
113 node->in = edge;
114
115 ++this->outCount;
116 ++node->inCount;
117
118 assert(graph || node->graph);
119 if (!node->graph)
120 graph->insert(node);
121 if (!graph)
122 node->graph->insert(this);
123
124 if (kind == Edge::UNKNOWN)
125 graph->classifyEdges();
126 }
127
detach(Graph::Node * node)128 bool Graph::Node::detach(Graph::Node *node)
129 {
130 EdgeIterator ei = this->outgoing();
131 for (; !ei.end(); ei.next())
132 if (ei.getNode() == node)
133 break;
134 if (ei.end()) {
135 ERROR("no such node attached\n");
136 return false;
137 }
138 delete ei.getEdge();
139 return true;
140 }
141
142 // Cut a node from the graph, deleting all attached edges.
cut()143 void Graph::Node::cut()
144 {
145 while (out)
146 delete out;
147 while (in)
148 delete in;
149
150 if (graph) {
151 if (graph->root == this)
152 graph->root = NULL;
153 graph = NULL;
154 }
155 }
156
Edge(Node * org,Node * tgt,Type kind)157 Graph::Edge::Edge(Node *org, Node *tgt, Type kind)
158 {
159 target = tgt;
160 origin = org;
161 type = kind;
162
163 next[0] = next[1] = this;
164 prev[0] = prev[1] = this;
165 }
166
167 bool
reachableBy(const Node * node,const Node * term) const168 Graph::Node::reachableBy(const Node *node, const Node *term) const
169 {
170 std::stack<const Node *> stack;
171 const Node *pos = NULL;
172 const int seq = graph->nextSequence();
173
174 stack.push(node);
175
176 while (!stack.empty()) {
177 pos = stack.top();
178 stack.pop();
179
180 if (pos == this)
181 return true;
182 if (pos == term)
183 continue;
184
185 for (EdgeIterator ei = pos->outgoing(); !ei.end(); ei.next()) {
186 if (ei.getType() == Edge::BACK)
187 continue;
188 if (ei.getNode()->visit(seq))
189 stack.push(ei.getNode());
190 }
191 }
192 return pos == this;
193 }
194
195 class DFSIterator : public Iterator
196 {
197 public:
DFSIterator(Graph * graph,const bool preorder)198 DFSIterator(Graph *graph, const bool preorder)
199 {
200 unsigned int seq = graph->nextSequence();
201
202 nodes = new Graph::Node * [graph->getSize() + 1];
203 count = 0;
204 pos = 0;
205 nodes[graph->getSize()] = 0;
206
207 if (graph->getRoot()) {
208 graph->getRoot()->visit(seq);
209 search(graph->getRoot(), preorder, seq);
210 }
211 }
212
~DFSIterator()213 ~DFSIterator()
214 {
215 if (nodes)
216 delete[] nodes;
217 }
218
search(Graph::Node * node,const bool preorder,const int sequence)219 void search(Graph::Node *node, const bool preorder, const int sequence)
220 {
221 if (preorder)
222 nodes[count++] = node;
223
224 for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next())
225 if (ei.getNode()->visit(sequence))
226 search(ei.getNode(), preorder, sequence);
227
228 if (!preorder)
229 nodes[count++] = node;
230 }
231
end() const232 virtual bool end() const { return pos >= count; }
next()233 virtual void next() { if (pos < count) ++pos; }
get() const234 virtual void *get() const { return nodes[pos]; }
reset()235 virtual void reset() { pos = 0; }
236
237 protected:
238 Graph::Node **nodes;
239 int count;
240 int pos;
241 };
242
iteratorDFS(bool preorder)243 IteratorRef Graph::iteratorDFS(bool preorder)
244 {
245 return IteratorRef(new DFSIterator(this, preorder));
246 }
247
safeIteratorDFS(bool preorder)248 IteratorRef Graph::safeIteratorDFS(bool preorder)
249 {
250 return this->iteratorDFS(preorder);
251 }
252
253 class CFGIterator : public Iterator
254 {
255 public:
CFGIterator(Graph * graph)256 CFGIterator(Graph *graph)
257 {
258 nodes = new Graph::Node * [graph->getSize() + 1];
259 count = 0;
260 pos = 0;
261 nodes[graph->getSize()] = 0;
262
263 // TODO: argh, use graph->sequence instead of tag and just raise it by > 1
264 for (IteratorRef it = graph->iteratorDFS(); !it->end(); it->next())
265 reinterpret_cast<Graph::Node *>(it->get())->tag = 0;
266
267 if (graph->getRoot())
268 search(graph->getRoot(), graph->nextSequence());
269 }
270
~CFGIterator()271 ~CFGIterator()
272 {
273 if (nodes)
274 delete[] nodes;
275 }
276
get() const277 virtual void *get() const { return nodes[pos]; }
end() const278 virtual bool end() const { return pos >= count; }
next()279 virtual void next() { if (pos < count) ++pos; }
reset()280 virtual void reset() { pos = 0; }
281
282 private:
search(Graph::Node * node,const int sequence)283 void search(Graph::Node *node, const int sequence)
284 {
285 Stack bb, cross;
286
287 bb.push(node);
288
289 while (bb.getSize() || cross.getSize()) {
290 if (bb.getSize() == 0)
291 cross.moveTo(bb);
292
293 node = reinterpret_cast<Graph::Node *>(bb.pop().u.p);
294 assert(node);
295 if (!node->visit(sequence))
296 continue;
297 node->tag = 0;
298
299 for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next()) {
300 switch (ei.getType()) {
301 case Graph::Edge::TREE:
302 case Graph::Edge::FORWARD:
303 if (++(ei.getNode()->tag) == ei.getNode()->incidentCountFwd())
304 bb.push(ei.getNode());
305 break;
306 case Graph::Edge::BACK:
307 continue;
308 case Graph::Edge::CROSS:
309 if (++(ei.getNode()->tag) == 1)
310 cross.push(ei.getNode());
311 break;
312 default:
313 assert(!"unknown edge kind in CFG");
314 break;
315 }
316 }
317 nodes[count++] = node;
318 }
319 }
320
321 private:
322 Graph::Node **nodes;
323 int count;
324 int pos;
325 };
326
iteratorCFG()327 IteratorRef Graph::iteratorCFG()
328 {
329 return IteratorRef(new CFGIterator(this));
330 }
331
safeIteratorCFG()332 IteratorRef Graph::safeIteratorCFG()
333 {
334 return this->iteratorCFG();
335 }
336
337 /**
338 * Edge classification:
339 *
340 * We have a graph and want to classify the edges into one of four types:
341 * - TREE: edges that belong to a spanning tree of the graph
342 * - FORWARD: edges from a node to a descendent in the spanning tree
343 * - BACK: edges from a node to a parent (or itself) in the spanning tree
344 * - CROSS: all other edges (because they cross between branches in the
345 * spanning tree)
346 */
classifyEdges()347 void Graph::classifyEdges()
348 {
349 int seq;
350
351 for (IteratorRef it = iteratorDFS(true); !it->end(); it->next()) {
352 Node *node = reinterpret_cast<Node *>(it->get());
353 node->visit(0);
354 node->tag = 0;
355 }
356
357 classifyDFS(root, (seq = 0));
358
359 sequence = seq;
360 }
361
classifyDFS(Node * curr,int & seq)362 void Graph::classifyDFS(Node *curr, int& seq)
363 {
364 Graph::Edge *edge;
365 Graph::Node *node;
366
367 curr->visit(++seq);
368 curr->tag = 1;
369
370 for (edge = curr->out; edge; edge = edge->next[0]) {
371 node = edge->target;
372
373 if (node->getSequence() == 0) {
374 edge->type = Edge::TREE;
375 classifyDFS(node, seq);
376 } else
377 if (node->getSequence() > curr->getSequence()) {
378 edge->type = Edge::FORWARD;
379 } else {
380 edge->type = node->tag ? Edge::BACK : Edge::CROSS;
381 }
382 }
383
384 for (edge = curr->in; edge; edge = edge->next[1]) {
385 node = edge->origin;
386
387 if (node->getSequence() == 0) {
388 edge->type = Edge::TREE;
389 classifyDFS(node, seq);
390 } else
391 if (node->getSequence() > curr->getSequence()) {
392 edge->type = Edge::FORWARD;
393 } else {
394 edge->type = node->tag ? Edge::BACK : Edge::CROSS;
395 }
396 }
397
398 curr->tag = 0;
399 }
400
401 // @dist is indexed by Node::tag, returns -1 if no path found
402 int
findLightestPathWeight(Node * a,Node * b,const std::vector<int> & weight)403 Graph::findLightestPathWeight(Node *a, Node *b, const std::vector<int> &weight)
404 {
405 std::vector<int> path(weight.size(), std::numeric_limits<int>::max());
406 std::list<Node *> nodeList;
407 const int seq = nextSequence();
408
409 path[a->tag] = 0;
410 for (Node *c = a; c && c != b;) {
411 const int p = path[c->tag] + weight[c->tag];
412 for (EdgeIterator ei = c->outgoing(); !ei.end(); ei.next()) {
413 Node *t = ei.getNode();
414 if (t->getSequence() < seq) {
415 if (path[t->tag] == std::numeric_limits<int>::max())
416 nodeList.push_front(t);
417 if (p < path[t->tag])
418 path[t->tag] = p;
419 }
420 }
421 c->visit(seq);
422 Node *next = NULL;
423 for (std::list<Node *>::iterator n = nodeList.begin();
424 n != nodeList.end(); ++n) {
425 if (!next || path[(*n)->tag] < path[next->tag])
426 next = *n;
427 if ((*n) == c) {
428 // erase visited
429 n = nodeList.erase(n);
430 --n;
431 }
432 }
433 c = next;
434 }
435 if (path[b->tag] == std::numeric_limits<int>::max())
436 return -1;
437 return path[b->tag];
438 }
439
440 } // namespace nv50_ir
441