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