1 /*
2 * Copyright © 2022 Imagination Technologies Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * 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 THE
18 * 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 "rogue.h"
25 #include "util/macros.h"
26
27 #include <stdbool.h>
28
29 /**
30 * \file rogue_dce.c
31 *
32 * \brief Contains the rogue_dce pass.
33 */
34
35 /* TODO:
36 * 0) Add bools/flags to registers in rogue_info that specifies whether they can
37 * be I/O registers (i.e. populated by driver/used by driver).
38 * 1) Loop through instructions and delete ones that have their destinations
39 * unused (with exception of pixel output, shared, etc.).
40 * 2) Loop through registers and delete ones that have no uses/writes.
41 */
42
rogue_dce_alu_instr(rogue_alu_instr * alu)43 static bool rogue_dce_alu_instr(rogue_alu_instr *alu)
44 {
45 bool progress = false;
46
47 switch (alu->op) {
48 case ROGUE_ALU_OP_MOV:
49 case ROGUE_ALU_OP_MBYP:
50 if (!alu->mod && rogue_instr_dst_src_equal(&alu->dst[0], &alu->src[0])) {
51 rogue_instr_delete(&alu->instr);
52 progress = true;
53 }
54 break;
55
56 default:
57 break;
58 }
59
60 return progress;
61 }
62
rogue_dce_instrs(rogue_shader * shader)63 static bool rogue_dce_instrs(rogue_shader *shader)
64 {
65 bool progress = false;
66
67 rogue_foreach_instr_in_shader_safe (instr, shader) {
68 switch (instr->type) {
69 case ROGUE_INSTR_TYPE_ALU:
70 progress |= rogue_dce_alu_instr(rogue_instr_as_alu(instr));
71 break;
72
73 case ROGUE_INSTR_TYPE_BACKEND:
74 break;
75
76 case ROGUE_INSTR_TYPE_CTRL:
77 break;
78
79 case ROGUE_INSTR_TYPE_BITWISE:
80 break;
81
82 default:
83 unreachable("Unsupported instruction type.");
84 return false;
85 }
86 }
87
88 return progress;
89 }
90
91 /* TODO: Do this in rogue_trim instead? */
rogue_try_release_reg(rogue_reg * reg)92 static bool rogue_try_release_reg(rogue_reg *reg)
93 {
94 /* Check if the register is used or written to. */
95 if (!rogue_reg_is_unused(reg))
96 return false;
97
98 /* Check if the register is part of a regarray. */
99 if (reg->regarray)
100 return false;
101
102 /* Register is unused, delete it. */
103 rogue_reg_delete(reg);
104
105 return true;
106 }
107
rogue_dce_regs(rogue_shader * shader)108 static bool rogue_dce_regs(rogue_shader *shader)
109 {
110 bool progress = false;
111
112 /* Remove unused SSA/temp registers that aren't in any regarrays. */
113 rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_SSA) {
114 progress |= rogue_try_release_reg(reg);
115 }
116
117 rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_TEMP) {
118 progress |= rogue_try_release_reg(reg);
119 }
120
121 return progress;
122 }
123
124 PUBLIC
rogue_dce(rogue_shader * shader)125 bool rogue_dce(rogue_shader *shader)
126 {
127 if (shader->is_grouped)
128 return false;
129
130 bool progress = false;
131
132 progress |= rogue_dce_instrs(shader);
133 progress |= rogue_dce_regs(shader);
134
135 return progress;
136 }
137