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 #define CASE(copies, expected) \
13 do { \
14 agx_builder *A = agx_test_builder(mem_ctx); \
15 agx_builder *B = agx_test_builder(mem_ctx); \
16 \
17 agx_emit_parallel_copies(A, copies, ARRAY_SIZE(copies)); \
18 \
19 { \
20 agx_builder *b = B; \
21 expected; \
22 } \
23 \
24 ASSERT_SHADER_EQUAL(A->shader, B->shader); \
25 } while (0)
26
27 class LowerParallelCopy : public testing::Test {
28 protected:
LowerParallelCopy()29 LowerParallelCopy()
30 {
31 mem_ctx = ralloc_context(NULL);
32 }
33
~LowerParallelCopy()34 ~LowerParallelCopy()
35 {
36 ralloc_free(mem_ctx);
37 }
38
39 void *mem_ctx;
40 };
41
TEST_F(LowerParallelCopy,UnrelatedCopies)42 TEST_F(LowerParallelCopy, UnrelatedCopies)
43 {
44 struct agx_copy test_1[] = {
45 {.dest = 0, .src = agx_register(2, AGX_SIZE_32)},
46 {.dest = 4, .src = agx_register(6, AGX_SIZE_32)},
47 };
48
49 CASE(test_1, {
50 agx_mov_to(b, agx_register(0, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
51 agx_mov_to(b, agx_register(4, AGX_SIZE_32), agx_register(6, AGX_SIZE_32));
52 });
53
54 struct agx_copy test_2[] = {
55 {.dest = 0, .src = agx_register(1, AGX_SIZE_16)},
56 {.dest = 4, .src = agx_register(5, AGX_SIZE_16)},
57 };
58
59 CASE(test_2, {
60 agx_mov_to(b, agx_register(0, AGX_SIZE_16), agx_register(1, AGX_SIZE_16));
61 agx_mov_to(b, agx_register(4, AGX_SIZE_16), agx_register(5, AGX_SIZE_16));
62 });
63 }
64
TEST_F(LowerParallelCopy,RelatedSource)65 TEST_F(LowerParallelCopy, RelatedSource)
66 {
67 struct agx_copy test_1[] = {
68 {.dest = 0, .src = agx_register(2, AGX_SIZE_32)},
69 {.dest = 4, .src = agx_register(2, AGX_SIZE_32)},
70 };
71
72 CASE(test_1, {
73 agx_mov_to(b, agx_register(0, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
74 agx_mov_to(b, agx_register(4, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
75 });
76
77 struct agx_copy test_2[] = {
78 {.dest = 0, .src = agx_register(1, AGX_SIZE_16)},
79 {.dest = 4, .src = agx_register(1, AGX_SIZE_16)},
80 };
81
82 CASE(test_2, {
83 agx_mov_to(b, agx_register(0, AGX_SIZE_16), agx_register(1, AGX_SIZE_16));
84 agx_mov_to(b, agx_register(4, AGX_SIZE_16), agx_register(1, AGX_SIZE_16));
85 });
86 }
87
TEST_F(LowerParallelCopy,DependentCopies)88 TEST_F(LowerParallelCopy, DependentCopies)
89 {
90 struct agx_copy test_1[] = {
91 {.dest = 0, .src = agx_register(2, AGX_SIZE_32)},
92 {.dest = 4, .src = agx_register(0, AGX_SIZE_32)},
93 };
94
95 CASE(test_1, {
96 agx_mov_to(b, agx_register(4, AGX_SIZE_32), agx_register(0, AGX_SIZE_32));
97 agx_mov_to(b, agx_register(0, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
98 });
99
100 struct agx_copy test_2[] = {
101 {.dest = 0, .src = agx_register(1, AGX_SIZE_16)},
102 {.dest = 4, .src = agx_register(0, AGX_SIZE_16)},
103 };
104
105 CASE(test_2, {
106 agx_mov_to(b, agx_register(4, AGX_SIZE_16), agx_register(0, AGX_SIZE_16));
107 agx_mov_to(b, agx_register(0, AGX_SIZE_16), agx_register(1, AGX_SIZE_16));
108 });
109 }
110
TEST_F(LowerParallelCopy,ManyDependentCopies)111 TEST_F(LowerParallelCopy, ManyDependentCopies)
112 {
113 struct agx_copy test_1[] = {
114 {.dest = 0, .src = agx_register(2, AGX_SIZE_32)},
115 {.dest = 4, .src = agx_register(0, AGX_SIZE_32)},
116 {.dest = 8, .src = agx_register(6, AGX_SIZE_32)},
117 {.dest = 6, .src = agx_register(4, AGX_SIZE_32)},
118 };
119
120 CASE(test_1, {
121 agx_mov_to(b, agx_register(8, AGX_SIZE_32), agx_register(6, AGX_SIZE_32));
122 agx_mov_to(b, agx_register(6, AGX_SIZE_32), agx_register(4, AGX_SIZE_32));
123 agx_mov_to(b, agx_register(4, AGX_SIZE_32), agx_register(0, AGX_SIZE_32));
124 agx_mov_to(b, agx_register(0, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
125 });
126
127 struct agx_copy test_2[] = {
128 {.dest = 0, .src = agx_register(1, AGX_SIZE_16)},
129 {.dest = 2, .src = agx_register(0, AGX_SIZE_16)},
130 {.dest = 4, .src = agx_register(3, AGX_SIZE_16)},
131 {.dest = 3, .src = agx_register(2, AGX_SIZE_16)},
132 };
133
134 CASE(test_2, {
135 agx_mov_to(b, agx_register(4, AGX_SIZE_16), agx_register(3, AGX_SIZE_16));
136 agx_mov_to(b, agx_register(3, AGX_SIZE_16), agx_register(2, AGX_SIZE_16));
137 agx_mov_to(b, agx_register(2, AGX_SIZE_16), agx_register(0, AGX_SIZE_16));
138 agx_mov_to(b, agx_register(0, AGX_SIZE_16), agx_register(1, AGX_SIZE_16));
139 });
140 }
141
TEST_F(LowerParallelCopy,Swap)142 TEST_F(LowerParallelCopy, Swap)
143 {
144 struct agx_copy test_1[] = {
145 {.dest = 0, .src = agx_register(2, AGX_SIZE_32)},
146 {.dest = 2, .src = agx_register(0, AGX_SIZE_32)},
147 };
148
149 CASE(test_1, {
150 agx_swap(b, agx_register(0, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
151 });
152
153 struct agx_copy test_2[] = {
154 {.dest = 0, .src = agx_register(1, AGX_SIZE_16)},
155 {.dest = 1, .src = agx_register(0, AGX_SIZE_16)},
156 };
157
158 CASE(test_2, {
159 agx_swap(b, agx_register(0, AGX_SIZE_16), agx_register(1, AGX_SIZE_16));
160 });
161 }
162
TEST_F(LowerParallelCopy,Cycle3)163 TEST_F(LowerParallelCopy, Cycle3)
164 {
165 struct agx_copy test[] = {
166 {.dest = 0, .src = agx_register(1, AGX_SIZE_16)},
167 {.dest = 1, .src = agx_register(2, AGX_SIZE_16)},
168 {.dest = 2, .src = agx_register(0, AGX_SIZE_16)},
169 };
170
171 CASE(test, {
172 agx_swap(b, agx_register(0, AGX_SIZE_16), agx_register(1, AGX_SIZE_16));
173 agx_swap(b, agx_register(1, AGX_SIZE_16), agx_register(2, AGX_SIZE_16));
174 });
175 }
176
TEST_F(LowerParallelCopy,Immediate64)177 TEST_F(LowerParallelCopy, Immediate64)
178 {
179 agx_index imm = agx_immediate(10);
180 imm.size = AGX_SIZE_64;
181
182 struct agx_copy test_1[] = {
183 {.dest = 4, .src = imm},
184 };
185
186 CASE(test_1, {
187 agx_mov_imm_to(b, agx_register(4, AGX_SIZE_32), 10);
188 agx_mov_imm_to(b, agx_register(6, AGX_SIZE_32), 0);
189 });
190 }
191
192 /* Test case from Hack et al */
TEST_F(LowerParallelCopy,TwoSwaps)193 TEST_F(LowerParallelCopy, TwoSwaps)
194 {
195 struct agx_copy test[] = {
196 {.dest = 4, .src = agx_register(2, AGX_SIZE_32)},
197 {.dest = 6, .src = agx_register(4, AGX_SIZE_32)},
198 {.dest = 2, .src = agx_register(6, AGX_SIZE_32)},
199 {.dest = 8, .src = agx_register(8, AGX_SIZE_32)},
200 };
201
202 CASE(test, {
203 agx_swap(b, agx_register(4, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
204 agx_swap(b, agx_register(6, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
205 });
206 }
207
TEST_F(LowerParallelCopy,VectorizeAlignedHalfRegs)208 TEST_F(LowerParallelCopy, VectorizeAlignedHalfRegs)
209 {
210 struct agx_copy test[] = {
211 {.dest = 0, .src = agx_register(10, AGX_SIZE_16)},
212 {.dest = 1, .src = agx_register(11, AGX_SIZE_16)},
213 {.dest = 2, .src = agx_uniform(8, AGX_SIZE_16)},
214 {.dest = 3, .src = agx_uniform(9, AGX_SIZE_16)},
215 };
216
217 CASE(test, {
218 agx_mov_to(b, agx_register(0, AGX_SIZE_32),
219 agx_register(10, AGX_SIZE_32));
220 agx_mov_to(b, agx_register(2, AGX_SIZE_32), agx_uniform(8, AGX_SIZE_32));
221 });
222 }
223
TEST_F(LowerParallelCopy,StackCopies)224 TEST_F(LowerParallelCopy, StackCopies)
225 {
226 struct agx_copy test[] = {
227 {.dest = 21, .dest_mem = true, .src = agx_register(20, AGX_SIZE_16)},
228 {.dest = 22, .dest_mem = true, .src = agx_register(22, AGX_SIZE_32)},
229 {.dest = 0, .src = agx_memory_register(10, AGX_SIZE_16)},
230 {.dest = 1, .src = agx_memory_register(11, AGX_SIZE_16)},
231 {.dest = 0, .dest_mem = true, .src = agx_memory_register(12, AGX_SIZE_16)},
232 {.dest = 1, .dest_mem = true, .src = agx_memory_register(13, AGX_SIZE_16)},
233 {.dest = 2,
234 .dest_mem = true,
235 .src = agx_memory_register(804, AGX_SIZE_32)},
236 {.dest = 804,
237 .dest_mem = true,
238 .src = agx_memory_register(2, AGX_SIZE_32)},
239 {.dest = 807,
240 .dest_mem = true,
241 .src = agx_memory_register(808, AGX_SIZE_16)},
242 {.dest = 808,
243 .dest_mem = true,
244 .src = agx_memory_register(807, AGX_SIZE_16)},
245 };
246
247 CASE(test, {
248 /* Vectorized fill */
249 agx_mov_to(b, agx_register(0, AGX_SIZE_32),
250 agx_memory_register(10, AGX_SIZE_32));
251
252 /* Regular spills */
253 agx_mov_to(b, agx_memory_register(21, AGX_SIZE_16),
254 agx_register(20, AGX_SIZE_16));
255 agx_mov_to(b, agx_memory_register(22, AGX_SIZE_32),
256 agx_register(22, AGX_SIZE_32));
257
258 /* Vectorized stack->stack copy */
259 agx_mov_to(b, agx_register(2, AGX_SIZE_32),
260 agx_memory_register(12, AGX_SIZE_32));
261
262 agx_mov_to(b, agx_memory_register(0, AGX_SIZE_32),
263 agx_register(2, AGX_SIZE_32));
264
265 /* Stack swap: 32-bit */
266 agx_index temp1 = agx_register(4, AGX_SIZE_32);
267 agx_index temp2 = agx_register(6, AGX_SIZE_32);
268 agx_index spilled_gpr_vec2 = agx_register(0, AGX_SIZE_32);
269 spilled_gpr_vec2.channels_m1++;
270
271 agx_mov_to(b, temp1, agx_memory_register(2, AGX_SIZE_32));
272 agx_mov_to(b, temp2, agx_memory_register(804, AGX_SIZE_32));
273 agx_mov_to(b, agx_memory_register(804, AGX_SIZE_32), temp1);
274 agx_mov_to(b, agx_memory_register(2, AGX_SIZE_32), temp2);
275
276 /* Stack swap: 16-bit */
277 spilled_gpr_vec2.size = AGX_SIZE_16;
278 temp1.size = AGX_SIZE_16;
279 temp2.size = AGX_SIZE_16;
280
281 agx_mov_to(b, temp1, agx_memory_register(807, AGX_SIZE_16));
282 agx_mov_to(b, temp2, agx_memory_register(808, AGX_SIZE_16));
283 agx_mov_to(b, agx_memory_register(808, AGX_SIZE_16), temp1);
284 agx_mov_to(b, agx_memory_register(807, AGX_SIZE_16), temp2);
285 });
286 }
287
288 #if 0
289 TEST_F(LowerParallelCopy, LooksLikeASwap) {
290 struct agx_copy test[] = {
291 { .dest = 0, .src = agx_register(2, AGX_SIZE_32) },
292 { .dest = 2, .src = agx_register(0, AGX_SIZE_32) },
293 { .dest = 4, .src = agx_register(2, AGX_SIZE_32) },
294 };
295
296 CASE(test, {
297 agx_mov_to(b, agx_register(4, AGX_SIZE_32), agx_register(2, AGX_SIZE_32));
298 agx_mov_to(b, agx_register(2, AGX_SIZE_32), agx_register(0, AGX_SIZE_32));
299 agx_mov_to(b, agx_register(0, AGX_SIZE_32), agx_register(4, AGX_SIZE_32));
300 });
301 }
302 #endif
303