nir: Add a lower_vec_to_movs pass
[mesa.git] / src / glsl / nir / nir_dominance.c
1 /*
2 * Copyright © 2014 Intel Corporation
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 (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Connor Abbott (cwabbott0@gmail.com)
25 *
26 */
27
28 #include "nir.h"
29
30 /*
31 * Implements the algorithms for computing the dominance tree and the
32 * dominance frontier from "A Simple, Fast Dominance Algorithm" by Cooper,
33 * Harvey, and Kennedy.
34 */
35
36 typedef struct {
37 nir_function_impl *impl;
38 bool progress;
39 } dom_state;
40
41 static bool
42 init_block_cb(nir_block *block, void *_state)
43 {
44 dom_state *state = (dom_state *) _state;
45 if (block == state->impl->start_block)
46 block->imm_dom = block;
47 else
48 block->imm_dom = NULL;
49 block->num_dom_children = 0;
50
51 struct set_entry *entry;
52 set_foreach(block->dom_frontier, entry) {
53 _mesa_set_remove(block->dom_frontier, entry);
54 }
55
56 return true;
57 }
58
59 static nir_block *
60 intersect(nir_block *b1, nir_block *b2)
61 {
62 while (b1 != b2) {
63 /*
64 * Note, the comparisons here are the opposite of what the paper says
65 * because we index blocks from beginning -> end (i.e. reverse
66 * post-order) instead of post-order like they assume.
67 */
68 while (b1->index > b2->index)
69 b1 = b1->imm_dom;
70 while (b2->index > b1->index)
71 b2 = b2->imm_dom;
72 }
73
74 return b1;
75 }
76
77 static bool
78 calc_dominance_cb(nir_block *block, void *_state)
79 {
80 dom_state *state = (dom_state *) _state;
81 if (block == state->impl->start_block)
82 return true;
83
84 nir_block *new_idom = NULL;
85 struct set_entry *entry;
86 set_foreach(block->predecessors, entry) {
87 nir_block *pred = (nir_block *) entry->key;
88
89 if (pred->imm_dom) {
90 if (new_idom)
91 new_idom = intersect(pred, new_idom);
92 else
93 new_idom = pred;
94 }
95 }
96
97 assert(new_idom);
98 if (block->imm_dom != new_idom) {
99 block->imm_dom = new_idom;
100 state->progress = true;
101 }
102
103 return true;
104 }
105
106 static bool
107 calc_dom_frontier_cb(nir_block *block, void *state)
108 {
109 (void) state;
110
111 if (block->predecessors->entries > 1) {
112 struct set_entry *entry;
113 set_foreach(block->predecessors, entry) {
114 nir_block *runner = (nir_block *) entry->key;
115 while (runner != block->imm_dom) {
116 _mesa_set_add(runner->dom_frontier, _mesa_hash_pointer(block),
117 block);
118 runner = runner->imm_dom;
119 }
120 }
121 }
122
123 return true;
124 }
125
126 /*
127 * Compute each node's children in the dominance tree from the immediate
128 * dominator information. We do this in three stages:
129 *
130 * 1. Calculate the number of children each node has
131 * 2. Allocate arrays, setting the number of children to 0 again
132 * 3. For each node, add itself to its parent's list of children, using
133 * num_dom_children as an index - at the end of this step, num_dom_children
134 * for each node will be the same as it was at the end of step #1.
135 */
136
137 static bool
138 block_count_children(nir_block *block, void *state)
139 {
140 (void) state;
141
142 if (block->imm_dom)
143 block->imm_dom->num_dom_children++;
144
145 return true;
146 }
147
148 static bool
149 block_alloc_children(nir_block *block, void *state)
150 {
151 void *mem_ctx = state;
152
153 block->dom_children = ralloc_array(mem_ctx, nir_block *,
154 block->num_dom_children);
155 block->num_dom_children = 0;
156
157 return true;
158 }
159
160 static bool
161 block_add_child(nir_block *block, void *state)
162 {
163 (void) state;
164
165 if (block->imm_dom)
166 block->imm_dom->dom_children[block->imm_dom->num_dom_children++] = block;
167
168 return true;
169 }
170
171 static void
172 calc_dom_children(nir_function_impl* impl)
173 {
174 void *mem_ctx = ralloc_parent(impl);
175
176 nir_foreach_block(impl, block_count_children, NULL);
177 nir_foreach_block(impl, block_alloc_children, mem_ctx);
178 nir_foreach_block(impl, block_add_child, NULL);
179 }
180
181 void
182 nir_calc_dominance_impl(nir_function_impl *impl)
183 {
184 if (!impl->dominance_dirty)
185 return;
186
187 nir_index_blocks(impl);
188
189 dom_state state;
190 state.impl = impl;
191 state.progress = true;
192
193 nir_foreach_block(impl, init_block_cb, &state);
194
195 while (state.progress) {
196 state.progress = false;
197 nir_foreach_block(impl, calc_dominance_cb, &state);
198 }
199
200 nir_foreach_block(impl, calc_dom_frontier_cb, &state);
201
202 impl->start_block->imm_dom = NULL;
203
204 calc_dom_children(impl);
205
206 impl->dominance_dirty = false;
207 }
208
209 void
210 nir_calc_dominance(nir_shader *shader)
211 {
212 nir_foreach_overload(shader, overload) {
213 if (overload->impl)
214 nir_calc_dominance_impl(overload->impl);
215 }
216 }
217
218 static bool
219 dump_block_dom(nir_block *block, void *state)
220 {
221 FILE *fp = (FILE *) state;
222 if (block->imm_dom)
223 fprintf(fp, "\t%u -> %u\n", block->imm_dom->index, block->index);
224 return true;
225 }
226
227 void
228 nir_dump_dom_tree_impl(nir_function_impl *impl, FILE *fp)
229 {
230 fprintf(fp, "digraph doms_%s {\n", impl->overload->function->name);
231 nir_foreach_block(impl, dump_block_dom, fp);
232 fprintf(fp, "}\n\n");
233 }
234
235 void
236 nir_dump_dom_tree(nir_shader *shader, FILE *fp)
237 {
238 nir_foreach_overload(shader, overload) {
239 if (overload->impl)
240 nir_dump_dom_tree_impl(overload->impl, fp);
241 }
242 }
243
244 static bool
245 dump_block_dom_frontier(nir_block *block, void *state)
246 {
247 FILE *fp = (FILE *) state;
248
249 fprintf(fp, "DF(%u) = {", block->index);
250 struct set_entry *entry;
251 set_foreach(block->dom_frontier, entry) {
252 nir_block *df = (nir_block *) entry->key;
253 fprintf(fp, "%u, ", df->index);
254 }
255 fprintf(fp, "}\n");
256 return true;
257 }
258
259 void
260 nir_dump_dom_frontier_impl(nir_function_impl *impl, FILE *fp)
261 {
262 nir_foreach_block(impl, dump_block_dom_frontier, fp);
263 }
264
265 void
266 nir_dump_dom_frontier(nir_shader *shader, FILE *fp)
267 {
268 nir_foreach_overload(shader, overload) {
269 if (overload->impl)
270 nir_dump_dom_frontier_impl(overload->impl, fp);
271 }
272 }
273
274 static bool
275 dump_block_succs(nir_block *block, void *state)
276 {
277 FILE *fp = (FILE *) state;
278 if (block->successors[0])
279 fprintf(fp, "\t%u -> %u\n", block->index, block->successors[0]->index);
280 if (block->successors[1])
281 fprintf(fp, "\t%u -> %u\n", block->index, block->successors[1]->index);
282 return true;
283 }
284
285 void
286 nir_dump_cfg_impl(nir_function_impl *impl, FILE *fp)
287 {
288 fprintf(fp, "digraph cfg_%s {\n", impl->overload->function->name);
289 nir_foreach_block(impl, dump_block_succs, fp);
290 fprintf(fp, "}\n\n");
291 }
292
293 void
294 nir_dump_cfg(nir_shader *shader, FILE *fp)
295 {
296 nir_foreach_overload(shader, overload) {
297 if (overload->impl)
298 nir_dump_cfg_impl(overload->impl, fp);
299 }
300 }