• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 static void
delete_block(struct ir3 * ir,struct ir3_block * block)33 delete_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(struct ir3_block, block->node.next, 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 
109 bool
ir3_remove_unreachable(struct ir3 * ir)110 ir3_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