brw_cfg.cpp revision 01e04c3f
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 36static bblock_t * 37pop_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 46static exec_node * 47link(void *mem_ctx, bblock_t *block) 48{ 49 bblock_link *l = new(mem_ctx) bblock_link(block); 50 return &l->link; 51} 52 53bblock_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 61void 62bblock_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 68bool 69bblock_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 80bool 81bblock_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 92static bool 93ends_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 105static bool 106starts_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 114bool 115bblock_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 127void 128bblock_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 144void 145bblock_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 155cfg_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 389cfg_t::~cfg_t() 390{ 391 ralloc_free(mem_ctx); 392} 393 394void 395cfg_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 447bblock_t * 448cfg_t::new_block() 449{ 450 bblock_t *block = new(mem_ctx) bblock_t(this); 451 452 return block; 453} 454 455void 456cfg_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 468void 469cfg_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 480void 481cfg_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 */ 516void 517cfg_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 553bblock_t * 554cfg_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 570void 571cfg_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 584void 585cfg_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