1 /*
2 * Copyright © 2012 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 * Eric Anholt <eric@anholt.net>
25 *
26 */
27
28 #include "brw_cfg.h"
29
30 /** @file brw_cfg.cpp
31 *
32 * Walks the shader instructions generated and creates a set of basic
33 * blocks with successor/predecessor edges connecting them.
34 */
35
36 static bblock_t *
pop_stack(exec_list * list)37 pop_stack(exec_list *list)
38 {
39 bblock_link *link = (bblock_link *)list->get_tail();
40 bblock_t *block = link->block;
41 link->link.remove();
42
43 return block;
44 }
45
46 static exec_node *
link(void * mem_ctx,bblock_t * block)47 link(void *mem_ctx, bblock_t *block)
48 {
49 bblock_link *l = new(mem_ctx) bblock_link(block);
50 return &l->link;
51 }
52
bblock_t(cfg_t * cfg)53 bblock_t::bblock_t(cfg_t *cfg) :
54 cfg(cfg), idom(NULL), start_ip(0), end_ip(0), num(0), cycle_count(0)
55 {
56 instructions.make_empty();
57 parents.make_empty();
58 children.make_empty();
59 }
60
61 void
add_successor(void * mem_ctx,bblock_t * successor)62 bblock_t::add_successor(void *mem_ctx, bblock_t *successor)
63 {
64 successor->parents.push_tail(::link(mem_ctx, this));
65 children.push_tail(::link(mem_ctx, successor));
66 }
67
68 bool
is_predecessor_of(const bblock_t * block) const69 bblock_t::is_predecessor_of(const bblock_t *block) const
70 {
71 foreach_list_typed_safe (bblock_link, parent, link, &block->parents) {
72 if (parent->block == this) {
73 return true;
74 }
75 }
76
77 return false;
78 }
79
80 bool
is_successor_of(const bblock_t * block) const81 bblock_t::is_successor_of(const bblock_t *block) const
82 {
83 foreach_list_typed_safe (bblock_link, child, link, &block->children) {
84 if (child->block == this) {
85 return true;
86 }
87 }
88
89 return false;
90 }
91
92 static bool
ends_block(const backend_instruction * inst)93 ends_block(const backend_instruction *inst)
94 {
95 enum opcode op = inst->opcode;
96
97 return op == BRW_OPCODE_IF ||
98 op == BRW_OPCODE_ELSE ||
99 op == BRW_OPCODE_CONTINUE ||
100 op == BRW_OPCODE_BREAK ||
101 op == BRW_OPCODE_DO ||
102 op == BRW_OPCODE_WHILE;
103 }
104
105 static bool
starts_block(const backend_instruction * inst)106 starts_block(const backend_instruction *inst)
107 {
108 enum opcode op = inst->opcode;
109
110 return op == BRW_OPCODE_DO ||
111 op == BRW_OPCODE_ENDIF;
112 }
113
114 bool
can_combine_with(const bblock_t * that) const115 bblock_t::can_combine_with(const bblock_t *that) const
116 {
117 if ((const bblock_t *)this->link.next != that)
118 return false;
119
120 if (ends_block(this->end()) ||
121 starts_block(that->start()))
122 return false;
123
124 return true;
125 }
126
127 void
combine_with(bblock_t * that)128 bblock_t::combine_with(bblock_t *that)
129 {
130 assert(this->can_combine_with(that));
131 foreach_list_typed (bblock_link, link, link, &this->children) {
132 assert(link->block == that);
133 }
134 foreach_list_typed (bblock_link, link, link, &that->parents) {
135 assert(link->block == this);
136 }
137
138 this->end_ip = that->end_ip;
139 this->instructions.append_list(&that->instructions);
140
141 this->cfg->remove_block(that);
142 }
143
144 void
dump(backend_shader * s) const145 bblock_t::dump(backend_shader *s) const
146 {
147 int ip = this->start_ip;
148 foreach_inst_in_block(backend_instruction, inst, this) {
149 fprintf(stderr, "%5d: ", ip);
150 s->dump_instruction(inst);
151 ip++;
152 }
153 }
154
cfg_t(exec_list * instructions)155 cfg_t::cfg_t(exec_list *instructions)
156 {
157 mem_ctx = ralloc_context(NULL);
158 block_list.make_empty();
159 blocks = NULL;
160 num_blocks = 0;
161 idom_dirty = true;
162 cycle_count = 0;
163
164 bblock_t *cur = NULL;
165 int ip = 0;
166
167 bblock_t *entry = new_block();
168 bblock_t *cur_if = NULL; /**< BB ending with IF. */
169 bblock_t *cur_else = NULL; /**< BB ending with ELSE. */
170 bblock_t *cur_endif = NULL; /**< BB starting with ENDIF. */
171 bblock_t *cur_do = NULL; /**< BB starting with DO. */
172 bblock_t *cur_while = NULL; /**< BB immediately following WHILE. */
173 exec_list if_stack, else_stack, do_stack, while_stack;
174 bblock_t *next;
175
176 set_next_block(&cur, entry, ip);
177
178 foreach_in_list_safe(backend_instruction, inst, instructions) {
179 /* set_next_block wants the post-incremented ip */
180 ip++;
181
182 inst->exec_node::remove();
183
184 switch (inst->opcode) {
185 case BRW_OPCODE_IF:
186 cur->instructions.push_tail(inst);
187
188 /* Push our information onto a stack so we can recover from
189 * nested ifs.
190 */
191 if_stack.push_tail(link(mem_ctx, cur_if));
192 else_stack.push_tail(link(mem_ctx, cur_else));
193
194 cur_if = cur;
195 cur_else = NULL;
196 cur_endif = NULL;
197
198 /* Set up our immediately following block, full of "then"
199 * instructions.
200 */
201 next = new_block();
202 cur_if->add_successor(mem_ctx, next);
203
204 set_next_block(&cur, next, ip);
205 break;
206
207 case BRW_OPCODE_ELSE:
208 cur->instructions.push_tail(inst);
209
210 cur_else = cur;
211
212 next = new_block();
213 assert(cur_if != NULL);
214 cur_if->add_successor(mem_ctx, next);
215
216 set_next_block(&cur, next, ip);
217 break;
218
219 case BRW_OPCODE_ENDIF: {
220 if (cur->instructions.is_empty()) {
221 /* New block was just created; use it. */
222 cur_endif = cur;
223 } else {
224 cur_endif = new_block();
225
226 cur->add_successor(mem_ctx, cur_endif);
227
228 set_next_block(&cur, cur_endif, ip - 1);
229 }
230
231 cur->instructions.push_tail(inst);
232
233 if (cur_else) {
234 cur_else->add_successor(mem_ctx, cur_endif);
235 } else {
236 assert(cur_if != NULL);
237 cur_if->add_successor(mem_ctx, cur_endif);
238 }
239
240 assert(cur_if->end()->opcode == BRW_OPCODE_IF);
241 assert(!cur_else || cur_else->end()->opcode == BRW_OPCODE_ELSE);
242
243 /* Pop the stack so we're in the previous if/else/endif */
244 cur_if = pop_stack(&if_stack);
245 cur_else = pop_stack(&else_stack);
246 break;
247 }
248 case BRW_OPCODE_DO:
249 /* Push our information onto a stack so we can recover from
250 * nested loops.
251 */
252 do_stack.push_tail(link(mem_ctx, cur_do));
253 while_stack.push_tail(link(mem_ctx, cur_while));
254
255 /* Set up the block just after the while. Don't know when exactly
256 * it will start, yet.
257 */
258 cur_while = new_block();
259
260 if (cur->instructions.is_empty()) {
261 /* New block was just created; use it. */
262 cur_do = cur;
263 } else {
264 cur_do = new_block();
265
266 cur->add_successor(mem_ctx, cur_do);
267
268 set_next_block(&cur, cur_do, ip - 1);
269 }
270
271 cur->instructions.push_tail(inst);
272
273 /* Represent divergent execution of the loop as a pair of alternative
274 * edges coming out of the DO instruction: For any physical iteration
275 * of the loop a given logical thread can either start off enabled
276 * (which is represented as the "next" successor), or disabled (if it
277 * has reached a non-uniform exit of the loop during a previous
278 * iteration, which is represented as the "cur_while" successor).
279 *
280 * The disabled edge will be taken by the logical thread anytime we
281 * arrive at the DO instruction through a back-edge coming from a
282 * conditional exit of the loop where divergent control flow started.
283 *
284 * This guarantees that there is a control-flow path from any
285 * divergence point of the loop into the convergence point
286 * (immediately past the WHILE instruction) such that it overlaps the
287 * whole IP region of divergent control flow (potentially the whole
288 * loop) *and* doesn't imply the execution of any instructions part
289 * of the loop (since the corresponding execution mask bit will be
290 * disabled for a diverging thread).
291 *
292 * This way we make sure that any variables that are live throughout
293 * the region of divergence for an inactive logical thread are also
294 * considered to interfere with any other variables assigned by
295 * active logical threads within the same physical region of the
296 * program, since otherwise we would risk cross-channel data
297 * corruption.
298 */
299 next = new_block();
300 cur->add_successor(mem_ctx, next);
301 cur->add_successor(mem_ctx, cur_while);
302 set_next_block(&cur, next, ip);
303 break;
304
305 case BRW_OPCODE_CONTINUE:
306 cur->instructions.push_tail(inst);
307
308 /* A conditional CONTINUE may start a region of divergent control
309 * flow until the start of the next loop iteration (*not* until the
310 * end of the loop which is why the successor is not the top-level
311 * divergence point at cur_do). The live interval of any variable
312 * extending through a CONTINUE edge is guaranteed to overlap the
313 * whole region of divergent execution, because any variable live-out
314 * at the CONTINUE instruction will also be live-in at the top of the
315 * loop, and therefore also live-out at the bottom-most point of the
316 * loop which is reachable from the top (since a control flow path
317 * exists from a definition of the variable through this CONTINUE
318 * instruction, the top of the loop, the (reachable) bottom of the
319 * loop, the top of the loop again, into a use of the variable).
320 */
321 assert(cur_do != NULL);
322 cur->add_successor(mem_ctx, cur_do->next());
323
324 next = new_block();
325 if (inst->predicate)
326 cur->add_successor(mem_ctx, next);
327
328 set_next_block(&cur, next, ip);
329 break;
330
331 case BRW_OPCODE_BREAK:
332 cur->instructions.push_tail(inst);
333
334 /* A conditional BREAK instruction may start a region of divergent
335 * control flow until the end of the loop if the condition is
336 * non-uniform, in which case the loop will execute additional
337 * iterations with the present channel disabled. We model this as a
338 * control flow path from the divergence point to the convergence
339 * point that overlaps the whole IP range of the loop and skips over
340 * the execution of any other instructions part of the loop.
341 *
342 * See the DO case for additional explanation.
343 */
344 assert(cur_do != NULL);
345 cur->add_successor(mem_ctx, cur_do);
346
347 next = new_block();
348 if (inst->predicate)
349 cur->add_successor(mem_ctx, next);
350
351 set_next_block(&cur, next, ip);
352 break;
353
354 case BRW_OPCODE_WHILE:
355 cur->instructions.push_tail(inst);
356
357 assert(cur_do != NULL && cur_while != NULL);
358
359 /* A conditional WHILE instruction may start a region of divergent
360 * control flow until the end of the loop, just like the BREAK
361 * instruction. See the BREAK case for more details. OTOH an
362 * unconditional WHILE instruction is non-divergent (just like an
363 * unconditional CONTINUE), and will necessarily lead to the
364 * execution of an additional iteration of the loop for all enabled
365 * channels, so we may skip over the divergence point at the top of
366 * the loop to keep the CFG as unambiguous as possible.
367 */
368 cur->add_successor(mem_ctx, inst->predicate ? cur_do :
369 cur_do->next());
370
371 set_next_block(&cur, cur_while, ip);
372
373 /* Pop the stack so we're in the previous loop */
374 cur_do = pop_stack(&do_stack);
375 cur_while = pop_stack(&while_stack);
376 break;
377
378 default:
379 cur->instructions.push_tail(inst);
380 break;
381 }
382 }
383
384 cur->end_ip = ip - 1;
385
386 make_block_array();
387 }
388
~cfg_t()389 cfg_t::~cfg_t()
390 {
391 ralloc_free(mem_ctx);
392 }
393
394 void
remove_block(bblock_t * block)395 cfg_t::remove_block(bblock_t *block)
396 {
397 foreach_list_typed_safe (bblock_link, predecessor, link, &block->parents) {
398 /* Remove block from all of its predecessors' successor lists. */
399 foreach_list_typed_safe (bblock_link, successor, link,
400 &predecessor->block->children) {
401 if (block == successor->block) {
402 successor->link.remove();
403 ralloc_free(successor);
404 }
405 }
406
407 /* Add removed-block's successors to its predecessors' successor lists. */
408 foreach_list_typed (bblock_link, successor, link, &block->children) {
409 if (!successor->block->is_successor_of(predecessor->block)) {
410 predecessor->block->children.push_tail(link(mem_ctx,
411 successor->block));
412 }
413 }
414 }
415
416 foreach_list_typed_safe (bblock_link, successor, link, &block->children) {
417 /* Remove block from all of its childrens' parents lists. */
418 foreach_list_typed_safe (bblock_link, predecessor, link,
419 &successor->block->parents) {
420 if (block == predecessor->block) {
421 predecessor->link.remove();
422 ralloc_free(predecessor);
423 }
424 }
425
426 /* Add removed-block's predecessors to its successors' predecessor lists. */
427 foreach_list_typed (bblock_link, predecessor, link, &block->parents) {
428 if (!predecessor->block->is_predecessor_of(successor->block)) {
429 successor->block->parents.push_tail(link(mem_ctx,
430 predecessor->block));
431 }
432 }
433 }
434
435 block->link.remove();
436
437 for (int b = block->num; b < this->num_blocks - 1; b++) {
438 this->blocks[b] = this->blocks[b + 1];
439 this->blocks[b]->num = b;
440 }
441
442 this->blocks[this->num_blocks - 1]->num = this->num_blocks - 2;
443 this->num_blocks--;
444 idom_dirty = true;
445 }
446
447 bblock_t *
new_block()448 cfg_t::new_block()
449 {
450 bblock_t *block = new(mem_ctx) bblock_t(this);
451
452 return block;
453 }
454
455 void
set_next_block(bblock_t ** cur,bblock_t * block,int ip)456 cfg_t::set_next_block(bblock_t **cur, bblock_t *block, int ip)
457 {
458 if (*cur) {
459 (*cur)->end_ip = ip - 1;
460 }
461
462 block->start_ip = ip;
463 block->num = num_blocks++;
464 block_list.push_tail(&block->link);
465 *cur = block;
466 }
467
468 void
make_block_array()469 cfg_t::make_block_array()
470 {
471 blocks = ralloc_array(mem_ctx, bblock_t *, num_blocks);
472
473 int i = 0;
474 foreach_block (block, this) {
475 blocks[i++] = block;
476 }
477 assert(i == num_blocks);
478 }
479
480 void
dump(backend_shader * s)481 cfg_t::dump(backend_shader *s)
482 {
483 if (idom_dirty)
484 calculate_idom();
485
486 foreach_block (block, this) {
487 if (block->idom)
488 fprintf(stderr, "START B%d IDOM(B%d)", block->num, block->idom->num);
489 else
490 fprintf(stderr, "START B%d IDOM(none)", block->num);
491
492 foreach_list_typed(bblock_link, link, link, &block->parents) {
493 fprintf(stderr, " <-B%d",
494 link->block->num);
495 }
496 fprintf(stderr, "\n");
497 if (s != NULL)
498 block->dump(s);
499 fprintf(stderr, "END B%d", block->num);
500 foreach_list_typed(bblock_link, link, link, &block->children) {
501 fprintf(stderr, " ->B%d",
502 link->block->num);
503 }
504 fprintf(stderr, "\n");
505 }
506 }
507
508 /* Calculates the immediate dominator of each block, according to "A Simple,
509 * Fast Dominance Algorithm" by Keith D. Cooper, Timothy J. Harvey, and Ken
510 * Kennedy.
511 *
512 * The authors claim that for control flow graphs of sizes normally encountered
513 * (less than 1000 nodes) that this algorithm is significantly faster than
514 * others like Lengauer-Tarjan.
515 */
516 void
calculate_idom()517 cfg_t::calculate_idom()
518 {
519 foreach_block(block, this) {
520 block->idom = NULL;
521 }
522 blocks[0]->idom = blocks[0];
523
524 bool changed;
525 do {
526 changed = false;
527
528 foreach_block(block, this) {
529 if (block->num == 0)
530 continue;
531
532 bblock_t *new_idom = NULL;
533 foreach_list_typed(bblock_link, parent, link, &block->parents) {
534 if (parent->block->idom) {
535 if (new_idom == NULL) {
536 new_idom = parent->block;
537 } else if (parent->block->idom != NULL) {
538 new_idom = intersect(parent->block, new_idom);
539 }
540 }
541 }
542
543 if (block->idom != new_idom) {
544 block->idom = new_idom;
545 changed = true;
546 }
547 }
548 } while (changed);
549
550 idom_dirty = false;
551 }
552
553 bblock_t *
intersect(bblock_t * b1,bblock_t * b2)554 cfg_t::intersect(bblock_t *b1, bblock_t *b2)
555 {
556 /* Note, the comparisons here are the opposite of what the paper says
557 * because we index blocks from beginning -> end (i.e. reverse post-order)
558 * instead of post-order like they assume.
559 */
560 while (b1->num != b2->num) {
561 while (b1->num > b2->num)
562 b1 = b1->idom;
563 while (b2->num > b1->num)
564 b2 = b2->idom;
565 }
566 assert(b1);
567 return b1;
568 }
569
570 void
dump_cfg()571 cfg_t::dump_cfg()
572 {
573 printf("digraph CFG {\n");
574 for (int b = 0; b < num_blocks; b++) {
575 bblock_t *block = this->blocks[b];
576
577 foreach_list_typed_safe (bblock_link, child, link, &block->children) {
578 printf("\t%d -> %d\n", b, child->block->num);
579 }
580 }
581 printf("}\n");
582 }
583
584 void
dump_domtree()585 cfg_t::dump_domtree()
586 {
587 printf("digraph DominanceTree {\n");
588 foreach_block(block, this) {
589 if (block->idom) {
590 printf("\t%d -> %d\n", block->idom->num, block->num);
591 }
592 }
593 printf("}\n");
594 }
595