1/* 2 * Copyright (C) 2021 Valve 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include "ir3.h" 25 26/* Sometimes we can get unreachable blocks from NIR. In particular this happens 27 * for blocks after an if where both sides end in a break/continue. These blocks 28 * are then reachable only via the physical CFG. This pass deletes these blocks 29 * and reroutes the physical edge past it. 30 */ 31 32static void 33delete_block(struct ir3 *ir, struct ir3_block *block) 34{ 35 struct ir3_instruction *end = NULL; 36 foreach_instr (instr, &block->instr_list) { 37 if (instr->opc == OPC_END) { 38 end = instr; 39 break; 40 } 41 } 42 43 /* The end block can be legitimately unreachable if the shader only exits via 44 * discarding. ir3_legalize will then insert a branch to the end. Keep the 45 * block around but delete all the other instructions and make the end not 46 * take any sources, so that we don't have any dangling references to other 47 * unreachable blocks. 48 */ 49 if (end) { 50 foreach_instr_safe (instr, &block->instr_list) { 51 if (instr != end) 52 list_delinit(&instr->node); 53 } 54 end->srcs_count = 0; 55 return; 56 } 57 58 for (unsigned i = 0; i < 2; i++) { 59 struct ir3_block *succ = block->successors[i]; 60 if (!succ) 61 continue; 62 63 unsigned pred_idx = ir3_block_get_pred_index(succ, block); 64 65 /* If this isn't the last predecessor, we swap it with the last before 66 * removing it. 67 */ 68 bool swap_pred = pred_idx != succ->predecessors_count - 1; 69 70 foreach_instr (phi, &succ->instr_list) { 71 if (phi->opc != OPC_META_PHI) 72 break; 73 74 if (swap_pred) 75 phi->srcs[pred_idx] = phi->srcs[phi->srcs_count - 1]; 76 phi->srcs_count--; 77 } 78 if (swap_pred) { 79 succ->predecessors[pred_idx] = 80 succ->predecessors[succ->predecessors_count - 1]; 81 } 82 succ->predecessors_count--; 83 } 84 85 for (unsigned i = 0; i < 2; i++) { 86 struct ir3_block *succ = block->physical_successors[i]; 87 if (!succ) 88 continue; 89 90 ir3_block_remove_physical_predecessor(succ, block); 91 } 92 93 if (block->physical_predecessors_count != 0) { 94 /* There should be only one physical predecessor, for the fallthrough 95 * edge. 96 */ 97 assert(block->physical_predecessors_count == 1); 98 struct ir3_block *pred = block->physical_predecessors[0]; 99 assert(block->node.next != &ir->block_list); 100 struct ir3_block *next = list_entry(block->node.next, struct ir3_block, node); 101 if (pred->physical_successors[1] == block) 102 pred->physical_successors[1] = next; 103 else 104 pred->physical_successors[0] = next; 105 ir3_block_add_physical_predecessor(next, pred); 106 } 107} 108 109bool 110ir3_remove_unreachable(struct ir3 *ir) 111{ 112 bool progress = false; 113 foreach_block_safe (block, &ir->block_list) { 114 if (block != ir3_start_block(ir) && block->predecessors_count == 0) { 115 delete_block(ir, block); 116 list_del(&block->node); 117 progress = true; 118 } 119 } 120 121 return progress; 122} 123