1 /* 2 * Copyright 2013 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 24 /** @file brw_dead_control_flow.cpp 25 * 26 * This file implements the dead control flow elimination optimization pass. 27 */ 28 29 #include "brw_shader.h" 30 #include "brw_cfg.h" 31 32 /* Look for and eliminate dead control flow: 33 * 34 * - if/endif 35 * - else in else/endif 36 * - then in if/else/endif 37 */ 38 bool 39 dead_control_flow_eliminate(backend_shader *s) 40 { 41 bool progress = false; 42 43 foreach_block_safe (block, s->cfg) { 44 bblock_t *prev_block = block->prev(); 45 46 if (!prev_block) 47 continue; 48 49 backend_instruction *const inst = block->start(); 50 backend_instruction *const prev_inst = prev_block->end(); 51 52 /* ENDIF instructions, by definition, can only be found at the start of 53 * basic blocks. 54 */ 55 if (inst->opcode == BRW_OPCODE_ENDIF && 56 prev_inst->opcode == BRW_OPCODE_ELSE) { 57 bblock_t *const else_block = prev_block; 58 backend_instruction *const else_inst = prev_inst; 59 60 else_inst->remove(else_block); 61 progress = true; 62 } else if (inst->opcode == BRW_OPCODE_ENDIF && 63 prev_inst->opcode == BRW_OPCODE_IF) { 64 bblock_t *const endif_block = block; 65 bblock_t *const if_block = prev_block; 66 backend_instruction *const endif_inst = inst; 67 backend_instruction *const if_inst = prev_inst; 68 69 bblock_t *earlier_block = NULL, *later_block = NULL; 70 71 if (if_block->start_ip == if_block->end_ip) { 72 earlier_block = if_block->prev(); 73 } else { 74 earlier_block = if_block; 75 } 76 if_inst->remove(if_block); 77 78 if (endif_block->start_ip == endif_block->end_ip) { 79 later_block = endif_block->next(); 80 } else { 81 later_block = endif_block; 82 } 83 endif_inst->remove(endif_block); 84 85 assert((earlier_block == NULL) == (later_block == NULL)); 86 if (earlier_block && earlier_block->can_combine_with(later_block)) { 87 earlier_block->combine_with(later_block); 88 89 /* If ENDIF was in its own block, then we've now deleted it and 90 * merged the two surrounding blocks, the latter of which the 91 * __next block pointer was pointing to. 92 */ 93 if (endif_block != later_block) { 94 __next = earlier_block->next(); 95 } 96 } 97 98 progress = true; 99 } else if (inst->opcode == BRW_OPCODE_ELSE && 100 prev_inst->opcode == BRW_OPCODE_IF) { 101 bblock_t *const else_block = block; 102 backend_instruction *const if_inst = prev_inst; 103 backend_instruction *const else_inst = inst; 104 105 /* Since the else-branch is becoming the new then-branch, the 106 * condition has to be inverted. 107 */ 108 if_inst->predicate_inverse = !if_inst->predicate_inverse; 109 else_inst->remove(else_block); 110 111 progress = true; 112 } 113 } 114 115 if (progress) 116 s->invalidate_live_intervals(); 117 118 return progress; 119 } 120