vc4: Add missing progress note in opt_algebraic.
[mesa.git] / src / gallium / drivers / vc4 / vc4_opt_algebraic.c
1 /*
2 * Copyright © 2014 Broadcom
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 /**
25 * @file vc4_opt_algebraic.c
26 *
27 * This is the optimization pass for miscellaneous changes to instructions
28 * where we can simplify the operation by some knowledge about the specific
29 * operations.
30 *
31 * Mostly this will be a matter of turning things into MOVs so that they can
32 * later be copy-propagated out.
33 */
34
35 #include "vc4_qir.h"
36 #include "util/u_math.h"
37
38 static bool debug;
39
40 static void
41 dump_from(struct vc4_compile *c, struct qinst *inst)
42 {
43 if (!debug)
44 return;
45
46 fprintf(stderr, "optimizing: ");
47 qir_dump_inst(c, inst);
48 fprintf(stderr, "\n");
49 }
50
51 static void
52 dump_to(struct vc4_compile *c, struct qinst *inst)
53 {
54 if (!debug)
55 return;
56
57 fprintf(stderr, "to: ");
58 qir_dump_inst(c, inst);
59 fprintf(stderr, "\n");
60 }
61
62 static bool
63 is_constant_value(struct vc4_compile *c, struct qreg reg,
64 uint32_t val)
65 {
66 if (reg.file == QFILE_UNIF &&
67 !reg.pack &&
68 c->uniform_contents[reg.index] == QUNIFORM_CONSTANT &&
69 c->uniform_data[reg.index] == val) {
70 return true;
71 }
72
73 if (reg.file == QFILE_SMALL_IMM && reg.index == val)
74 return true;
75
76 return false;
77 }
78
79 static bool
80 is_zero(struct vc4_compile *c, struct qreg reg)
81 {
82 reg = qir_follow_movs(c, reg);
83 return is_constant_value(c, reg, 0);
84 }
85
86 static bool
87 is_1f(struct vc4_compile *c, struct qreg reg)
88 {
89 reg = qir_follow_movs(c, reg);
90 return is_constant_value(c, reg, fui(1.0));
91 }
92
93 static void
94 replace_with_mov(struct vc4_compile *c, struct qinst *inst, struct qreg arg)
95 {
96 dump_from(c, inst);
97 inst->op = QOP_MOV;
98 inst->src[0] = arg;
99 inst->src[1] = c->undef;
100 dump_to(c, inst);
101 }
102
103 static bool
104 replace_x_0_with_x(struct vc4_compile *c,
105 struct qinst *inst,
106 int arg)
107 {
108 if (!is_zero(c, inst->src[arg]))
109 return false;
110 replace_with_mov(c, inst, inst->src[1 - arg]);
111 return true;
112 }
113
114 static bool
115 replace_x_0_with_0(struct vc4_compile *c,
116 struct qinst *inst,
117 int arg)
118 {
119 if (!is_zero(c, inst->src[arg]))
120 return false;
121 replace_with_mov(c, inst, inst->src[arg]);
122 return true;
123 }
124
125 static bool
126 fmul_replace_one(struct vc4_compile *c,
127 struct qinst *inst,
128 int arg)
129 {
130 if (!is_1f(c, inst->src[arg]))
131 return false;
132 replace_with_mov(c, inst, inst->src[1 - arg]);
133 return true;
134 }
135
136 bool
137 qir_opt_algebraic(struct vc4_compile *c)
138 {
139 bool progress = false;
140
141 list_for_each_entry(struct qinst, inst, &c->instructions, link) {
142 switch (inst->op) {
143 case QOP_SEL_X_Y_ZS:
144 case QOP_SEL_X_Y_ZC:
145 case QOP_SEL_X_Y_NS:
146 case QOP_SEL_X_Y_NC:
147 case QOP_SEL_X_Y_CS:
148 case QOP_SEL_X_Y_CC:
149 if (is_zero(c, inst->src[1])) {
150 /* Replace references to a 0 uniform value
151 * with the SEL_X_0 equivalent.
152 */
153 dump_from(c, inst);
154 inst->op -= (QOP_SEL_X_Y_ZS - QOP_SEL_X_0_ZS);
155 inst->src[1] = c->undef;
156 progress = true;
157 dump_to(c, inst);
158 break;
159 }
160
161 if (is_zero(c, inst->src[0])) {
162 /* Replace references to a 0 uniform value
163 * with the SEL_X_0 equivalent, flipping the
164 * condition being evaluated since the operand
165 * order is flipped.
166 */
167 dump_from(c, inst);
168 inst->op -= QOP_SEL_X_Y_ZS;
169 inst->op ^= 1;
170 inst->op += QOP_SEL_X_0_ZS;
171 inst->src[0] = inst->src[1];
172 inst->src[1] = c->undef;
173 progress = true;
174 dump_to(c, inst);
175 break;
176 }
177
178 break;
179
180 case QOP_FSUB:
181 case QOP_SUB:
182 if (is_zero(c, inst->src[1])) {
183 replace_with_mov(c, inst, inst->src[0]);
184 progress = true;
185 }
186 break;
187
188 case QOP_ADD:
189 if (replace_x_0_with_x(c, inst, 0) ||
190 replace_x_0_with_x(c, inst, 1)) {
191 progress = true;
192 break;
193 }
194 break;
195
196 case QOP_FADD:
197 if (replace_x_0_with_x(c, inst, 0) ||
198 replace_x_0_with_x(c, inst, 1)) {
199 progress = true;
200 break;
201 }
202
203 /* FADD(a, FSUB(0, b)) -> FSUB(a, b) */
204 if (inst->src[1].file == QFILE_TEMP &&
205 c->defs[inst->src[1].index] &&
206 c->defs[inst->src[1].index]->op == QOP_FSUB) {
207 struct qinst *fsub = c->defs[inst->src[1].index];
208 if (is_zero(c, fsub->src[0])) {
209 dump_from(c, inst);
210 inst->op = QOP_FSUB;
211 inst->src[1] = fsub->src[1];
212 progress = true;
213 dump_to(c, inst);
214 break;
215 }
216 }
217
218 /* FADD(FSUB(0, b), a) -> FSUB(a, b) */
219 if (inst->src[0].file == QFILE_TEMP &&
220 c->defs[inst->src[0].index] &&
221 c->defs[inst->src[0].index]->op == QOP_FSUB) {
222 struct qinst *fsub = c->defs[inst->src[0].index];
223 if (is_zero(c, fsub->src[0])) {
224 dump_from(c, inst);
225 inst->op = QOP_FSUB;
226 inst->src[0] = inst->src[1];
227 inst->src[1] = fsub->src[1];
228 dump_to(c, inst);
229 progress = true;
230 break;
231 }
232 }
233 break;
234
235 case QOP_FMUL:
236 if (!inst->dst.pack &&
237 (replace_x_0_with_0(c, inst, 0) ||
238 replace_x_0_with_0(c, inst, 1) ||
239 fmul_replace_one(c, inst, 0) ||
240 fmul_replace_one(c, inst, 1))) {
241 progress = true;
242 break;
243 }
244 break;
245
246 case QOP_MUL24:
247 if (!inst->dst.pack &&
248 (replace_x_0_with_0(c, inst, 0) ||
249 replace_x_0_with_0(c, inst, 1))) {
250 progress = true;
251 break;
252 }
253 break;
254
255 case QOP_AND:
256 if (replace_x_0_with_0(c, inst, 0) ||
257 replace_x_0_with_0(c, inst, 1)) {
258 progress = true;
259 break;
260 }
261
262 if (is_constant_value(c, inst->src[0], ~0)) {
263 replace_with_mov(c, inst, inst->src[1]);
264 progress = true;
265 break;
266 }
267 if (is_constant_value(c, inst->src[1], ~0)) {
268 replace_with_mov(c, inst, inst->src[0]);
269 progress = true;
270 break;
271 }
272 break;
273
274 case QOP_OR:
275 if (replace_x_0_with_x(c, inst, 0) ||
276 replace_x_0_with_x(c, inst, 1)) {
277 progress = true;
278 break;
279 }
280 break;
281
282 case QOP_RCP:
283 if (is_1f(c, inst->src[0])) {
284 replace_with_mov(c, inst, inst->src[0]);
285 progress = true;
286 break;
287 }
288 break;
289
290 default:
291 break;
292 }
293 }
294
295 return progress;
296 }