xref: /aosp_15_r20/external/mesa3d/src/freedreno/ir3/ir3_validate.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2020 Google, Inc.
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker #include "util/ralloc.h"
9*61046927SAndroid Build Coastguard Worker 
10*61046927SAndroid Build Coastguard Worker #include "ir3.h"
11*61046927SAndroid Build Coastguard Worker #include "ir3_compiler.h"
12*61046927SAndroid Build Coastguard Worker 
13*61046927SAndroid Build Coastguard Worker struct ir3_validate_ctx {
14*61046927SAndroid Build Coastguard Worker    struct ir3 *ir;
15*61046927SAndroid Build Coastguard Worker 
16*61046927SAndroid Build Coastguard Worker    /* Current block being validated: */
17*61046927SAndroid Build Coastguard Worker    struct ir3_block *current_block;
18*61046927SAndroid Build Coastguard Worker 
19*61046927SAndroid Build Coastguard Worker    /* Current instruction being validated: */
20*61046927SAndroid Build Coastguard Worker    struct ir3_instruction *current_instr;
21*61046927SAndroid Build Coastguard Worker 
22*61046927SAndroid Build Coastguard Worker    /* Set of instructions found so far, used to validate that we
23*61046927SAndroid Build Coastguard Worker     * don't have SSA uses that occure before def's
24*61046927SAndroid Build Coastguard Worker     */
25*61046927SAndroid Build Coastguard Worker    struct set *defs;
26*61046927SAndroid Build Coastguard Worker };
27*61046927SAndroid Build Coastguard Worker 
28*61046927SAndroid Build Coastguard Worker static void
validate_error(struct ir3_validate_ctx * ctx,const char * condstr)29*61046927SAndroid Build Coastguard Worker validate_error(struct ir3_validate_ctx *ctx, const char *condstr)
30*61046927SAndroid Build Coastguard Worker {
31*61046927SAndroid Build Coastguard Worker    fprintf(stderr, "validation fail: %s\n", condstr);
32*61046927SAndroid Build Coastguard Worker    if (ctx->current_instr) {
33*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "  -> for instruction: ");
34*61046927SAndroid Build Coastguard Worker       ir3_print_instr(ctx->current_instr);
35*61046927SAndroid Build Coastguard Worker    } else {
36*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "  -> for block%u\n", block_id(ctx->current_block));
37*61046927SAndroid Build Coastguard Worker    }
38*61046927SAndroid Build Coastguard Worker    abort();
39*61046927SAndroid Build Coastguard Worker }
40*61046927SAndroid Build Coastguard Worker 
41*61046927SAndroid Build Coastguard Worker #define validate_assert(ctx, cond)                                             \
42*61046927SAndroid Build Coastguard Worker    do {                                                                        \
43*61046927SAndroid Build Coastguard Worker       if (!(cond)) {                                                           \
44*61046927SAndroid Build Coastguard Worker          validate_error(ctx, #cond);                                           \
45*61046927SAndroid Build Coastguard Worker       }                                                                        \
46*61046927SAndroid Build Coastguard Worker    } while (0)
47*61046927SAndroid Build Coastguard Worker 
48*61046927SAndroid Build Coastguard Worker static unsigned
reg_class_flags(struct ir3_register * reg)49*61046927SAndroid Build Coastguard Worker reg_class_flags(struct ir3_register *reg)
50*61046927SAndroid Build Coastguard Worker {
51*61046927SAndroid Build Coastguard Worker    return reg->flags & (IR3_REG_HALF | IR3_REG_SHARED | IR3_REG_PREDICATE);
52*61046927SAndroid Build Coastguard Worker }
53*61046927SAndroid Build Coastguard Worker 
54*61046927SAndroid Build Coastguard Worker static void
validate_reg(struct ir3_validate_ctx * ctx,struct ir3_register * reg)55*61046927SAndroid Build Coastguard Worker validate_reg(struct ir3_validate_ctx *ctx, struct ir3_register *reg)
56*61046927SAndroid Build Coastguard Worker {
57*61046927SAndroid Build Coastguard Worker    if ((reg->flags & IR3_REG_SHARED) && reg->num != INVALID_REG) {
58*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg->num >= SHARED_REG_START);
59*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg->num - SHARED_REG_START < SHARED_REG_SIZE);
60*61046927SAndroid Build Coastguard Worker    }
61*61046927SAndroid Build Coastguard Worker }
62*61046927SAndroid Build Coastguard Worker 
63*61046927SAndroid Build Coastguard Worker static void
validate_src(struct ir3_validate_ctx * ctx,struct ir3_instruction * instr,struct ir3_register * reg)64*61046927SAndroid Build Coastguard Worker validate_src(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr,
65*61046927SAndroid Build Coastguard Worker              struct ir3_register *reg)
66*61046927SAndroid Build Coastguard Worker {
67*61046927SAndroid Build Coastguard Worker    if (reg->flags & IR3_REG_IMMED)
68*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, ir3_valid_immediate(instr, reg->iim_val));
69*61046927SAndroid Build Coastguard Worker 
70*61046927SAndroid Build Coastguard Worker    if (!(reg->flags & IR3_REG_SSA) || !reg->def)
71*61046927SAndroid Build Coastguard Worker       return;
72*61046927SAndroid Build Coastguard Worker 
73*61046927SAndroid Build Coastguard Worker    if (reg->flags & IR3_REG_PREDICATE)
74*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, !(reg->flags & (IR3_REG_SHARED | IR3_REG_HALF)));
75*61046927SAndroid Build Coastguard Worker 
76*61046927SAndroid Build Coastguard Worker    struct ir3_register *src = reg->def;
77*61046927SAndroid Build Coastguard Worker 
78*61046927SAndroid Build Coastguard Worker    validate_assert(ctx, _mesa_set_search(ctx->defs, src->instr));
79*61046927SAndroid Build Coastguard Worker    validate_assert(ctx, src->wrmask == reg->wrmask);
80*61046927SAndroid Build Coastguard Worker    validate_assert(ctx, reg_class_flags(src) == reg_class_flags(reg));
81*61046927SAndroid Build Coastguard Worker 
82*61046927SAndroid Build Coastguard Worker    if (src->flags & IR3_REG_CONST)
83*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, !(src->flags & IR3_REG_SHARED));
84*61046927SAndroid Build Coastguard Worker 
85*61046927SAndroid Build Coastguard Worker    if (reg->tied) {
86*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg->tied->tied == reg);
87*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg_class_flags(reg) == reg_class_flags(reg->tied));
88*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, !(reg->flags & (IR3_REG_CONST | IR3_REG_IMMED)));
89*61046927SAndroid Build Coastguard Worker       bool found = false;
90*61046927SAndroid Build Coastguard Worker       foreach_dst (dst, instr) {
91*61046927SAndroid Build Coastguard Worker          if (dst == reg->tied) {
92*61046927SAndroid Build Coastguard Worker             found = true;
93*61046927SAndroid Build Coastguard Worker             break;
94*61046927SAndroid Build Coastguard Worker          }
95*61046927SAndroid Build Coastguard Worker       }
96*61046927SAndroid Build Coastguard Worker       validate_assert(ctx,
97*61046927SAndroid Build Coastguard Worker                       found && "tied register not in the same instruction");
98*61046927SAndroid Build Coastguard Worker    }
99*61046927SAndroid Build Coastguard Worker 
100*61046927SAndroid Build Coastguard Worker    validate_reg(ctx, reg);
101*61046927SAndroid Build Coastguard Worker }
102*61046927SAndroid Build Coastguard Worker 
103*61046927SAndroid Build Coastguard Worker /* phi sources are logically read at the end of the predecessor basic block,
104*61046927SAndroid Build Coastguard Worker  * and we have to validate them then in order to correctly validate that the
105*61046927SAndroid Build Coastguard Worker  * use comes after the definition for loop phis.
106*61046927SAndroid Build Coastguard Worker  */
107*61046927SAndroid Build Coastguard Worker static void
validate_phi_src(struct ir3_validate_ctx * ctx,struct ir3_block * block,struct ir3_block * pred)108*61046927SAndroid Build Coastguard Worker validate_phi_src(struct ir3_validate_ctx *ctx, struct ir3_block *block,
109*61046927SAndroid Build Coastguard Worker                  struct ir3_block *pred)
110*61046927SAndroid Build Coastguard Worker {
111*61046927SAndroid Build Coastguard Worker    unsigned pred_idx = ir3_block_get_pred_index(block, pred);
112*61046927SAndroid Build Coastguard Worker 
113*61046927SAndroid Build Coastguard Worker    foreach_instr (phi, &block->instr_list) {
114*61046927SAndroid Build Coastguard Worker       if (phi->opc != OPC_META_PHI)
115*61046927SAndroid Build Coastguard Worker          break;
116*61046927SAndroid Build Coastguard Worker 
117*61046927SAndroid Build Coastguard Worker       ctx->current_instr = phi;
118*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, phi->srcs_count == block->predecessors_count);
119*61046927SAndroid Build Coastguard Worker       validate_src(ctx, phi, phi->srcs[pred_idx]);
120*61046927SAndroid Build Coastguard Worker    }
121*61046927SAndroid Build Coastguard Worker }
122*61046927SAndroid Build Coastguard Worker 
123*61046927SAndroid Build Coastguard Worker static void
validate_phi(struct ir3_validate_ctx * ctx,struct ir3_instruction * phi)124*61046927SAndroid Build Coastguard Worker validate_phi(struct ir3_validate_ctx *ctx, struct ir3_instruction *phi)
125*61046927SAndroid Build Coastguard Worker {
126*61046927SAndroid Build Coastguard Worker    _mesa_set_add(ctx->defs, phi);
127*61046927SAndroid Build Coastguard Worker    validate_assert(ctx, phi->dsts_count == 1);
128*61046927SAndroid Build Coastguard Worker    validate_assert(ctx, is_dest_gpr(phi->dsts[0]));
129*61046927SAndroid Build Coastguard Worker }
130*61046927SAndroid Build Coastguard Worker 
131*61046927SAndroid Build Coastguard Worker static void
validate_dst(struct ir3_validate_ctx * ctx,struct ir3_instruction * instr,struct ir3_register * reg)132*61046927SAndroid Build Coastguard Worker validate_dst(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr,
133*61046927SAndroid Build Coastguard Worker              struct ir3_register *reg)
134*61046927SAndroid Build Coastguard Worker {
135*61046927SAndroid Build Coastguard Worker    if (reg->tied) {
136*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg->tied->tied == reg);
137*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg_class_flags(reg->tied) == reg_class_flags(reg));
138*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg->tied->wrmask == reg->wrmask);
139*61046927SAndroid Build Coastguard Worker       if (reg->flags & IR3_REG_ARRAY) {
140*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg->tied->array.base == reg->array.base);
141*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg->tied->size == reg->size);
142*61046927SAndroid Build Coastguard Worker       }
143*61046927SAndroid Build Coastguard Worker       bool found = false;
144*61046927SAndroid Build Coastguard Worker       foreach_src (src, instr) {
145*61046927SAndroid Build Coastguard Worker          if (src == reg->tied) {
146*61046927SAndroid Build Coastguard Worker             found = true;
147*61046927SAndroid Build Coastguard Worker             break;
148*61046927SAndroid Build Coastguard Worker          }
149*61046927SAndroid Build Coastguard Worker       }
150*61046927SAndroid Build Coastguard Worker       validate_assert(ctx,
151*61046927SAndroid Build Coastguard Worker                       found && "tied register not in the same instruction");
152*61046927SAndroid Build Coastguard Worker    }
153*61046927SAndroid Build Coastguard Worker 
154*61046927SAndroid Build Coastguard Worker    if (reg->flags & IR3_REG_SSA)
155*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, reg->instr == instr);
156*61046927SAndroid Build Coastguard Worker 
157*61046927SAndroid Build Coastguard Worker    if (reg->flags & IR3_REG_RELATIV)
158*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, instr->address);
159*61046927SAndroid Build Coastguard Worker 
160*61046927SAndroid Build Coastguard Worker    validate_reg(ctx, reg);
161*61046927SAndroid Build Coastguard Worker }
162*61046927SAndroid Build Coastguard Worker 
163*61046927SAndroid Build Coastguard Worker #define validate_reg_size(ctx, reg, type)                                      \
164*61046927SAndroid Build Coastguard Worker    validate_assert(                                                            \
165*61046927SAndroid Build Coastguard Worker       ctx, (type_size(type) <= 16) == !!((reg)->flags & IR3_REG_HALF))
166*61046927SAndroid Build Coastguard Worker 
167*61046927SAndroid Build Coastguard Worker static bool
block_contains(struct ir3_block * block,struct ir3_instruction * instr)168*61046927SAndroid Build Coastguard Worker block_contains(struct ir3_block *block, struct ir3_instruction *instr)
169*61046927SAndroid Build Coastguard Worker {
170*61046927SAndroid Build Coastguard Worker    foreach_instr (block_instr, &block->instr_list) {
171*61046927SAndroid Build Coastguard Worker       if (block_instr == instr)
172*61046927SAndroid Build Coastguard Worker          return true;
173*61046927SAndroid Build Coastguard Worker    }
174*61046927SAndroid Build Coastguard Worker 
175*61046927SAndroid Build Coastguard Worker    return false;
176*61046927SAndroid Build Coastguard Worker }
177*61046927SAndroid Build Coastguard Worker 
178*61046927SAndroid Build Coastguard Worker static void
validate_rpt(struct ir3_validate_ctx * ctx,struct ir3_instruction * instr)179*61046927SAndroid Build Coastguard Worker validate_rpt(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr)
180*61046927SAndroid Build Coastguard Worker {
181*61046927SAndroid Build Coastguard Worker    if (ir3_instr_is_first_rpt(instr)) {
182*61046927SAndroid Build Coastguard Worker       /* All instructions in a repeat group should be in the same block as the
183*61046927SAndroid Build Coastguard Worker        * first one.
184*61046927SAndroid Build Coastguard Worker        */
185*61046927SAndroid Build Coastguard Worker       foreach_instr_rpt (rpt, instr) {
186*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, rpt->block == instr->block);
187*61046927SAndroid Build Coastguard Worker 
188*61046927SAndroid Build Coastguard Worker          /* Validate that the block actually contains the repeat. This would
189*61046927SAndroid Build Coastguard Worker           * fail if, for example, list_delinit is called instead of
190*61046927SAndroid Build Coastguard Worker           * ir3_instr_remove.
191*61046927SAndroid Build Coastguard Worker           */
192*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, block_contains(instr->block, rpt));
193*61046927SAndroid Build Coastguard Worker       }
194*61046927SAndroid Build Coastguard Worker    } else if (instr->repeat) {
195*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, ir3_supports_rpt(ctx->ir->compiler, instr->opc));
196*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, !instr->nop);
197*61046927SAndroid Build Coastguard Worker    }
198*61046927SAndroid Build Coastguard Worker }
199*61046927SAndroid Build Coastguard Worker 
200*61046927SAndroid Build Coastguard Worker static void
validate_instr(struct ir3_validate_ctx * ctx,struct ir3_instruction * instr)201*61046927SAndroid Build Coastguard Worker validate_instr(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr)
202*61046927SAndroid Build Coastguard Worker {
203*61046927SAndroid Build Coastguard Worker    struct ir3_register *last_reg = NULL;
204*61046927SAndroid Build Coastguard Worker 
205*61046927SAndroid Build Coastguard Worker    validate_rpt(ctx, instr);
206*61046927SAndroid Build Coastguard Worker 
207*61046927SAndroid Build Coastguard Worker    foreach_src_n (reg, n, instr) {
208*61046927SAndroid Build Coastguard Worker       if (reg->flags & IR3_REG_RELATIV)
209*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->address);
210*61046927SAndroid Build Coastguard Worker 
211*61046927SAndroid Build Coastguard Worker       validate_src(ctx, instr, reg);
212*61046927SAndroid Build Coastguard Worker 
213*61046927SAndroid Build Coastguard Worker       /* Validate that all src's are either half of full.
214*61046927SAndroid Build Coastguard Worker        *
215*61046927SAndroid Build Coastguard Worker        * Note: tex instructions w/ .s2en are a bit special in that the
216*61046927SAndroid Build Coastguard Worker        * tex/samp src reg is half-reg for non-bindless and full for
217*61046927SAndroid Build Coastguard Worker        * bindless, irrespective of the precision of other srcs. The
218*61046927SAndroid Build Coastguard Worker        * tex/samp src is the first src reg when .s2en is set
219*61046927SAndroid Build Coastguard Worker        */
220*61046927SAndroid Build Coastguard Worker       if (reg->tied) {
221*61046927SAndroid Build Coastguard Worker          /* must have the same size as the destination, handled in
222*61046927SAndroid Build Coastguard Worker           * validate_reg().
223*61046927SAndroid Build Coastguard Worker           */
224*61046927SAndroid Build Coastguard Worker       } else if (reg == instr->address) {
225*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg->flags & IR3_REG_HALF);
226*61046927SAndroid Build Coastguard Worker       } else if ((instr->flags & IR3_INSTR_S2EN) && (n < 2)) {
227*61046927SAndroid Build Coastguard Worker          if (n == 0) {
228*61046927SAndroid Build Coastguard Worker             if (instr->flags & IR3_INSTR_B)
229*61046927SAndroid Build Coastguard Worker                validate_assert(ctx, !(reg->flags & IR3_REG_HALF));
230*61046927SAndroid Build Coastguard Worker             else
231*61046927SAndroid Build Coastguard Worker                validate_assert(ctx, reg->flags & IR3_REG_HALF);
232*61046927SAndroid Build Coastguard Worker          }
233*61046927SAndroid Build Coastguard Worker       } else if (opc_cat(instr->opc) == 1 || opc_cat(instr->opc) == 6) {
234*61046927SAndroid Build Coastguard Worker          /* handled below */
235*61046927SAndroid Build Coastguard Worker       } else if (opc_cat(instr->opc) == 0) {
236*61046927SAndroid Build Coastguard Worker          /* end/chmask/etc are allowed to have different size sources */
237*61046927SAndroid Build Coastguard Worker       } else if (instr->opc == OPC_META_PARALLEL_COPY) {
238*61046927SAndroid Build Coastguard Worker          /* pcopy sources have to match with their destination but can have
239*61046927SAndroid Build Coastguard Worker           * different sizes from each other.
240*61046927SAndroid Build Coastguard Worker           */
241*61046927SAndroid Build Coastguard Worker       } else if (instr->opc == OPC_ANY_MACRO || instr->opc == OPC_ALL_MACRO ||
242*61046927SAndroid Build Coastguard Worker                  instr->opc == OPC_READ_FIRST_MACRO ||
243*61046927SAndroid Build Coastguard Worker                  instr->opc == OPC_READ_COND_MACRO) {
244*61046927SAndroid Build Coastguard Worker          /* nothing yet */
245*61046927SAndroid Build Coastguard Worker       } else if (n > 0) {
246*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, (last_reg->flags & IR3_REG_HALF) ==
247*61046927SAndroid Build Coastguard Worker                                  (reg->flags & IR3_REG_HALF));
248*61046927SAndroid Build Coastguard Worker       }
249*61046927SAndroid Build Coastguard Worker 
250*61046927SAndroid Build Coastguard Worker       if (is_scalar_alu(instr, ctx->ir->compiler) && reg != instr->address)
251*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg->flags & (IR3_REG_SHARED | IR3_REG_IMMED |
252*61046927SAndroid Build Coastguard Worker                                             IR3_REG_CONST));
253*61046927SAndroid Build Coastguard Worker 
254*61046927SAndroid Build Coastguard Worker       last_reg = reg;
255*61046927SAndroid Build Coastguard Worker    }
256*61046927SAndroid Build Coastguard Worker 
257*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < instr->dsts_count; i++) {
258*61046927SAndroid Build Coastguard Worker       struct ir3_register *reg = instr->dsts[i];
259*61046927SAndroid Build Coastguard Worker 
260*61046927SAndroid Build Coastguard Worker       validate_dst(ctx, instr, reg);
261*61046927SAndroid Build Coastguard Worker    }
262*61046927SAndroid Build Coastguard Worker 
263*61046927SAndroid Build Coastguard Worker    _mesa_set_add(ctx->defs, instr);
264*61046927SAndroid Build Coastguard Worker 
265*61046927SAndroid Build Coastguard Worker    if ((opc_cat(instr->opc) == 2 || opc_cat(instr->opc) == 3 ||
266*61046927SAndroid Build Coastguard Worker         opc_cat(instr->opc) == 4)) {
267*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, !(instr->dsts[0]->flags & IR3_REG_SHARED) ||
268*61046927SAndroid Build Coastguard Worker                       ctx->ir->compiler->has_scalar_alu);
269*61046927SAndroid Build Coastguard Worker    }
270*61046927SAndroid Build Coastguard Worker 
271*61046927SAndroid Build Coastguard Worker    /* Check that src/dst types match the register types, and for
272*61046927SAndroid Build Coastguard Worker     * instructions that have different opcodes depending on type,
273*61046927SAndroid Build Coastguard Worker     * that the opcodes are correct.
274*61046927SAndroid Build Coastguard Worker     */
275*61046927SAndroid Build Coastguard Worker    switch (opc_cat(instr->opc)) {
276*61046927SAndroid Build Coastguard Worker    case 1: /* move instructions */
277*61046927SAndroid Build Coastguard Worker       if (instr->opc == OPC_MOVMSK || instr->opc == OPC_BALLOT_MACRO) {
278*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->dsts_count == 1);
279*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->dsts[0]->flags & IR3_REG_SHARED);
280*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->dsts[0]->flags & IR3_REG_HALF));
281*61046927SAndroid Build Coastguard Worker          validate_assert(
282*61046927SAndroid Build Coastguard Worker             ctx, util_is_power_of_two_or_zero(instr->dsts[0]->wrmask + 1));
283*61046927SAndroid Build Coastguard Worker       } else if (instr->opc == OPC_ANY_MACRO || instr->opc == OPC_ALL_MACRO ||
284*61046927SAndroid Build Coastguard Worker                  instr->opc == OPC_READ_FIRST_MACRO ||
285*61046927SAndroid Build Coastguard Worker                  instr->opc == OPC_READ_COND_MACRO) {
286*61046927SAndroid Build Coastguard Worker          /* nothing yet */
287*61046927SAndroid Build Coastguard Worker       } else if (instr->opc == OPC_ELECT_MACRO || instr->opc == OPC_SHPS_MACRO) {
288*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->dsts_count == 1);
289*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->dsts[0]->flags & IR3_REG_SHARED));
290*61046927SAndroid Build Coastguard Worker       } else if (instr->opc == OPC_SCAN_MACRO) {
291*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->dsts_count == 3);
292*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->srcs_count == 2);
293*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg_class_flags(instr->dsts[0]) ==
294*61046927SAndroid Build Coastguard Worker                               reg_class_flags(instr->srcs[0]));
295*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg_class_flags(instr->dsts[1]) ==
296*61046927SAndroid Build Coastguard Worker                               reg_class_flags(instr->srcs[0]));
297*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg_class_flags(instr->dsts[2]) == IR3_REG_SHARED);
298*61046927SAndroid Build Coastguard Worker       } else if (instr->opc == OPC_SCAN_CLUSTERS_MACRO) {
299*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->dsts_count >= 2 && instr->dsts_count < 5);
300*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->srcs_count >= 2 && instr->srcs_count < 4);
301*61046927SAndroid Build Coastguard Worker          validate_assert(ctx,
302*61046927SAndroid Build Coastguard Worker                          reg_class_flags(instr->dsts[0]) == IR3_REG_SHARED);
303*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, reg_class_flags(instr->dsts[1]) ==
304*61046927SAndroid Build Coastguard Worker                                  reg_class_flags(instr->srcs[1]));
305*61046927SAndroid Build Coastguard Worker 
306*61046927SAndroid Build Coastguard Worker          /* exclusive scan */
307*61046927SAndroid Build Coastguard Worker          if (instr->srcs_count == 3) {
308*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, instr->dsts_count >= 3);
309*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, reg_class_flags(instr->srcs[2]) ==
310*61046927SAndroid Build Coastguard Worker                                     reg_class_flags(instr->srcs[1]));
311*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, reg_class_flags(instr->dsts[2]) ==
312*61046927SAndroid Build Coastguard Worker                                     reg_class_flags(instr->srcs[1]));
313*61046927SAndroid Build Coastguard Worker          }
314*61046927SAndroid Build Coastguard Worker 
315*61046927SAndroid Build Coastguard Worker          /* scratch register */
316*61046927SAndroid Build Coastguard Worker          validate_assert(ctx,
317*61046927SAndroid Build Coastguard Worker                          reg_class_flags(instr->dsts[instr->dsts_count - 1]) ==
318*61046927SAndroid Build Coastguard Worker                             reg_class_flags(instr->srcs[1]));
319*61046927SAndroid Build Coastguard Worker       } else {
320*61046927SAndroid Build Coastguard Worker          foreach_dst (dst, instr)
321*61046927SAndroid Build Coastguard Worker             validate_reg_size(ctx, dst, instr->cat1.dst_type);
322*61046927SAndroid Build Coastguard Worker          foreach_src (src, instr) {
323*61046927SAndroid Build Coastguard Worker             if (!src->tied && src != instr->address)
324*61046927SAndroid Build Coastguard Worker                validate_reg_size(ctx, src, instr->cat1.src_type);
325*61046927SAndroid Build Coastguard Worker          }
326*61046927SAndroid Build Coastguard Worker 
327*61046927SAndroid Build Coastguard Worker          switch (instr->opc) {
328*61046927SAndroid Build Coastguard Worker          case OPC_SWZ:
329*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, instr->srcs_count == 2);
330*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, instr->dsts_count == 2);
331*61046927SAndroid Build Coastguard Worker             break;
332*61046927SAndroid Build Coastguard Worker          case OPC_GAT:
333*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, instr->srcs_count == 4);
334*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, instr->dsts_count == 1);
335*61046927SAndroid Build Coastguard Worker             break;
336*61046927SAndroid Build Coastguard Worker          case OPC_SCT:
337*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, instr->srcs_count == 1);
338*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, instr->dsts_count == 4);
339*61046927SAndroid Build Coastguard Worker             break;
340*61046927SAndroid Build Coastguard Worker          default:
341*61046927SAndroid Build Coastguard Worker             break;
342*61046927SAndroid Build Coastguard Worker          }
343*61046927SAndroid Build Coastguard Worker       }
344*61046927SAndroid Build Coastguard Worker 
345*61046927SAndroid Build Coastguard Worker       if (instr->opc != OPC_MOV)
346*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !instr->address);
347*61046927SAndroid Build Coastguard Worker 
348*61046927SAndroid Build Coastguard Worker       break;
349*61046927SAndroid Build Coastguard Worker    case 3:
350*61046927SAndroid Build Coastguard Worker       /* Validate that cat3 opc matches the src type.  We've already checked
351*61046927SAndroid Build Coastguard Worker        * that all the src regs are same type
352*61046927SAndroid Build Coastguard Worker        */
353*61046927SAndroid Build Coastguard Worker       if (instr->srcs[0]->flags & IR3_REG_HALF) {
354*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->opc == cat3_half_opc(instr->opc));
355*61046927SAndroid Build Coastguard Worker       } else {
356*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->opc == cat3_full_opc(instr->opc));
357*61046927SAndroid Build Coastguard Worker       }
358*61046927SAndroid Build Coastguard Worker       break;
359*61046927SAndroid Build Coastguard Worker    case 4:
360*61046927SAndroid Build Coastguard Worker       /* Validate that cat4 opc matches the dst type: */
361*61046927SAndroid Build Coastguard Worker       if (instr->dsts[0]->flags & IR3_REG_HALF) {
362*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->opc == cat4_half_opc(instr->opc));
363*61046927SAndroid Build Coastguard Worker       } else {
364*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->opc == cat4_full_opc(instr->opc));
365*61046927SAndroid Build Coastguard Worker       }
366*61046927SAndroid Build Coastguard Worker       break;
367*61046927SAndroid Build Coastguard Worker    case 5:
368*61046927SAndroid Build Coastguard Worker       validate_reg_size(ctx, instr->dsts[0], instr->cat5.type);
369*61046927SAndroid Build Coastguard Worker       break;
370*61046927SAndroid Build Coastguard Worker    case 6:
371*61046927SAndroid Build Coastguard Worker       switch (instr->opc) {
372*61046927SAndroid Build Coastguard Worker       case OPC_RESINFO:
373*61046927SAndroid Build Coastguard Worker       case OPC_RESFMT:
374*61046927SAndroid Build Coastguard Worker          if (instr->dsts_count > 0)
375*61046927SAndroid Build Coastguard Worker             validate_reg_size(ctx, instr->dsts[0], instr->cat6.type);
376*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->srcs[0], instr->cat6.type);
377*61046927SAndroid Build Coastguard Worker          break;
378*61046927SAndroid Build Coastguard Worker       case OPC_L2G:
379*61046927SAndroid Build Coastguard Worker       case OPC_G2L:
380*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->dsts[0]->flags & IR3_REG_HALF));
381*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
382*61046927SAndroid Build Coastguard Worker          break;
383*61046927SAndroid Build Coastguard Worker       case OPC_STG:
384*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
385*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[1]->flags & IR3_REG_HALF));
386*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->srcs[2], instr->cat6.type);
387*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[3]->flags & IR3_REG_HALF));
388*61046927SAndroid Build Coastguard Worker          break;
389*61046927SAndroid Build Coastguard Worker       case OPC_STG_A:
390*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
391*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[2]->flags & IR3_REG_HALF));
392*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[3]->flags & IR3_REG_HALF));
393*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->srcs[4], instr->cat6.type);
394*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[5]->flags & IR3_REG_HALF));
395*61046927SAndroid Build Coastguard Worker          break;
396*61046927SAndroid Build Coastguard Worker       case OPC_STL:
397*61046927SAndroid Build Coastguard Worker       case OPC_STP:
398*61046927SAndroid Build Coastguard Worker       case OPC_STLW:
399*61046927SAndroid Build Coastguard Worker       case OPC_SPILL_MACRO:
400*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
401*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->srcs[1], instr->cat6.type);
402*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[2]->flags & IR3_REG_HALF));
403*61046927SAndroid Build Coastguard Worker          break;
404*61046927SAndroid Build Coastguard Worker       case OPC_STIB:
405*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
406*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[1]->flags & IR3_REG_HALF));
407*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->srcs[3], instr->cat6.type);
408*61046927SAndroid Build Coastguard Worker          break;
409*61046927SAndroid Build Coastguard Worker       case OPC_GETFIBERID:
410*61046927SAndroid Build Coastguard Worker       case OPC_GETSPID:
411*61046927SAndroid Build Coastguard Worker       case OPC_GETWID:
412*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->dsts[0], instr->cat6.type);
413*61046927SAndroid Build Coastguard Worker          break;
414*61046927SAndroid Build Coastguard Worker       case OPC_STC:
415*61046927SAndroid Build Coastguard Worker       case OPC_STSC:
416*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->srcs[0], instr->cat6.type);
417*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[1]->flags & IR3_REG_HALF));
418*61046927SAndroid Build Coastguard Worker          break;
419*61046927SAndroid Build Coastguard Worker       case OPC_PUSH_CONSTS_LOAD_MACRO:
420*61046927SAndroid Build Coastguard Worker          break;
421*61046927SAndroid Build Coastguard Worker       case OPC_LDC:
422*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
423*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[1]->flags & IR3_REG_HALF));
424*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !!(instr->dsts[0]->flags & IR3_REG_SHARED) ==
425*61046927SAndroid Build Coastguard Worker                               !!(instr->flags & IR3_INSTR_U));
426*61046927SAndroid Build Coastguard Worker          break;
427*61046927SAndroid Build Coastguard Worker       case OPC_LDC_K:
428*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
429*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[1]->flags & IR3_REG_HALF));
430*61046927SAndroid Build Coastguard Worker          break;
431*61046927SAndroid Build Coastguard Worker       case OPC_LDP:
432*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
433*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[1]->flags & IR3_REG_HALF));
434*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[2]->flags & IR3_REG_HALF));
435*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->dsts[0], instr->cat6.type);
436*61046927SAndroid Build Coastguard Worker          break;
437*61046927SAndroid Build Coastguard Worker       default:
438*61046927SAndroid Build Coastguard Worker          validate_reg_size(ctx, instr->dsts[0], instr->cat6.type);
439*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, !(instr->srcs[0]->flags & IR3_REG_HALF));
440*61046927SAndroid Build Coastguard Worker          if (instr->srcs_count > 1)
441*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, !(instr->srcs[1]->flags & IR3_REG_HALF));
442*61046927SAndroid Build Coastguard Worker          break;
443*61046927SAndroid Build Coastguard Worker       }
444*61046927SAndroid Build Coastguard Worker    }
445*61046927SAndroid Build Coastguard Worker 
446*61046927SAndroid Build Coastguard Worker    if (instr->opc == OPC_META_PARALLEL_COPY) {
447*61046927SAndroid Build Coastguard Worker       foreach_src_n (src, n, instr) {
448*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, (src->flags & IR3_REG_HALF) ==
449*61046927SAndroid Build Coastguard Worker                          (instr->dsts[n]->flags & IR3_REG_HALF));
450*61046927SAndroid Build Coastguard Worker          if (instr->dsts[n]->flags & IR3_REG_SHARED) {
451*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, src->flags & (IR3_REG_SHARED | IR3_REG_CONST |
452*61046927SAndroid Build Coastguard Worker                                                IR3_REG_IMMED));
453*61046927SAndroid Build Coastguard Worker          } else {
454*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, !(src->flags & IR3_REG_SHARED));
455*61046927SAndroid Build Coastguard Worker          }
456*61046927SAndroid Build Coastguard Worker       }
457*61046927SAndroid Build Coastguard Worker    }
458*61046927SAndroid Build Coastguard Worker }
459*61046927SAndroid Build Coastguard Worker 
460*61046927SAndroid Build Coastguard Worker static bool
is_physical_successor(struct ir3_block * block,struct ir3_block * succ)461*61046927SAndroid Build Coastguard Worker is_physical_successor(struct ir3_block *block, struct ir3_block *succ)
462*61046927SAndroid Build Coastguard Worker {
463*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < block->physical_successors_count; i++)
464*61046927SAndroid Build Coastguard Worker       if (block->physical_successors[i] == succ)
465*61046927SAndroid Build Coastguard Worker          return true;
466*61046927SAndroid Build Coastguard Worker    return false;
467*61046927SAndroid Build Coastguard Worker }
468*61046927SAndroid Build Coastguard Worker 
469*61046927SAndroid Build Coastguard Worker void
ir3_validate(struct ir3 * ir)470*61046927SAndroid Build Coastguard Worker ir3_validate(struct ir3 *ir)
471*61046927SAndroid Build Coastguard Worker {
472*61046927SAndroid Build Coastguard Worker #ifdef NDEBUG
473*61046927SAndroid Build Coastguard Worker #define VALIDATE 0
474*61046927SAndroid Build Coastguard Worker #else
475*61046927SAndroid Build Coastguard Worker #define VALIDATE 1
476*61046927SAndroid Build Coastguard Worker #endif
477*61046927SAndroid Build Coastguard Worker 
478*61046927SAndroid Build Coastguard Worker    if (!VALIDATE)
479*61046927SAndroid Build Coastguard Worker       return;
480*61046927SAndroid Build Coastguard Worker 
481*61046927SAndroid Build Coastguard Worker    struct ir3_validate_ctx *ctx = ralloc_size(NULL, sizeof(*ctx));
482*61046927SAndroid Build Coastguard Worker 
483*61046927SAndroid Build Coastguard Worker    ctx->ir = ir;
484*61046927SAndroid Build Coastguard Worker    ctx->defs = _mesa_pointer_set_create(ctx);
485*61046927SAndroid Build Coastguard Worker 
486*61046927SAndroid Build Coastguard Worker    foreach_block (block, &ir->block_list) {
487*61046927SAndroid Build Coastguard Worker       ctx->current_block = block;
488*61046927SAndroid Build Coastguard Worker       ctx->current_instr = NULL;
489*61046927SAndroid Build Coastguard Worker 
490*61046927SAndroid Build Coastguard Worker       /* We require that the first block does not have any predecessors,
491*61046927SAndroid Build Coastguard Worker        * which allows us to assume that phi nodes and meta:input's do not
492*61046927SAndroid Build Coastguard Worker        * appear in the same basic block.
493*61046927SAndroid Build Coastguard Worker        */
494*61046927SAndroid Build Coastguard Worker       validate_assert(
495*61046927SAndroid Build Coastguard Worker          ctx, block != ir3_start_block(ir) || block->predecessors_count == 0);
496*61046927SAndroid Build Coastguard Worker 
497*61046927SAndroid Build Coastguard Worker       struct ir3_instruction *prev = NULL;
498*61046927SAndroid Build Coastguard Worker       foreach_instr (instr, &block->instr_list) {
499*61046927SAndroid Build Coastguard Worker          ctx->current_instr = instr;
500*61046927SAndroid Build Coastguard Worker          validate_assert(ctx, instr->block == block);
501*61046927SAndroid Build Coastguard Worker          if (instr->opc == OPC_META_PHI) {
502*61046927SAndroid Build Coastguard Worker             /* phis must be the first in the block */
503*61046927SAndroid Build Coastguard Worker             validate_assert(ctx, prev == NULL || prev->opc == OPC_META_PHI);
504*61046927SAndroid Build Coastguard Worker             validate_phi(ctx, instr);
505*61046927SAndroid Build Coastguard Worker          } else {
506*61046927SAndroid Build Coastguard Worker             validate_instr(ctx, instr);
507*61046927SAndroid Build Coastguard Worker          }
508*61046927SAndroid Build Coastguard Worker          prev = instr;
509*61046927SAndroid Build Coastguard Worker       }
510*61046927SAndroid Build Coastguard Worker 
511*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < 2; i++) {
512*61046927SAndroid Build Coastguard Worker          if (block->successors[i]) {
513*61046927SAndroid Build Coastguard Worker             validate_phi_src(ctx, block->successors[i], block);
514*61046927SAndroid Build Coastguard Worker 
515*61046927SAndroid Build Coastguard Worker             ctx->current_instr = NULL;
516*61046927SAndroid Build Coastguard Worker 
517*61046927SAndroid Build Coastguard Worker             /* Each logical successor should also be a physical successor: */
518*61046927SAndroid Build Coastguard Worker             if (block->physical_successors_count > 0)
519*61046927SAndroid Build Coastguard Worker                validate_assert(ctx, is_physical_successor(block, block->successors[i]));
520*61046927SAndroid Build Coastguard Worker          }
521*61046927SAndroid Build Coastguard Worker       }
522*61046927SAndroid Build Coastguard Worker 
523*61046927SAndroid Build Coastguard Worker       validate_assert(ctx, block->successors[0] || !block->successors[1]);
524*61046927SAndroid Build Coastguard Worker    }
525*61046927SAndroid Build Coastguard Worker 
526*61046927SAndroid Build Coastguard Worker    ralloc_free(ctx);
527*61046927SAndroid Build Coastguard Worker }
528