nv50/ir: add function for splitting a BasicBlock
[mesa.git] / src / gallium / drivers / nv50 / codegen / nv50_ir_graph.h
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
28 namespace nv50_ir {
29
30 #define ITER_NODE(x) reinterpret_cast<Graph::Node *>((x).get())
31 #define ITER_EDGE(x) reinterpret_cast<Graph::Edge *>((x).get())
32
33 // A connected graph.
34 class Graph
35 {
36 public:
37 class Node;
38
39 class GraphIterator : public Iterator
40 {
41 public:
42 virtual ~GraphIterator() { };
43 };
44
45 class Edge
46 {
47 public:
48 enum Type
49 {
50 UNKNOWN,
51 TREE,
52 FORWARD,
53 BACK,
54 CROSS, // e.g. loop break
55 DUMMY
56 };
57
58 Edge(Node *dst, Node *src, Type kind);
59 ~Edge() { unlink(); }
60
61 inline Node *getOrigin() const { return origin; }
62 inline Node *getTarget() const { return target; }
63
64 inline Type getType() const { return type; }
65 const char *typeStr() const;
66
67 private:
68 Node *origin;
69 Node *target;
70
71 Type type;
72 Edge *next[2]; // next edge outgoing/incident from/to origin/target
73 Edge *prev[2];
74
75 void unlink();
76
77 friend class Graph;
78 };
79
80 class EdgeIterator : public Iterator
81 {
82 public:
83 EdgeIterator() : e(0), t(0), d(0), rev(false) { }
84 EdgeIterator(Graph::Edge *first, int dir, bool reverse)
85 : d(dir), rev(reverse)
86 {
87 t = e = ((rev && first) ? first->prev[d] : first);
88 }
89
90 virtual void next()
91 {
92 Graph::Edge *n = (rev ? e->prev[d] : e->next[d]);
93 e = (n == t ? NULL : n);
94 }
95 virtual bool end() const { return !e; }
96 virtual void *get() const { return e; }
97
98 inline Node *getNode() const { assert(e); return d ?
99 e->origin : e->target; }
100 inline Edge *getEdge() const { return e; }
101 inline Edge::Type getType() { return e ? e->getType() : Edge::UNKNOWN; }
102
103 private:
104 Graph::Edge *e;
105 Graph::Edge *t;
106 int d;
107 bool rev;
108 };
109
110 class Node
111 {
112 public:
113 Node(void *);
114 ~Node() { cut(); }
115
116 void attach(Node *, Edge::Type);
117 bool detach(Node *);
118 void cut();
119
120 inline EdgeIterator outgoing(bool reverse = false) const;
121 inline EdgeIterator incident(bool reverse = false) const;
122
123 inline Node *parent() const; // returns NULL if count(incident edges) != 1
124
125 bool reachableBy(Node *node, Node *term);
126
127 inline bool visit(int);
128 inline int getSequence() const;
129
130 inline int incidentCountFwd() const; // count of incident non-back edges
131 inline int incidentCount() const { return inCount; }
132 inline int outgoingCount() const { return outCount; }
133
134 Graph *getGraph() const { return graph; }
135
136 void *data;
137
138 private:
139 Edge *in;
140 Edge *out;
141 Graph *graph;
142
143 int visited;
144
145 int16_t inCount;
146 int16_t outCount;
147 public:
148 int tag; // for temporary use
149
150 friend class Graph;
151 };
152
153 public:
154 Graph();
155 ~Graph(); // does *not* free the nodes (make it an option ?)
156
157 inline Node *getRoot() const { return root; }
158
159 inline unsigned int getSize() const { return size; }
160
161 inline int nextSequence();
162
163 void insert(Node *node); // attach to or set as root
164
165 GraphIterator *iteratorDFS(bool preorder = true);
166 GraphIterator *iteratorCFG();
167
168 // safe iterators are unaffected by changes to the *edges* of the graph
169 GraphIterator *safeIteratorDFS(bool preorder = true);
170 GraphIterator *safeIteratorCFG();
171
172 inline void putIterator(Iterator *); // should be GraphIterator *
173
174 void classifyEdges();
175
176 private:
177 void classifyDFS(Node *, int&);
178
179 private:
180 Node *root;
181 unsigned int size;
182 int sequence;
183 };
184
185 int Graph::nextSequence()
186 {
187 return ++sequence;
188 }
189
190 Graph::Node *Graph::Node::parent() const
191 {
192 if (inCount != 1)
193 return NULL;
194 assert(in);
195 return in->origin;
196 }
197
198 bool Graph::Node::visit(int v)
199 {
200 if (visited == v)
201 return false;
202 visited = v;
203 return true;
204 }
205
206 int Graph::Node::getSequence() const
207 {
208 return visited;
209 }
210
211 void Graph::putIterator(Iterator *iter)
212 {
213 delete reinterpret_cast<GraphIterator *>(iter);
214 }
215
216 Graph::EdgeIterator Graph::Node::outgoing(bool reverse) const
217 {
218 return EdgeIterator(out, 0, reverse);
219 }
220
221 Graph::EdgeIterator Graph::Node::incident(bool reverse) const
222 {
223 return EdgeIterator(in, 1, reverse);
224 }
225
226 int Graph::Node::incidentCountFwd() const
227 {
228 int n = 0;
229 for (EdgeIterator ei = incident(); !ei.end(); ei.next())
230 if (ei.getType() != Edge::BACK)
231 ++n;
232 return n;
233 }
234
235 } // namespace nv50_ir
236
237 #endif // __NV50_IR_GRAPH_H__