xref: /aosp_15_r20/external/mesa3d/src/freedreno/ir3/ir3_remove_unreachable.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2021 Valve Corporation
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "ir3.h"
7 
8 /* Sometimes we can get unreachable blocks from NIR. In particular this happens
9  * for blocks after an if where both sides end in a break/continue. These blocks
10  * are then reachable only via the physical CFG. This pass deletes these blocks
11  * and reroutes the physical edge past it.
12  */
13 
14 static void
delete_block(struct ir3 * ir,struct ir3_block * block)15 delete_block(struct ir3 *ir, struct ir3_block *block)
16 {
17    struct ir3_instruction *end = NULL;
18    foreach_instr (instr, &block->instr_list) {
19       if (instr->opc == OPC_END) {
20          end = instr;
21          break;
22       }
23    }
24 
25    /* The end block can be legitimately unreachable if the shader only exits via
26     * discarding. ir3_legalize will then insert a branch to the end. Keep the
27     * block around but delete all the other instructions and make the end not
28     * take any sources, so that we don't have any dangling references to other
29     * unreachable blocks.
30     */
31    if (end) {
32       foreach_instr_safe (instr, &block->instr_list) {
33          if (instr != end)
34             list_delinit(&instr->node);
35       }
36       end->srcs_count = 0;
37       return;
38    }
39 
40    for (unsigned i = 0; i < 2; i++) {
41       struct ir3_block *succ = block->successors[i];
42       if (!succ)
43          continue;
44 
45       unsigned pred_idx = ir3_block_get_pred_index(succ, block);
46 
47       /* If this isn't the last predecessor, we swap it with the last before
48        * removing it.
49        */
50       bool swap_pred = pred_idx != succ->predecessors_count - 1;
51 
52       foreach_instr (phi, &succ->instr_list) {
53          if (phi->opc != OPC_META_PHI)
54             break;
55 
56          if (swap_pred)
57             phi->srcs[pred_idx] = phi->srcs[phi->srcs_count - 1];
58          phi->srcs_count--;
59       }
60       if (swap_pred) {
61          succ->predecessors[pred_idx] =
62             succ->predecessors[succ->predecessors_count - 1];
63       }
64       succ->predecessors_count--;
65    }
66 }
67 
68 bool
ir3_remove_unreachable(struct ir3 * ir)69 ir3_remove_unreachable(struct ir3 *ir)
70 {
71    bool progress = false;
72    foreach_block_safe (block, &ir->block_list) {
73       if (block != ir3_start_block(ir) && block->predecessors_count == 0) {
74          delete_block(ir, block);
75          list_del(&block->node);
76          progress = true;
77       }
78    }
79 
80    return progress;
81 }
82