17ec681f3Smrg/* 27ec681f3Smrg * Copyright (C) 2021 Valve Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 217ec681f3Smrg * SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "ir3.h" 257ec681f3Smrg 267ec681f3Smrg/* Sometimes we can get unreachable blocks from NIR. In particular this happens 277ec681f3Smrg * for blocks after an if where both sides end in a break/continue. These blocks 287ec681f3Smrg * are then reachable only via the physical CFG. This pass deletes these blocks 297ec681f3Smrg * and reroutes the physical edge past it. 307ec681f3Smrg */ 317ec681f3Smrg 327ec681f3Smrgstatic void 337ec681f3Smrgdelete_block(struct ir3 *ir, struct ir3_block *block) 347ec681f3Smrg{ 357ec681f3Smrg struct ir3_instruction *end = NULL; 367ec681f3Smrg foreach_instr (instr, &block->instr_list) { 377ec681f3Smrg if (instr->opc == OPC_END) { 387ec681f3Smrg end = instr; 397ec681f3Smrg break; 407ec681f3Smrg } 417ec681f3Smrg } 427ec681f3Smrg 437ec681f3Smrg /* The end block can be legitimately unreachable if the shader only exits via 447ec681f3Smrg * discarding. ir3_legalize will then insert a branch to the end. Keep the 457ec681f3Smrg * block around but delete all the other instructions and make the end not 467ec681f3Smrg * take any sources, so that we don't have any dangling references to other 477ec681f3Smrg * unreachable blocks. 487ec681f3Smrg */ 497ec681f3Smrg if (end) { 507ec681f3Smrg foreach_instr_safe (instr, &block->instr_list) { 517ec681f3Smrg if (instr != end) 527ec681f3Smrg list_delinit(&instr->node); 537ec681f3Smrg } 547ec681f3Smrg end->srcs_count = 0; 557ec681f3Smrg return; 567ec681f3Smrg } 577ec681f3Smrg 587ec681f3Smrg for (unsigned i = 0; i < 2; i++) { 597ec681f3Smrg struct ir3_block *succ = block->successors[i]; 607ec681f3Smrg if (!succ) 617ec681f3Smrg continue; 627ec681f3Smrg 637ec681f3Smrg unsigned pred_idx = ir3_block_get_pred_index(succ, block); 647ec681f3Smrg 657ec681f3Smrg /* If this isn't the last predecessor, we swap it with the last before 667ec681f3Smrg * removing it. 677ec681f3Smrg */ 687ec681f3Smrg bool swap_pred = pred_idx != succ->predecessors_count - 1; 697ec681f3Smrg 707ec681f3Smrg foreach_instr (phi, &succ->instr_list) { 717ec681f3Smrg if (phi->opc != OPC_META_PHI) 727ec681f3Smrg break; 737ec681f3Smrg 747ec681f3Smrg if (swap_pred) 757ec681f3Smrg phi->srcs[pred_idx] = phi->srcs[phi->srcs_count - 1]; 767ec681f3Smrg phi->srcs_count--; 777ec681f3Smrg } 787ec681f3Smrg if (swap_pred) { 797ec681f3Smrg succ->predecessors[pred_idx] = 807ec681f3Smrg succ->predecessors[succ->predecessors_count - 1]; 817ec681f3Smrg } 827ec681f3Smrg succ->predecessors_count--; 837ec681f3Smrg } 847ec681f3Smrg 857ec681f3Smrg for (unsigned i = 0; i < 2; i++) { 867ec681f3Smrg struct ir3_block *succ = block->physical_successors[i]; 877ec681f3Smrg if (!succ) 887ec681f3Smrg continue; 897ec681f3Smrg 907ec681f3Smrg ir3_block_remove_physical_predecessor(succ, block); 917ec681f3Smrg } 927ec681f3Smrg 937ec681f3Smrg if (block->physical_predecessors_count != 0) { 947ec681f3Smrg /* There should be only one physical predecessor, for the fallthrough 957ec681f3Smrg * edge. 967ec681f3Smrg */ 977ec681f3Smrg assert(block->physical_predecessors_count == 1); 987ec681f3Smrg struct ir3_block *pred = block->physical_predecessors[0]; 997ec681f3Smrg assert(block->node.next != &ir->block_list); 1007ec681f3Smrg struct ir3_block *next = LIST_ENTRY(struct ir3_block, block->node.next, node); 1017ec681f3Smrg if (pred->physical_successors[1] == block) 1027ec681f3Smrg pred->physical_successors[1] = next; 1037ec681f3Smrg else 1047ec681f3Smrg pred->physical_successors[0] = next; 1057ec681f3Smrg ir3_block_add_physical_predecessor(next, pred); 1067ec681f3Smrg } 1077ec681f3Smrg} 1087ec681f3Smrg 1097ec681f3Smrgbool 1107ec681f3Smrgir3_remove_unreachable(struct ir3 *ir) 1117ec681f3Smrg{ 1127ec681f3Smrg bool progress = false; 1137ec681f3Smrg foreach_block_safe (block, &ir->block_list) { 1147ec681f3Smrg if (block != ir3_start_block(ir) && block->predecessors_count == 0) { 1157ec681f3Smrg delete_block(ir, block); 1167ec681f3Smrg list_del(&block->node); 1177ec681f3Smrg progress = true; 1187ec681f3Smrg } 1197ec681f3Smrg } 1207ec681f3Smrg 1217ec681f3Smrg return progress; 1227ec681f3Smrg} 123