1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 2022 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker * Copyright 2021 Collabora, Ltd.
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #include "util/compiler.h"
8*61046927SAndroid Build Coastguard Worker #include "agx_compiler.h"
9*61046927SAndroid Build Coastguard Worker #include "agx_debug.h"
10*61046927SAndroid Build Coastguard Worker #include "agx_opcodes.h"
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard Worker /* Validatation doesn't make sense in release builds */
13*61046927SAndroid Build Coastguard Worker #ifndef NDEBUG
14*61046927SAndroid Build Coastguard Worker
15*61046927SAndroid Build Coastguard Worker #define agx_validate_assert(stmt) \
16*61046927SAndroid Build Coastguard Worker if (!(stmt)) { \
17*61046927SAndroid Build Coastguard Worker return false; \
18*61046927SAndroid Build Coastguard Worker }
19*61046927SAndroid Build Coastguard Worker
20*61046927SAndroid Build Coastguard Worker /*
21*61046927SAndroid Build Coastguard Worker * If a block contains phi nodes, they must come at the start of the block. If a
22*61046927SAndroid Build Coastguard Worker * block contains control flow, it must come at the beginning/end as applicable.
23*61046927SAndroid Build Coastguard Worker * Therefore the form of a valid block is:
24*61046927SAndroid Build Coastguard Worker *
25*61046927SAndroid Build Coastguard Worker * Control flow instructions (else)
26*61046927SAndroid Build Coastguard Worker * Phi nodes
27*61046927SAndroid Build Coastguard Worker * General instructions
28*61046927SAndroid Build Coastguard Worker * Control flow instructions (except else)
29*61046927SAndroid Build Coastguard Worker *
30*61046927SAndroid Build Coastguard Worker * Validate that this form is satisfied.
31*61046927SAndroid Build Coastguard Worker */
32*61046927SAndroid Build Coastguard Worker enum agx_block_state {
33*61046927SAndroid Build Coastguard Worker AGX_BLOCK_STATE_CF_ELSE = 0,
34*61046927SAndroid Build Coastguard Worker AGX_BLOCK_STATE_PHI = 1,
35*61046927SAndroid Build Coastguard Worker AGX_BLOCK_STATE_BODY = 2,
36*61046927SAndroid Build Coastguard Worker AGX_BLOCK_STATE_CF = 3
37*61046927SAndroid Build Coastguard Worker };
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker static bool
agx_validate_block_form(agx_block * block)40*61046927SAndroid Build Coastguard Worker agx_validate_block_form(agx_block *block)
41*61046927SAndroid Build Coastguard Worker {
42*61046927SAndroid Build Coastguard Worker enum agx_block_state state = AGX_BLOCK_STATE_CF_ELSE;
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker agx_foreach_instr_in_block(block, I) {
45*61046927SAndroid Build Coastguard Worker switch (I->op) {
46*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_PRELOAD:
47*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_ELSE_ICMP:
48*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_ELSE_FCMP:
49*61046927SAndroid Build Coastguard Worker agx_validate_assert(state == AGX_BLOCK_STATE_CF_ELSE);
50*61046927SAndroid Build Coastguard Worker break;
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_PHI:
53*61046927SAndroid Build Coastguard Worker agx_validate_assert(state == AGX_BLOCK_STATE_CF_ELSE ||
54*61046927SAndroid Build Coastguard Worker state == AGX_BLOCK_STATE_PHI);
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker state = AGX_BLOCK_STATE_PHI;
57*61046927SAndroid Build Coastguard Worker break;
58*61046927SAndroid Build Coastguard Worker
59*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_EXPORT:
60*61046927SAndroid Build Coastguard Worker agx_validate_assert(agx_num_successors(block) == 0);
61*61046927SAndroid Build Coastguard Worker state = AGX_BLOCK_STATE_CF;
62*61046927SAndroid Build Coastguard Worker break;
63*61046927SAndroid Build Coastguard Worker
64*61046927SAndroid Build Coastguard Worker default:
65*61046927SAndroid Build Coastguard Worker if (instr_after_logical_end(I)) {
66*61046927SAndroid Build Coastguard Worker state = AGX_BLOCK_STATE_CF;
67*61046927SAndroid Build Coastguard Worker } else {
68*61046927SAndroid Build Coastguard Worker agx_validate_assert(state != AGX_BLOCK_STATE_CF);
69*61046927SAndroid Build Coastguard Worker state = AGX_BLOCK_STATE_BODY;
70*61046927SAndroid Build Coastguard Worker }
71*61046927SAndroid Build Coastguard Worker break;
72*61046927SAndroid Build Coastguard Worker }
73*61046927SAndroid Build Coastguard Worker }
74*61046927SAndroid Build Coastguard Worker
75*61046927SAndroid Build Coastguard Worker return true;
76*61046927SAndroid Build Coastguard Worker }
77*61046927SAndroid Build Coastguard Worker
78*61046927SAndroid Build Coastguard Worker /*
79*61046927SAndroid Build Coastguard Worker * Only moves and phis use stack. Phis cannot use moves due to their
80*61046927SAndroid Build Coastguard Worker * parallel nature, so we allow phis to take memory, later lowered to moves.
81*61046927SAndroid Build Coastguard Worker */
82*61046927SAndroid Build Coastguard Worker static bool
is_stack_valid(agx_instr * I)83*61046927SAndroid Build Coastguard Worker is_stack_valid(agx_instr *I)
84*61046927SAndroid Build Coastguard Worker {
85*61046927SAndroid Build Coastguard Worker return (I->op == AGX_OPCODE_MOV) || (I->op == AGX_OPCODE_PHI);
86*61046927SAndroid Build Coastguard Worker }
87*61046927SAndroid Build Coastguard Worker
88*61046927SAndroid Build Coastguard Worker static bool
agx_validate_sources(agx_instr * I)89*61046927SAndroid Build Coastguard Worker agx_validate_sources(agx_instr *I)
90*61046927SAndroid Build Coastguard Worker {
91*61046927SAndroid Build Coastguard Worker agx_foreach_src(I, s) {
92*61046927SAndroid Build Coastguard Worker agx_index src = I->src[s];
93*61046927SAndroid Build Coastguard Worker
94*61046927SAndroid Build Coastguard Worker if (src.type == AGX_INDEX_IMMEDIATE) {
95*61046927SAndroid Build Coastguard Worker agx_validate_assert(!src.kill);
96*61046927SAndroid Build Coastguard Worker agx_validate_assert(!src.cache);
97*61046927SAndroid Build Coastguard Worker agx_validate_assert(!src.discard);
98*61046927SAndroid Build Coastguard Worker
99*61046927SAndroid Build Coastguard Worker bool ldst = agx_allows_16bit_immediate(I);
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker /* Immediates are encoded as 8-bit (16-bit for memory load/store). For
102*61046927SAndroid Build Coastguard Worker * integers, they extend to 16-bit. For floating point, they are 8-bit
103*61046927SAndroid Build Coastguard Worker * minifloats. The 8-bit minifloats are a strict subset of 16-bit
104*61046927SAndroid Build Coastguard Worker * standard floats, so we treat them as such in the IR, with an
105*61046927SAndroid Build Coastguard Worker * implicit f16->f32 for 32-bit floating point operations.
106*61046927SAndroid Build Coastguard Worker */
107*61046927SAndroid Build Coastguard Worker agx_validate_assert(src.size == AGX_SIZE_16);
108*61046927SAndroid Build Coastguard Worker agx_validate_assert(src.value < (1 << (ldst ? 16 : 8)));
109*61046927SAndroid Build Coastguard Worker } else if (I->op == AGX_OPCODE_COLLECT && !agx_is_null(src)) {
110*61046927SAndroid Build Coastguard Worker agx_validate_assert(src.size == I->src[0].size);
111*61046927SAndroid Build Coastguard Worker } else if (I->op == AGX_OPCODE_PHI) {
112*61046927SAndroid Build Coastguard Worker agx_validate_assert(src.size == I->dest[0].size);
113*61046927SAndroid Build Coastguard Worker agx_validate_assert(!agx_is_null(src));
114*61046927SAndroid Build Coastguard Worker }
115*61046927SAndroid Build Coastguard Worker
116*61046927SAndroid Build Coastguard Worker agx_validate_assert(!src.memory || is_stack_valid(I));
117*61046927SAndroid Build Coastguard Worker }
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker return true;
120*61046927SAndroid Build Coastguard Worker }
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker static bool
agx_validate_defs(agx_instr * I,BITSET_WORD * defs)123*61046927SAndroid Build Coastguard Worker agx_validate_defs(agx_instr *I, BITSET_WORD *defs)
124*61046927SAndroid Build Coastguard Worker {
125*61046927SAndroid Build Coastguard Worker agx_foreach_ssa_src(I, s) {
126*61046927SAndroid Build Coastguard Worker /* Skip phis, they're special in loop headers */
127*61046927SAndroid Build Coastguard Worker if (I->op == AGX_OPCODE_PHI)
128*61046927SAndroid Build Coastguard Worker break;
129*61046927SAndroid Build Coastguard Worker
130*61046927SAndroid Build Coastguard Worker /* Sources must be defined before their use */
131*61046927SAndroid Build Coastguard Worker if (!BITSET_TEST(defs, I->src[s].value))
132*61046927SAndroid Build Coastguard Worker return false;
133*61046927SAndroid Build Coastguard Worker }
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker agx_foreach_ssa_dest(I, d) {
136*61046927SAndroid Build Coastguard Worker /* Static single assignment */
137*61046927SAndroid Build Coastguard Worker if (BITSET_TEST(defs, I->dest[d].value))
138*61046927SAndroid Build Coastguard Worker return false;
139*61046927SAndroid Build Coastguard Worker
140*61046927SAndroid Build Coastguard Worker BITSET_SET(defs, I->dest[d].value);
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker if (I->dest[d].memory && !is_stack_valid(I))
143*61046927SAndroid Build Coastguard Worker return false;
144*61046927SAndroid Build Coastguard Worker }
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker return true;
147*61046927SAndroid Build Coastguard Worker }
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker /** Returns number of registers written by an instruction */
150*61046927SAndroid Build Coastguard Worker static unsigned
agx_write_registers(const agx_instr * I,unsigned d)151*61046927SAndroid Build Coastguard Worker agx_write_registers(const agx_instr *I, unsigned d)
152*61046927SAndroid Build Coastguard Worker {
153*61046927SAndroid Build Coastguard Worker unsigned size = agx_size_align_16(I->dest[d].size);
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker switch (I->op) {
156*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_MOV:
157*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_PHI:
158*61046927SAndroid Build Coastguard Worker /* Tautological */
159*61046927SAndroid Build Coastguard Worker return agx_index_size_16(I->dest[d]);
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_ITER:
162*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_ITERPROJ:
163*61046927SAndroid Build Coastguard Worker assert(1 <= I->channels && I->channels <= 4);
164*61046927SAndroid Build Coastguard Worker return I->channels * size;
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_IMAGE_LOAD:
167*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_TEXTURE_LOAD:
168*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_TEXTURE_SAMPLE:
169*61046927SAndroid Build Coastguard Worker /* Even when masked out, these clobber 4 registers */
170*61046927SAndroid Build Coastguard Worker return 4 * size;
171*61046927SAndroid Build Coastguard Worker
172*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_DEVICE_LOAD:
173*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_LOCAL_LOAD:
174*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_STACK_LOAD:
175*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_LD_TILE:
176*61046927SAndroid Build Coastguard Worker /* Can write 16-bit or 32-bit. Anything logically 64-bit is already
177*61046927SAndroid Build Coastguard Worker * expanded to 32-bit in the mask.
178*61046927SAndroid Build Coastguard Worker */
179*61046927SAndroid Build Coastguard Worker return util_bitcount(I->mask) * MIN2(size, 2);
180*61046927SAndroid Build Coastguard Worker
181*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_LDCF:
182*61046927SAndroid Build Coastguard Worker return 6;
183*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_COLLECT:
184*61046927SAndroid Build Coastguard Worker return I->nr_srcs * agx_size_align_16(I->src[0].size);
185*61046927SAndroid Build Coastguard Worker default:
186*61046927SAndroid Build Coastguard Worker return size;
187*61046927SAndroid Build Coastguard Worker }
188*61046927SAndroid Build Coastguard Worker }
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker struct dim_info {
191*61046927SAndroid Build Coastguard Worker unsigned comps;
192*61046927SAndroid Build Coastguard Worker bool array;
193*61046927SAndroid Build Coastguard Worker };
194*61046927SAndroid Build Coastguard Worker
195*61046927SAndroid Build Coastguard Worker static struct dim_info
agx_dim_info(enum agx_dim dim)196*61046927SAndroid Build Coastguard Worker agx_dim_info(enum agx_dim dim)
197*61046927SAndroid Build Coastguard Worker {
198*61046927SAndroid Build Coastguard Worker switch (dim) {
199*61046927SAndroid Build Coastguard Worker case AGX_DIM_1D:
200*61046927SAndroid Build Coastguard Worker return (struct dim_info){1, false};
201*61046927SAndroid Build Coastguard Worker case AGX_DIM_1D_ARRAY:
202*61046927SAndroid Build Coastguard Worker return (struct dim_info){1, true};
203*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D:
204*61046927SAndroid Build Coastguard Worker return (struct dim_info){2, false};
205*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D_ARRAY:
206*61046927SAndroid Build Coastguard Worker return (struct dim_info){2, true};
207*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D_MS:
208*61046927SAndroid Build Coastguard Worker return (struct dim_info){3, false};
209*61046927SAndroid Build Coastguard Worker case AGX_DIM_3D:
210*61046927SAndroid Build Coastguard Worker return (struct dim_info){3, false};
211*61046927SAndroid Build Coastguard Worker case AGX_DIM_CUBE:
212*61046927SAndroid Build Coastguard Worker return (struct dim_info){3, false};
213*61046927SAndroid Build Coastguard Worker case AGX_DIM_CUBE_ARRAY:
214*61046927SAndroid Build Coastguard Worker return (struct dim_info){3, true};
215*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D_MS_ARRAY:
216*61046927SAndroid Build Coastguard Worker return (struct dim_info){2, true};
217*61046927SAndroid Build Coastguard Worker default:
218*61046927SAndroid Build Coastguard Worker unreachable("invalid dim");
219*61046927SAndroid Build Coastguard Worker }
220*61046927SAndroid Build Coastguard Worker }
221*61046927SAndroid Build Coastguard Worker
222*61046927SAndroid Build Coastguard Worker /*
223*61046927SAndroid Build Coastguard Worker * Return number of registers required for coordinates for a texture/image
224*61046927SAndroid Build Coastguard Worker * instruction. We handle layer + sample index as 32-bit even when only the
225*61046927SAndroid Build Coastguard Worker * lower 16-bits are present. LOD queries do not take a layer.
226*61046927SAndroid Build Coastguard Worker */
227*61046927SAndroid Build Coastguard Worker static unsigned
agx_coordinate_registers(const agx_instr * I)228*61046927SAndroid Build Coastguard Worker agx_coordinate_registers(const agx_instr *I)
229*61046927SAndroid Build Coastguard Worker {
230*61046927SAndroid Build Coastguard Worker struct dim_info dim = agx_dim_info(I->dim);
231*61046927SAndroid Build Coastguard Worker bool has_array = !I->query_lod;
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Worker return 2 * (dim.comps + (has_array && dim.array));
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Worker static unsigned
agx_read_registers(const agx_instr * I,unsigned s)237*61046927SAndroid Build Coastguard Worker agx_read_registers(const agx_instr *I, unsigned s)
238*61046927SAndroid Build Coastguard Worker {
239*61046927SAndroid Build Coastguard Worker unsigned size = agx_size_align_16(I->src[s].size);
240*61046927SAndroid Build Coastguard Worker
241*61046927SAndroid Build Coastguard Worker switch (I->op) {
242*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_MOV:
243*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_EXPORT:
244*61046927SAndroid Build Coastguard Worker /* Tautological */
245*61046927SAndroid Build Coastguard Worker return agx_index_size_16(I->src[0]);
246*61046927SAndroid Build Coastguard Worker
247*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_PHI:
248*61046927SAndroid Build Coastguard Worker if (I->src[s].type == AGX_INDEX_IMMEDIATE)
249*61046927SAndroid Build Coastguard Worker return size;
250*61046927SAndroid Build Coastguard Worker else
251*61046927SAndroid Build Coastguard Worker return agx_index_size_16(I->dest[0]);
252*61046927SAndroid Build Coastguard Worker
253*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_SPLIT:
254*61046927SAndroid Build Coastguard Worker return I->nr_dests * agx_size_align_16(agx_split_width(I));
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_UNIFORM_STORE:
257*61046927SAndroid Build Coastguard Worker if (s == 0)
258*61046927SAndroid Build Coastguard Worker return util_bitcount(I->mask) * size;
259*61046927SAndroid Build Coastguard Worker else
260*61046927SAndroid Build Coastguard Worker return size;
261*61046927SAndroid Build Coastguard Worker
262*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_DEVICE_STORE:
263*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_LOCAL_STORE:
264*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_STACK_STORE:
265*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_ST_TILE:
266*61046927SAndroid Build Coastguard Worker /* See agx_write_registers */
267*61046927SAndroid Build Coastguard Worker if (s == 0)
268*61046927SAndroid Build Coastguard Worker return util_bitcount(I->mask) * MIN2(size, 2);
269*61046927SAndroid Build Coastguard Worker else if (s == 2 && I->explicit_coords)
270*61046927SAndroid Build Coastguard Worker return 2;
271*61046927SAndroid Build Coastguard Worker else
272*61046927SAndroid Build Coastguard Worker return size;
273*61046927SAndroid Build Coastguard Worker
274*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_ZS_EMIT:
275*61046927SAndroid Build Coastguard Worker if (s == 1) {
276*61046927SAndroid Build Coastguard Worker /* Depth (bit 0) is fp32, stencil (bit 1) is u16 in the hw but we pad
277*61046927SAndroid Build Coastguard Worker * up to u32 for simplicity
278*61046927SAndroid Build Coastguard Worker */
279*61046927SAndroid Build Coastguard Worker bool z = !!(I->zs & 1);
280*61046927SAndroid Build Coastguard Worker bool s = !!(I->zs & 2);
281*61046927SAndroid Build Coastguard Worker assert(z || s);
282*61046927SAndroid Build Coastguard Worker
283*61046927SAndroid Build Coastguard Worker return (z && s) ? 4 : z ? 2 : 1;
284*61046927SAndroid Build Coastguard Worker } else {
285*61046927SAndroid Build Coastguard Worker return 1;
286*61046927SAndroid Build Coastguard Worker }
287*61046927SAndroid Build Coastguard Worker
288*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_IMAGE_WRITE:
289*61046927SAndroid Build Coastguard Worker if (s == 0)
290*61046927SAndroid Build Coastguard Worker return 4 * size /* data */;
291*61046927SAndroid Build Coastguard Worker else if (s == 1)
292*61046927SAndroid Build Coastguard Worker return agx_coordinate_registers(I);
293*61046927SAndroid Build Coastguard Worker else
294*61046927SAndroid Build Coastguard Worker return size;
295*61046927SAndroid Build Coastguard Worker
296*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_IMAGE_LOAD:
297*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_TEXTURE_LOAD:
298*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_TEXTURE_SAMPLE:
299*61046927SAndroid Build Coastguard Worker if (s == 0) {
300*61046927SAndroid Build Coastguard Worker return agx_coordinate_registers(I);
301*61046927SAndroid Build Coastguard Worker } else if (s == 1) {
302*61046927SAndroid Build Coastguard Worker /* LOD */
303*61046927SAndroid Build Coastguard Worker if (I->lod_mode == AGX_LOD_MODE_LOD_GRAD ||
304*61046927SAndroid Build Coastguard Worker I->lod_mode == AGX_LOD_MODE_LOD_GRAD_MIN) {
305*61046927SAndroid Build Coastguard Worker
306*61046927SAndroid Build Coastguard Worker /* Technically only 16-bit but we model as 32-bit to keep the IR
307*61046927SAndroid Build Coastguard Worker * simple, since the gradient is otherwise 32-bit.
308*61046927SAndroid Build Coastguard Worker */
309*61046927SAndroid Build Coastguard Worker unsigned min = I->lod_mode == AGX_LOD_MODE_LOD_GRAD_MIN ? 2 : 0;
310*61046927SAndroid Build Coastguard Worker
311*61046927SAndroid Build Coastguard Worker switch (I->dim) {
312*61046927SAndroid Build Coastguard Worker case AGX_DIM_1D:
313*61046927SAndroid Build Coastguard Worker case AGX_DIM_1D_ARRAY:
314*61046927SAndroid Build Coastguard Worker return (2 * 2 * 1) + min;
315*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D:
316*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D_ARRAY:
317*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D_MS_ARRAY:
318*61046927SAndroid Build Coastguard Worker case AGX_DIM_2D_MS:
319*61046927SAndroid Build Coastguard Worker return (2 * 2 * 2) + min;
320*61046927SAndroid Build Coastguard Worker case AGX_DIM_CUBE:
321*61046927SAndroid Build Coastguard Worker case AGX_DIM_CUBE_ARRAY:
322*61046927SAndroid Build Coastguard Worker case AGX_DIM_3D:
323*61046927SAndroid Build Coastguard Worker return (2 * 2 * 3) + min;
324*61046927SAndroid Build Coastguard Worker }
325*61046927SAndroid Build Coastguard Worker
326*61046927SAndroid Build Coastguard Worker unreachable("Invalid texture dimension");
327*61046927SAndroid Build Coastguard Worker } else if (I->lod_mode == AGX_LOD_MODE_AUTO_LOD_BIAS_MIN) {
328*61046927SAndroid Build Coastguard Worker return 2;
329*61046927SAndroid Build Coastguard Worker } else {
330*61046927SAndroid Build Coastguard Worker return 1;
331*61046927SAndroid Build Coastguard Worker }
332*61046927SAndroid Build Coastguard Worker } else if (s == 5) {
333*61046927SAndroid Build Coastguard Worker /* Compare/offset */
334*61046927SAndroid Build Coastguard Worker return 2 * ((!!I->shadow) + (!!I->offset));
335*61046927SAndroid Build Coastguard Worker } else {
336*61046927SAndroid Build Coastguard Worker return size;
337*61046927SAndroid Build Coastguard Worker }
338*61046927SAndroid Build Coastguard Worker
339*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_BLOCK_IMAGE_STORE:
340*61046927SAndroid Build Coastguard Worker if (s == 3 && I->explicit_coords)
341*61046927SAndroid Build Coastguard Worker return agx_coordinate_registers(I);
342*61046927SAndroid Build Coastguard Worker else
343*61046927SAndroid Build Coastguard Worker return size;
344*61046927SAndroid Build Coastguard Worker
345*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_ATOMIC:
346*61046927SAndroid Build Coastguard Worker case AGX_OPCODE_LOCAL_ATOMIC:
347*61046927SAndroid Build Coastguard Worker if (s == 0 && I->atomic_opc == AGX_ATOMIC_OPC_CMPXCHG)
348*61046927SAndroid Build Coastguard Worker return size * 2;
349*61046927SAndroid Build Coastguard Worker else
350*61046927SAndroid Build Coastguard Worker return size;
351*61046927SAndroid Build Coastguard Worker
352*61046927SAndroid Build Coastguard Worker default:
353*61046927SAndroid Build Coastguard Worker return size;
354*61046927SAndroid Build Coastguard Worker }
355*61046927SAndroid Build Coastguard Worker }
356*61046927SAndroid Build Coastguard Worker
357*61046927SAndroid Build Coastguard Worker /* Type check the dimensionality of sources and destinations. */
358*61046927SAndroid Build Coastguard Worker static bool
agx_validate_width(agx_context * ctx)359*61046927SAndroid Build Coastguard Worker agx_validate_width(agx_context *ctx)
360*61046927SAndroid Build Coastguard Worker {
361*61046927SAndroid Build Coastguard Worker bool succ = true;
362*61046927SAndroid Build Coastguard Worker
363*61046927SAndroid Build Coastguard Worker agx_foreach_instr_global(ctx, I) {
364*61046927SAndroid Build Coastguard Worker agx_foreach_dest(I, d) {
365*61046927SAndroid Build Coastguard Worker unsigned exp = agx_write_registers(I, d);
366*61046927SAndroid Build Coastguard Worker unsigned act =
367*61046927SAndroid Build Coastguard Worker agx_channels(I->dest[d]) * agx_size_align_16(I->dest[d].size);
368*61046927SAndroid Build Coastguard Worker
369*61046927SAndroid Build Coastguard Worker if (exp != act) {
370*61046927SAndroid Build Coastguard Worker succ = false;
371*61046927SAndroid Build Coastguard Worker fprintf(stderr, "destination %u, expected width %u, got width %u\n",
372*61046927SAndroid Build Coastguard Worker d, exp, act);
373*61046927SAndroid Build Coastguard Worker agx_print_instr(I, stderr);
374*61046927SAndroid Build Coastguard Worker fprintf(stderr, "\n");
375*61046927SAndroid Build Coastguard Worker }
376*61046927SAndroid Build Coastguard Worker }
377*61046927SAndroid Build Coastguard Worker
378*61046927SAndroid Build Coastguard Worker agx_foreach_src(I, s) {
379*61046927SAndroid Build Coastguard Worker if (I->src[s].type == AGX_INDEX_NULL)
380*61046927SAndroid Build Coastguard Worker continue;
381*61046927SAndroid Build Coastguard Worker
382*61046927SAndroid Build Coastguard Worker unsigned exp = agx_read_registers(I, s);
383*61046927SAndroid Build Coastguard Worker unsigned act =
384*61046927SAndroid Build Coastguard Worker agx_channels(I->src[s]) * agx_size_align_16(I->src[s].size);
385*61046927SAndroid Build Coastguard Worker
386*61046927SAndroid Build Coastguard Worker if (exp != act) {
387*61046927SAndroid Build Coastguard Worker succ = false;
388*61046927SAndroid Build Coastguard Worker fprintf(stderr, "source %u, expected width %u, got width %u\n", s,
389*61046927SAndroid Build Coastguard Worker exp, act);
390*61046927SAndroid Build Coastguard Worker agx_print_instr(I, stderr);
391*61046927SAndroid Build Coastguard Worker fprintf(stderr, "\n");
392*61046927SAndroid Build Coastguard Worker }
393*61046927SAndroid Build Coastguard Worker }
394*61046927SAndroid Build Coastguard Worker }
395*61046927SAndroid Build Coastguard Worker
396*61046927SAndroid Build Coastguard Worker return succ;
397*61046927SAndroid Build Coastguard Worker }
398*61046927SAndroid Build Coastguard Worker
399*61046927SAndroid Build Coastguard Worker static bool
agx_validate_predecessors(agx_block * block)400*61046927SAndroid Build Coastguard Worker agx_validate_predecessors(agx_block *block)
401*61046927SAndroid Build Coastguard Worker {
402*61046927SAndroid Build Coastguard Worker /* Loop headers (only) have predecessors that are later in source form */
403*61046927SAndroid Build Coastguard Worker bool has_later_preds = false;
404*61046927SAndroid Build Coastguard Worker
405*61046927SAndroid Build Coastguard Worker agx_foreach_predecessor(block, pred) {
406*61046927SAndroid Build Coastguard Worker if ((*pred)->index >= block->index)
407*61046927SAndroid Build Coastguard Worker has_later_preds = true;
408*61046927SAndroid Build Coastguard Worker }
409*61046927SAndroid Build Coastguard Worker
410*61046927SAndroid Build Coastguard Worker if (has_later_preds && !block->loop_header)
411*61046927SAndroid Build Coastguard Worker return false;
412*61046927SAndroid Build Coastguard Worker
413*61046927SAndroid Build Coastguard Worker /* Successors and predecessors are found together */
414*61046927SAndroid Build Coastguard Worker agx_foreach_predecessor(block, pred) {
415*61046927SAndroid Build Coastguard Worker bool found = false;
416*61046927SAndroid Build Coastguard Worker
417*61046927SAndroid Build Coastguard Worker agx_foreach_successor((*pred), succ) {
418*61046927SAndroid Build Coastguard Worker if (succ == block)
419*61046927SAndroid Build Coastguard Worker found = true;
420*61046927SAndroid Build Coastguard Worker }
421*61046927SAndroid Build Coastguard Worker
422*61046927SAndroid Build Coastguard Worker if (!found)
423*61046927SAndroid Build Coastguard Worker return false;
424*61046927SAndroid Build Coastguard Worker }
425*61046927SAndroid Build Coastguard Worker
426*61046927SAndroid Build Coastguard Worker return true;
427*61046927SAndroid Build Coastguard Worker }
428*61046927SAndroid Build Coastguard Worker
429*61046927SAndroid Build Coastguard Worker static bool
agx_validate_sr(const agx_instr * I)430*61046927SAndroid Build Coastguard Worker agx_validate_sr(const agx_instr *I)
431*61046927SAndroid Build Coastguard Worker {
432*61046927SAndroid Build Coastguard Worker bool none = (I->op == AGX_OPCODE_GET_SR);
433*61046927SAndroid Build Coastguard Worker bool coverage = (I->op == AGX_OPCODE_GET_SR_COVERAGE);
434*61046927SAndroid Build Coastguard Worker bool barrier = (I->op == AGX_OPCODE_GET_SR_BARRIER);
435*61046927SAndroid Build Coastguard Worker
436*61046927SAndroid Build Coastguard Worker /* Filter get_sr instructions */
437*61046927SAndroid Build Coastguard Worker if (!(none || coverage || barrier))
438*61046927SAndroid Build Coastguard Worker return true;
439*61046927SAndroid Build Coastguard Worker
440*61046927SAndroid Build Coastguard Worker switch (I->sr) {
441*61046927SAndroid Build Coastguard Worker case AGX_SR_ACTIVE_THREAD_INDEX_IN_QUAD:
442*61046927SAndroid Build Coastguard Worker case AGX_SR_ACTIVE_THREAD_INDEX_IN_SUBGROUP:
443*61046927SAndroid Build Coastguard Worker case AGX_SR_TOTAL_ACTIVE_THREADS_IN_QUAD:
444*61046927SAndroid Build Coastguard Worker case AGX_SR_TOTAL_ACTIVE_THREADS_IN_SUBGROUP:
445*61046927SAndroid Build Coastguard Worker case AGX_SR_COVERAGE_MASK:
446*61046927SAndroid Build Coastguard Worker case AGX_SR_IS_ACTIVE_THREAD:
447*61046927SAndroid Build Coastguard Worker return coverage;
448*61046927SAndroid Build Coastguard Worker
449*61046927SAndroid Build Coastguard Worker case AGX_SR_HELPER_OP:
450*61046927SAndroid Build Coastguard Worker case AGX_SR_HELPER_ARG_L:
451*61046927SAndroid Build Coastguard Worker case AGX_SR_HELPER_ARG_H:
452*61046927SAndroid Build Coastguard Worker return barrier;
453*61046927SAndroid Build Coastguard Worker
454*61046927SAndroid Build Coastguard Worker default:
455*61046927SAndroid Build Coastguard Worker return none;
456*61046927SAndroid Build Coastguard Worker }
457*61046927SAndroid Build Coastguard Worker }
458*61046927SAndroid Build Coastguard Worker
459*61046927SAndroid Build Coastguard Worker void
agx_validate(agx_context * ctx,const char * after)460*61046927SAndroid Build Coastguard Worker agx_validate(agx_context *ctx, const char *after)
461*61046927SAndroid Build Coastguard Worker {
462*61046927SAndroid Build Coastguard Worker bool fail = false;
463*61046927SAndroid Build Coastguard Worker
464*61046927SAndroid Build Coastguard Worker if (agx_compiler_debug & AGX_DBG_NOVALIDATE)
465*61046927SAndroid Build Coastguard Worker return;
466*61046927SAndroid Build Coastguard Worker
467*61046927SAndroid Build Coastguard Worker int last_index = -1;
468*61046927SAndroid Build Coastguard Worker
469*61046927SAndroid Build Coastguard Worker agx_foreach_block(ctx, block) {
470*61046927SAndroid Build Coastguard Worker if ((int)block->index < last_index) {
471*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Out-of-order block index %d vs %d after %s\n",
472*61046927SAndroid Build Coastguard Worker block->index, last_index, after);
473*61046927SAndroid Build Coastguard Worker agx_print_block(block, stderr);
474*61046927SAndroid Build Coastguard Worker fail = true;
475*61046927SAndroid Build Coastguard Worker }
476*61046927SAndroid Build Coastguard Worker
477*61046927SAndroid Build Coastguard Worker last_index = block->index;
478*61046927SAndroid Build Coastguard Worker
479*61046927SAndroid Build Coastguard Worker if (!agx_validate_block_form(block)) {
480*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Invalid block form after %s\n", after);
481*61046927SAndroid Build Coastguard Worker agx_print_block(block, stderr);
482*61046927SAndroid Build Coastguard Worker fail = true;
483*61046927SAndroid Build Coastguard Worker }
484*61046927SAndroid Build Coastguard Worker
485*61046927SAndroid Build Coastguard Worker if (!agx_validate_predecessors(block)) {
486*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Invalid loop header flag after %s\n", after);
487*61046927SAndroid Build Coastguard Worker agx_print_block(block, stderr);
488*61046927SAndroid Build Coastguard Worker fail = true;
489*61046927SAndroid Build Coastguard Worker }
490*61046927SAndroid Build Coastguard Worker }
491*61046927SAndroid Build Coastguard Worker
492*61046927SAndroid Build Coastguard Worker {
493*61046927SAndroid Build Coastguard Worker BITSET_WORD *defs = calloc(sizeof(BITSET_WORD), BITSET_WORDS(ctx->alloc));
494*61046927SAndroid Build Coastguard Worker
495*61046927SAndroid Build Coastguard Worker agx_foreach_instr_global(ctx, I) {
496*61046927SAndroid Build Coastguard Worker if (!agx_validate_defs(I, defs)) {
497*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Invalid defs after %s\n", after);
498*61046927SAndroid Build Coastguard Worker agx_print_instr(I, stderr);
499*61046927SAndroid Build Coastguard Worker fail = true;
500*61046927SAndroid Build Coastguard Worker }
501*61046927SAndroid Build Coastguard Worker }
502*61046927SAndroid Build Coastguard Worker
503*61046927SAndroid Build Coastguard Worker free(defs);
504*61046927SAndroid Build Coastguard Worker }
505*61046927SAndroid Build Coastguard Worker
506*61046927SAndroid Build Coastguard Worker agx_foreach_instr_global(ctx, I) {
507*61046927SAndroid Build Coastguard Worker if (!agx_validate_sources(I)) {
508*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Invalid sources form after %s\n", after);
509*61046927SAndroid Build Coastguard Worker agx_print_instr(I, stderr);
510*61046927SAndroid Build Coastguard Worker fail = true;
511*61046927SAndroid Build Coastguard Worker }
512*61046927SAndroid Build Coastguard Worker
513*61046927SAndroid Build Coastguard Worker if (!agx_validate_sr(I)) {
514*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Invalid SR after %s\n", after);
515*61046927SAndroid Build Coastguard Worker agx_print_instr(I, stdout);
516*61046927SAndroid Build Coastguard Worker fail = true;
517*61046927SAndroid Build Coastguard Worker }
518*61046927SAndroid Build Coastguard Worker }
519*61046927SAndroid Build Coastguard Worker
520*61046927SAndroid Build Coastguard Worker if (!agx_validate_width(ctx)) {
521*61046927SAndroid Build Coastguard Worker fprintf(stderr, "Invalid vectors after %s\n", after);
522*61046927SAndroid Build Coastguard Worker fail = true;
523*61046927SAndroid Build Coastguard Worker }
524*61046927SAndroid Build Coastguard Worker
525*61046927SAndroid Build Coastguard Worker if (fail) {
526*61046927SAndroid Build Coastguard Worker agx_print_shader(ctx, stderr);
527*61046927SAndroid Build Coastguard Worker exit(1);
528*61046927SAndroid Build Coastguard Worker }
529*61046927SAndroid Build Coastguard Worker }
530*61046927SAndroid Build Coastguard Worker
531*61046927SAndroid Build Coastguard Worker #endif /* NDEBUG */
532