1 /*
2 * Copyright 2021 Collabora, Ltd.
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "agx_builder.h"
7 #include "agx_compiler.h"
8 #include "agx_test.h"
9
10 #include <gtest/gtest.h>
11
12 static void
agx_optimize_and_dce(agx_context * ctx)13 agx_optimize_and_dce(agx_context *ctx)
14 {
15 agx_optimizer(ctx);
16 agx_dce(ctx, true);
17 }
18
19 #define CASE(instr, expected, size, returns) \
20 INSTRUCTION_CASE( \
21 { \
22 UNUSED agx_index out = agx_temp(b->shader, AGX_SIZE_##size); \
23 instr; \
24 if (returns) \
25 agx_unit_test(b, out); \
26 }, \
27 { \
28 UNUSED agx_index out = agx_temp(b->shader, AGX_SIZE_##size); \
29 expected; \
30 if (returns) \
31 agx_unit_test(b, out); \
32 }, \
33 agx_optimize_and_dce)
34
35 #define NEGCASE(instr, size) CASE(instr, instr, size, true)
36
37 #define CASE16(instr, expected) CASE(instr, expected, 16, true)
38 #define CASE32(instr, expected) CASE(instr, expected, 32, true)
39
40 #define CASE_NO_RETURN(instr, expected) \
41 CASE(instr, expected, 32 /* irrelevant */, false)
42
43 #define NEGCASE16(instr) NEGCASE(instr, 16)
44 #define NEGCASE32(instr) NEGCASE(instr, 32)
45
46 static inline agx_index
agx_fmov(agx_builder * b,agx_index s0)47 agx_fmov(agx_builder *b, agx_index s0)
48 {
49 agx_index tmp = agx_temp(b->shader, s0.size);
50 agx_fmov_to(b, tmp, s0);
51 return tmp;
52 }
53
54 class Optimizer : public testing::Test {
55 protected:
Optimizer()56 Optimizer()
57 {
58 mem_ctx = ralloc_context(NULL);
59
60 wx = agx_register(0, AGX_SIZE_32);
61 wy = agx_register(2, AGX_SIZE_32);
62 wz = agx_register(4, AGX_SIZE_32);
63
64 hx = agx_register(0, AGX_SIZE_16);
65 hy = agx_register(1, AGX_SIZE_16);
66 hz = agx_register(2, AGX_SIZE_16);
67 }
68
~Optimizer()69 ~Optimizer()
70 {
71 ralloc_free(mem_ctx);
72 }
73
74 void *mem_ctx;
75
76 agx_index wx, wy, wz, hx, hy, hz;
77 };
78
TEST_F(Optimizer,FloatCopyprop)79 TEST_F(Optimizer, FloatCopyprop)
80 {
81 CASE32(agx_fadd_to(b, out, agx_abs(agx_fmov(b, wx)), wy),
82 agx_fadd_to(b, out, agx_abs(wx), wy));
83
84 CASE32(agx_fadd_to(b, out, agx_neg(agx_fmov(b, wx)), wy),
85 agx_fadd_to(b, out, agx_neg(wx), wy));
86 }
87
TEST_F(Optimizer,FloatConversion)88 TEST_F(Optimizer, FloatConversion)
89 {
90 CASE32(
91 {
92 agx_index cvt = agx_temp(b->shader, AGX_SIZE_32);
93 agx_fmov_to(b, cvt, hx);
94 agx_fadd_to(b, out, cvt, wy);
95 },
96 { agx_fadd_to(b, out, hx, wy); });
97
98 CASE16(
99 {
100 agx_index sum = agx_temp(b->shader, AGX_SIZE_32);
101 agx_fadd_to(b, sum, wx, wy);
102 agx_fmov_to(b, out, sum);
103 },
104 { agx_fadd_to(b, out, wx, wy); });
105 }
106
TEST_F(Optimizer,FusedFABSNEG)107 TEST_F(Optimizer, FusedFABSNEG)
108 {
109 CASE32(agx_fadd_to(b, out, agx_fmov(b, agx_abs(wx)), wy),
110 agx_fadd_to(b, out, agx_abs(wx), wy));
111
112 CASE32(agx_fmul_to(b, out, wx, agx_fmov(b, agx_neg(agx_abs(wx)))),
113 agx_fmul_to(b, out, wx, agx_neg(agx_abs(wx))));
114 }
115
TEST_F(Optimizer,FusedFabsAbsorb)116 TEST_F(Optimizer, FusedFabsAbsorb)
117 {
118 CASE32(agx_fadd_to(b, out, agx_abs(agx_fmov(b, agx_abs(wx))), wy),
119 agx_fadd_to(b, out, agx_abs(wx), wy));
120 }
121
TEST_F(Optimizer,FusedFnegCancel)122 TEST_F(Optimizer, FusedFnegCancel)
123 {
124 CASE32(agx_fmul_to(b, out, wx, agx_neg(agx_fmov(b, agx_neg(wx)))),
125 agx_fmul_to(b, out, wx, wx));
126
127 CASE32(agx_fmul_to(b, out, wx, agx_neg(agx_fmov(b, agx_neg(agx_abs(wx))))),
128 agx_fmul_to(b, out, wx, agx_abs(wx)));
129 }
130
TEST_F(Optimizer,FusedNot)131 TEST_F(Optimizer, FusedNot)
132 {
133 CASE32(agx_not_to(b, out, agx_and(b, wx, wx)), agx_nand_to(b, out, wx, wx));
134
135 CASE32(agx_not_to(b, out, agx_or(b, wx, wx)), agx_nor_to(b, out, wx, wx));
136
137 CASE32(agx_not_to(b, out, agx_xor(b, wx, wx)), agx_xnor_to(b, out, wx, wx));
138
139 CASE32(agx_xor_to(b, out, agx_not(b, wx), agx_not(b, wx)),
140 agx_xor_to(b, out, wx, wx));
141
142 CASE32(agx_xor_to(b, out, agx_not(b, wx), wx), agx_xnor_to(b, out, wx, wx));
143
144 CASE32(agx_xor_to(b, out, wx, agx_not(b, wx)), agx_xnor_to(b, out, wx, wx));
145
146 CASE32(agx_nand_to(b, out, agx_not(b, wx), agx_not(b, wx)),
147 agx_or_to(b, out, wx, wx));
148
149 CASE32(agx_andn1_to(b, out, agx_not(b, wx), wx), agx_and_to(b, out, wx, wx));
150
151 CASE32(agx_andn1_to(b, out, wx, agx_not(b, wx)), agx_nor_to(b, out, wx, wx));
152
153 CASE32(agx_andn2_to(b, out, agx_not(b, wx), wx), agx_nor_to(b, out, wx, wx));
154
155 CASE32(agx_andn2_to(b, out, wx, agx_not(b, wx)), agx_and_to(b, out, wx, wx));
156
157 CASE32(agx_xor_to(b, out, agx_not(b, wx), agx_uniform(8, AGX_SIZE_32)),
158 agx_xnor_to(b, out, wx, agx_uniform(8, AGX_SIZE_32)));
159
160 CASE32(agx_or_to(b, out, agx_immediate(123), agx_not(b, wx)),
161 agx_orn2_to(b, out, agx_immediate(123), wx));
162
163 CASE32(agx_xor_to(b, out, wx, agx_not(b, wy)), agx_xnor_to(b, out, wx, wy));
164
165 CASE32(agx_xor_to(b, out, wy, agx_not(b, wx)), agx_xnor_to(b, out, wy, wx));
166
167 CASE32(agx_and_to(b, out, agx_not(b, wx), wy), agx_andn1_to(b, out, wx, wy));
168
169 CASE32(agx_or_to(b, out, wx, agx_not(b, wy)), agx_orn2_to(b, out, wx, wy));
170 }
171
TEST_F(Optimizer,FmulFsatF2F16)172 TEST_F(Optimizer, FmulFsatF2F16)
173 {
174 CASE16(
175 {
176 agx_index tmp = agx_temp(b->shader, AGX_SIZE_32);
177 agx_fmov_to(b, tmp, agx_fmul(b, wx, wy))->saturate = true;
178 agx_fmov_to(b, out, tmp);
179 },
180 { agx_fmul_to(b, out, wx, wy)->saturate = true; });
181 }
182
TEST_F(Optimizer,Copyprop)183 TEST_F(Optimizer, Copyprop)
184 {
185 CASE32(agx_fmul_to(b, out, wx, agx_mov(b, wy)), agx_fmul_to(b, out, wx, wy));
186 CASE32(agx_fmul_to(b, out, agx_mov(b, wx), agx_mov(b, wy)),
187 agx_fmul_to(b, out, wx, wy));
188 }
189
TEST_F(Optimizer,InlineHazards)190 TEST_F(Optimizer, InlineHazards)
191 {
192 NEGCASE32({
193 agx_instr *I = agx_collect_to(b, out, 4);
194 I->src[0] = agx_mov_imm(b, AGX_SIZE_32, 0);
195 I->src[1] = wy;
196 I->src[2] = wz;
197 I->src[3] = wz;
198 });
199 }
200
TEST_F(Optimizer,CopypropRespectsAbsNeg)201 TEST_F(Optimizer, CopypropRespectsAbsNeg)
202 {
203 CASE32(agx_fadd_to(b, out, agx_abs(agx_mov(b, wx)), wy),
204 agx_fadd_to(b, out, agx_abs(wx), wy));
205
206 CASE32(agx_fadd_to(b, out, agx_neg(agx_mov(b, wx)), wy),
207 agx_fadd_to(b, out, agx_neg(wx), wy));
208
209 CASE32(agx_fadd_to(b, out, agx_neg(agx_abs(agx_mov(b, wx))), wy),
210 agx_fadd_to(b, out, agx_neg(agx_abs(wx)), wy));
211 }
212
TEST_F(Optimizer,IntCopyprop)213 TEST_F(Optimizer, IntCopyprop)
214 {
215 CASE32(agx_xor_to(b, out, agx_mov(b, wx), wy), agx_xor_to(b, out, wx, wy));
216 }
217
TEST_F(Optimizer,CopypropSplitMovedUniform64)218 TEST_F(Optimizer, CopypropSplitMovedUniform64)
219 {
220 CASE32(
221 {
222 /* emit_load_preamble puts in the move, so we do too */
223 agx_index mov = agx_mov(b, agx_uniform(40, AGX_SIZE_64));
224 agx_instr *spl = agx_split(b, 2, mov);
225 spl->dest[0] = agx_temp(b->shader, AGX_SIZE_32);
226 spl->dest[1] = agx_temp(b->shader, AGX_SIZE_32);
227 agx_xor_to(b, out, spl->dest[0], spl->dest[1]);
228 },
229 {
230 agx_xor_to(b, out, agx_uniform(40, AGX_SIZE_32),
231 agx_uniform(42, AGX_SIZE_32));
232 });
233 }
234
TEST_F(Optimizer,IntCopypropDoesntConvert)235 TEST_F(Optimizer, IntCopypropDoesntConvert)
236 {
237 NEGCASE32({
238 agx_index cvt = agx_temp(b->shader, AGX_SIZE_32);
239 agx_mov_to(b, cvt, hx);
240 agx_xor_to(b, out, cvt, wy);
241 });
242 }
243
TEST_F(Optimizer,SkipPreloads)244 TEST_F(Optimizer, SkipPreloads)
245 {
246 NEGCASE32({
247 agx_index preload = agx_preload(b, agx_register(0, AGX_SIZE_32));
248 agx_xor_to(b, out, preload, wy);
249 });
250 }
251
TEST_F(Optimizer,NoConversionsOn16BitALU)252 TEST_F(Optimizer, NoConversionsOn16BitALU)
253 {
254 NEGCASE16({
255 agx_index cvt = agx_temp(b->shader, AGX_SIZE_16);
256 agx_fmov_to(b, cvt, wx);
257 agx_fadd_to(b, out, cvt, hy);
258 });
259
260 NEGCASE32(agx_fmov_to(b, out, agx_fadd(b, hx, hy)));
261 }
262
TEST_F(Optimizer,BallotCondition)263 TEST_F(Optimizer, BallotCondition)
264 {
265 CASE32(agx_ballot_to(b, out, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, true)),
266 agx_icmp_ballot_to(b, out, wx, wy, AGX_ICOND_UEQ, true));
267
268 CASE32(agx_ballot_to(b, out, agx_fcmp(b, wx, wy, AGX_FCOND_GE, false)),
269 agx_fcmp_ballot_to(b, out, wx, wy, AGX_FCOND_GE, false));
270
271 CASE32(agx_quad_ballot_to(b, out, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, true)),
272 agx_icmp_quad_ballot_to(b, out, wx, wy, AGX_ICOND_UEQ, true));
273
274 CASE32(agx_quad_ballot_to(b, out, agx_fcmp(b, wx, wy, AGX_FCOND_GT, false)),
275 agx_fcmp_quad_ballot_to(b, out, wx, wy, AGX_FCOND_GT, false));
276 }
277
TEST_F(Optimizer,BallotMultipleUses)278 TEST_F(Optimizer, BallotMultipleUses)
279 {
280 CASE32(
281 {
282 agx_index cmp = agx_fcmp(b, wx, wy, AGX_FCOND_GT, false);
283 agx_index ballot = agx_quad_ballot(b, cmp);
284 agx_fadd_to(b, out, cmp, ballot);
285 },
286 {
287 agx_index cmp = agx_fcmp(b, wx, wy, AGX_FCOND_GT, false);
288 agx_index ballot =
289 agx_fcmp_quad_ballot(b, wx, wy, AGX_FCOND_GT, false);
290 agx_fadd_to(b, out, cmp, ballot);
291 });
292 }
293
TEST_F(Optimizer,IfCondition)294 TEST_F(Optimizer, IfCondition)
295 {
296 CASE_NO_RETURN(agx_if_icmp(b, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, true),
297 agx_zero(), 1, AGX_ICOND_UEQ, true, NULL),
298 agx_if_icmp(b, wx, wy, 1, AGX_ICOND_UEQ, true, NULL));
299
300 CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, wx, wy, AGX_FCOND_EQ, true),
301 agx_zero(), 1, AGX_ICOND_UEQ, true, NULL),
302 agx_if_fcmp(b, wx, wy, 1, AGX_FCOND_EQ, true, NULL));
303
304 CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, hx, hy, AGX_FCOND_LT, false),
305 agx_zero(), 1, AGX_ICOND_UEQ, true, NULL),
306 agx_if_fcmp(b, hx, hy, 1, AGX_FCOND_LT, false, NULL));
307 }
308
TEST_F(Optimizer,SelectCondition)309 TEST_F(Optimizer, SelectCondition)
310 {
311 CASE32(agx_icmpsel_to(b, out, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, false),
312 agx_zero(), wz, wx, AGX_ICOND_UEQ),
313 agx_icmpsel_to(b, out, wx, wy, wx, wz, AGX_ICOND_UEQ));
314
315 CASE32(agx_icmpsel_to(b, out, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, true),
316 agx_zero(), wz, wx, AGX_ICOND_UEQ),
317 agx_icmpsel_to(b, out, wx, wy, wz, wx, AGX_ICOND_UEQ));
318
319 CASE32(agx_icmpsel_to(b, out, agx_fcmp(b, wx, wy, AGX_FCOND_EQ, false),
320 agx_zero(), wz, wx, AGX_ICOND_UEQ),
321 agx_fcmpsel_to(b, out, wx, wy, wx, wz, AGX_FCOND_EQ));
322
323 CASE32(agx_icmpsel_to(b, out, agx_fcmp(b, wx, wy, AGX_FCOND_LT, true),
324 agx_zero(), wz, wx, AGX_ICOND_UEQ),
325 agx_fcmpsel_to(b, out, wx, wy, wz, wx, AGX_FCOND_LT));
326 }
327