1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2022 Imagination Technologies Ltd.
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a copy
5*61046927SAndroid Build Coastguard Worker * of this software and associated documentation files (the "Software"), to deal
6*61046927SAndroid Build Coastguard Worker * in the Software without restriction, including without limitation the rights
7*61046927SAndroid Build Coastguard Worker * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8*61046927SAndroid Build Coastguard Worker * copies of the Software, and to permit persons to whom the Software is
9*61046927SAndroid Build Coastguard Worker * furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18*61046927SAndroid Build Coastguard Worker * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*61046927SAndroid Build Coastguard Worker * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*61046927SAndroid Build Coastguard Worker * SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #include "rogue.h"
25*61046927SAndroid Build Coastguard Worker #include "util/bitscan.h"
26*61046927SAndroid Build Coastguard Worker #include "util/macros.h"
27*61046927SAndroid Build Coastguard Worker #include "util/u_dynarray.h"
28*61046927SAndroid Build Coastguard Worker
29*61046927SAndroid Build Coastguard Worker #include <stdbool.h>
30*61046927SAndroid Build Coastguard Worker
31*61046927SAndroid Build Coastguard Worker /**
32*61046927SAndroid Build Coastguard Worker * \file rogue_validate.c
33*61046927SAndroid Build Coastguard Worker *
34*61046927SAndroid Build Coastguard Worker * \brief Contains functions to validate Rogue IR.
35*61046927SAndroid Build Coastguard Worker */
36*61046927SAndroid Build Coastguard Worker
37*61046927SAndroid Build Coastguard Worker /* TODO: Rogue_validate should make sure that immediate (sources) don't have any
38*61046927SAndroid Build Coastguard Worker * modifiers set... */
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker /* TODO NEXT: Check for emit/end/etc. as last instruction in vertex shader, and
41*61046927SAndroid Build Coastguard Worker * nop.end, or end flag set (or just pseudo-end) otherwise. */
42*61046927SAndroid Build Coastguard Worker
43*61046927SAndroid Build Coastguard Worker typedef struct rogue_validation_state {
44*61046927SAndroid Build Coastguard Worker const rogue_shader *shader; /** The shader being validated. */
45*61046927SAndroid Build Coastguard Worker const char *when; /** Description of the validation being done. */
46*61046927SAndroid Build Coastguard Worker bool nonfatal; /** Don't stop at the first error.*/
47*61046927SAndroid Build Coastguard Worker struct {
48*61046927SAndroid Build Coastguard Worker const rogue_block *block; /** Current basic block being validated. */
49*61046927SAndroid Build Coastguard Worker const rogue_instr *instr; /** Current instruction being validated. */
50*61046927SAndroid Build Coastguard Worker const rogue_instr_group *group; /** Current instruction group being
51*61046927SAndroid Build Coastguard Worker validated. */
52*61046927SAndroid Build Coastguard Worker const rogue_ref *ref; /** Current reference being validated. */
53*61046927SAndroid Build Coastguard Worker bool src; /** Current reference type (src/dst). */
54*61046927SAndroid Build Coastguard Worker unsigned param; /** Current reference src/dst index. */
55*61046927SAndroid Build Coastguard Worker } ctx;
56*61046927SAndroid Build Coastguard Worker struct util_dynarray *error_msgs; /** Error message list. */
57*61046927SAndroid Build Coastguard Worker } rogue_validation_state;
58*61046927SAndroid Build Coastguard Worker
59*61046927SAndroid Build Coastguard Worker /* Returns true if errors are present. */
validate_print_errors(rogue_validation_state * state)60*61046927SAndroid Build Coastguard Worker static bool validate_print_errors(rogue_validation_state *state)
61*61046927SAndroid Build Coastguard Worker {
62*61046927SAndroid Build Coastguard Worker if (!util_dynarray_num_elements(state->error_msgs, const char *))
63*61046927SAndroid Build Coastguard Worker return false;
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker util_dynarray_foreach (state->error_msgs, const char *, msg) {
66*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%s\n", *msg);
67*61046927SAndroid Build Coastguard Worker }
68*61046927SAndroid Build Coastguard Worker
69*61046927SAndroid Build Coastguard Worker fputs("\n", stderr);
70*61046927SAndroid Build Coastguard Worker
71*61046927SAndroid Build Coastguard Worker rogue_print_shader(stderr, state->shader);
72*61046927SAndroid Build Coastguard Worker fputs("\n", stderr);
73*61046927SAndroid Build Coastguard Worker
74*61046927SAndroid Build Coastguard Worker return true;
75*61046927SAndroid Build Coastguard Worker }
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Worker static void PRINTFLIKE(2, 3)
validate_log(rogue_validation_state * state,const char * fmt,...)78*61046927SAndroid Build Coastguard Worker validate_log(rogue_validation_state *state, const char *fmt, ...)
79*61046927SAndroid Build Coastguard Worker {
80*61046927SAndroid Build Coastguard Worker char *msg = ralloc_asprintf(state->error_msgs, "Validation error");
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Worker /* Add info about the item that was being validated. */
83*61046927SAndroid Build Coastguard Worker
84*61046927SAndroid Build Coastguard Worker if (state->ctx.block) {
85*61046927SAndroid Build Coastguard Worker if (state->ctx.block->label)
86*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&msg, " block \"%s\"", state->ctx.block->label);
87*61046927SAndroid Build Coastguard Worker else
88*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&msg, " block%u", state->ctx.block->index);
89*61046927SAndroid Build Coastguard Worker }
90*61046927SAndroid Build Coastguard Worker
91*61046927SAndroid Build Coastguard Worker if (state->ctx.instr) {
92*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&msg, " instr %u", state->ctx.instr->index);
93*61046927SAndroid Build Coastguard Worker }
94*61046927SAndroid Build Coastguard Worker
95*61046927SAndroid Build Coastguard Worker if (state->ctx.ref) {
96*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&msg,
97*61046927SAndroid Build Coastguard Worker " %s %u",
98*61046927SAndroid Build Coastguard Worker state->ctx.src ? "src" : "dst",
99*61046927SAndroid Build Coastguard Worker state->ctx.param);
100*61046927SAndroid Build Coastguard Worker }
101*61046927SAndroid Build Coastguard Worker
102*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&msg, ": ");
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker va_list args;
105*61046927SAndroid Build Coastguard Worker va_start(args, fmt);
106*61046927SAndroid Build Coastguard Worker ralloc_vasprintf_append(&msg, fmt, args);
107*61046927SAndroid Build Coastguard Worker util_dynarray_append(state->error_msgs, const char *, msg);
108*61046927SAndroid Build Coastguard Worker va_end(args);
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker if (!state->nonfatal) {
111*61046927SAndroid Build Coastguard Worker validate_print_errors(state);
112*61046927SAndroid Build Coastguard Worker abort();
113*61046927SAndroid Build Coastguard Worker }
114*61046927SAndroid Build Coastguard Worker }
115*61046927SAndroid Build Coastguard Worker
116*61046927SAndroid Build Coastguard Worker static rogue_validation_state *
create_validation_state(const rogue_shader * shader,const char * when)117*61046927SAndroid Build Coastguard Worker create_validation_state(const rogue_shader *shader, const char *when)
118*61046927SAndroid Build Coastguard Worker {
119*61046927SAndroid Build Coastguard Worker rogue_validation_state *state = rzalloc_size(shader, sizeof(*state));
120*61046927SAndroid Build Coastguard Worker
121*61046927SAndroid Build Coastguard Worker state->shader = shader;
122*61046927SAndroid Build Coastguard Worker state->when = when;
123*61046927SAndroid Build Coastguard Worker state->nonfatal = ROGUE_DEBUG(VLD_NONFATAL);
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Worker state->error_msgs = rzalloc_size(state, sizeof(*state->error_msgs));
126*61046927SAndroid Build Coastguard Worker util_dynarray_init(state->error_msgs, state);
127*61046927SAndroid Build Coastguard Worker
128*61046927SAndroid Build Coastguard Worker return state;
129*61046927SAndroid Build Coastguard Worker }
130*61046927SAndroid Build Coastguard Worker
validate_regarray(rogue_validation_state * state,rogue_regarray * regarray)131*61046927SAndroid Build Coastguard Worker static void validate_regarray(rogue_validation_state *state,
132*61046927SAndroid Build Coastguard Worker rogue_regarray *regarray)
133*61046927SAndroid Build Coastguard Worker {
134*61046927SAndroid Build Coastguard Worker if (!regarray->size) {
135*61046927SAndroid Build Coastguard Worker validate_log(state, "Register array is empty.");
136*61046927SAndroid Build Coastguard Worker return;
137*61046927SAndroid Build Coastguard Worker }
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker enum rogue_reg_class class = regarray->regs[0]->class;
140*61046927SAndroid Build Coastguard Worker unsigned base_index = regarray->regs[0]->index;
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker for (unsigned u = 0; u < regarray->size; ++u) {
143*61046927SAndroid Build Coastguard Worker if (regarray->regs[u]->class != class)
144*61046927SAndroid Build Coastguard Worker validate_log(state, "Register class mismatch in register array.");
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker if (regarray->regs[u]->index != (base_index + u))
147*61046927SAndroid Build Coastguard Worker validate_log(state, "Non-contiguous registers in register array.");
148*61046927SAndroid Build Coastguard Worker }
149*61046927SAndroid Build Coastguard Worker }
150*61046927SAndroid Build Coastguard Worker
validate_dst(rogue_validation_state * state,const rogue_instr_dst * dst,uint64_t supported_dst_types,unsigned i,unsigned stride,unsigned repeat,uint64_t repeat_mask)151*61046927SAndroid Build Coastguard Worker static void validate_dst(rogue_validation_state *state,
152*61046927SAndroid Build Coastguard Worker const rogue_instr_dst *dst,
153*61046927SAndroid Build Coastguard Worker uint64_t supported_dst_types,
154*61046927SAndroid Build Coastguard Worker unsigned i,
155*61046927SAndroid Build Coastguard Worker unsigned stride,
156*61046927SAndroid Build Coastguard Worker unsigned repeat,
157*61046927SAndroid Build Coastguard Worker uint64_t repeat_mask)
158*61046927SAndroid Build Coastguard Worker {
159*61046927SAndroid Build Coastguard Worker state->ctx.ref = &dst->ref;
160*61046927SAndroid Build Coastguard Worker state->ctx.src = false;
161*61046927SAndroid Build Coastguard Worker state->ctx.param = i;
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker if (rogue_ref_is_null(&dst->ref))
164*61046927SAndroid Build Coastguard Worker validate_log(state, "Destination has not been set.");
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker if (!rogue_ref_type_supported(dst->ref.type, supported_dst_types))
167*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported destination type.");
168*61046927SAndroid Build Coastguard Worker
169*61046927SAndroid Build Coastguard Worker if (rogue_ref_is_reg_or_regarray(&dst->ref) && stride != ~0U) {
170*61046927SAndroid Build Coastguard Worker unsigned dst_size = stride + 1;
171*61046927SAndroid Build Coastguard Worker if (repeat_mask & (1 << i))
172*61046927SAndroid Build Coastguard Worker dst_size *= repeat;
173*61046927SAndroid Build Coastguard Worker
174*61046927SAndroid Build Coastguard Worker if (rogue_ref_is_regarray(&dst->ref)) {
175*61046927SAndroid Build Coastguard Worker if (rogue_ref_get_regarray_size(&dst->ref) != dst_size) {
176*61046927SAndroid Build Coastguard Worker validate_log(state,
177*61046927SAndroid Build Coastguard Worker "Expected regarray size %u, got %u.",
178*61046927SAndroid Build Coastguard Worker dst_size,
179*61046927SAndroid Build Coastguard Worker rogue_ref_get_regarray_size(&dst->ref));
180*61046927SAndroid Build Coastguard Worker }
181*61046927SAndroid Build Coastguard Worker } else if (dst_size > 1) {
182*61046927SAndroid Build Coastguard Worker validate_log(state, "Expected regarray type for destination.");
183*61046927SAndroid Build Coastguard Worker }
184*61046927SAndroid Build Coastguard Worker }
185*61046927SAndroid Build Coastguard Worker
186*61046927SAndroid Build Coastguard Worker state->ctx.ref = NULL;
187*61046927SAndroid Build Coastguard Worker }
188*61046927SAndroid Build Coastguard Worker
validate_src(rogue_validation_state * state,const rogue_instr_src * src,uint64_t supported_src_types,unsigned i,unsigned stride,unsigned repeat,uint64_t repeat_mask)189*61046927SAndroid Build Coastguard Worker static void validate_src(rogue_validation_state *state,
190*61046927SAndroid Build Coastguard Worker const rogue_instr_src *src,
191*61046927SAndroid Build Coastguard Worker uint64_t supported_src_types,
192*61046927SAndroid Build Coastguard Worker unsigned i,
193*61046927SAndroid Build Coastguard Worker unsigned stride,
194*61046927SAndroid Build Coastguard Worker unsigned repeat,
195*61046927SAndroid Build Coastguard Worker uint64_t repeat_mask)
196*61046927SAndroid Build Coastguard Worker {
197*61046927SAndroid Build Coastguard Worker state->ctx.ref = &src->ref;
198*61046927SAndroid Build Coastguard Worker state->ctx.src = true;
199*61046927SAndroid Build Coastguard Worker state->ctx.param = i;
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker if (rogue_ref_is_null(&src->ref))
202*61046927SAndroid Build Coastguard Worker validate_log(state, "Source has not been set.");
203*61046927SAndroid Build Coastguard Worker
204*61046927SAndroid Build Coastguard Worker if (!rogue_ref_type_supported(src->ref.type, supported_src_types))
205*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported source type.");
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker if (rogue_ref_is_reg_or_regarray(&src->ref) && stride != ~0U) {
208*61046927SAndroid Build Coastguard Worker unsigned src_size = stride + 1;
209*61046927SAndroid Build Coastguard Worker if (repeat_mask & (1 << i))
210*61046927SAndroid Build Coastguard Worker src_size *= repeat;
211*61046927SAndroid Build Coastguard Worker
212*61046927SAndroid Build Coastguard Worker if (rogue_ref_is_regarray(&src->ref)) {
213*61046927SAndroid Build Coastguard Worker if (rogue_ref_get_regarray_size(&src->ref) != src_size) {
214*61046927SAndroid Build Coastguard Worker validate_log(state,
215*61046927SAndroid Build Coastguard Worker "Expected regarray size %u, got %u.",
216*61046927SAndroid Build Coastguard Worker src_size,
217*61046927SAndroid Build Coastguard Worker rogue_ref_get_regarray_size(&src->ref));
218*61046927SAndroid Build Coastguard Worker }
219*61046927SAndroid Build Coastguard Worker } else if (src_size > 1) {
220*61046927SAndroid Build Coastguard Worker validate_log(state, "Expected regarray type for source.");
221*61046927SAndroid Build Coastguard Worker }
222*61046927SAndroid Build Coastguard Worker }
223*61046927SAndroid Build Coastguard Worker
224*61046927SAndroid Build Coastguard Worker state->ctx.ref = NULL;
225*61046927SAndroid Build Coastguard Worker }
226*61046927SAndroid Build Coastguard Worker
validate_alu_op_mod_combo(uint64_t mods)227*61046927SAndroid Build Coastguard Worker static bool validate_alu_op_mod_combo(uint64_t mods)
228*61046927SAndroid Build Coastguard Worker {
229*61046927SAndroid Build Coastguard Worker rogue_foreach_mod_in_set (mod, mods) {
230*61046927SAndroid Build Coastguard Worker const rogue_alu_op_mod_info *info = &rogue_alu_op_mod_infos[mod];
231*61046927SAndroid Build Coastguard Worker
232*61046927SAndroid Build Coastguard Worker /* Check if any excluded op mods have been included. */
233*61046927SAndroid Build Coastguard Worker if (info->exclude & mods)
234*61046927SAndroid Build Coastguard Worker return false;
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Worker /* Check if any required op mods have been missed. */
237*61046927SAndroid Build Coastguard Worker if (info->require && !(info->require & mods))
238*61046927SAndroid Build Coastguard Worker return false;
239*61046927SAndroid Build Coastguard Worker }
240*61046927SAndroid Build Coastguard Worker
241*61046927SAndroid Build Coastguard Worker return true;
242*61046927SAndroid Build Coastguard Worker }
243*61046927SAndroid Build Coastguard Worker
validate_alu_instr(rogue_validation_state * state,const rogue_alu_instr * alu)244*61046927SAndroid Build Coastguard Worker static void validate_alu_instr(rogue_validation_state *state,
245*61046927SAndroid Build Coastguard Worker const rogue_alu_instr *alu)
246*61046927SAndroid Build Coastguard Worker {
247*61046927SAndroid Build Coastguard Worker if (alu->op == ROGUE_ALU_OP_INVALID || alu->op >= ROGUE_ALU_OP_COUNT)
248*61046927SAndroid Build Coastguard Worker validate_log(state, "Unknown ALU op 0x%x encountered.", alu->op);
249*61046927SAndroid Build Coastguard Worker
250*61046927SAndroid Build Coastguard Worker const rogue_alu_op_info *info = &rogue_alu_op_infos[alu->op];
251*61046927SAndroid Build Coastguard Worker
252*61046927SAndroid Build Coastguard Worker /* Check if instruction modifiers are valid. */
253*61046927SAndroid Build Coastguard Worker if (!rogue_mods_supported(alu->mod, info->supported_op_mods))
254*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported ALU op modifiers.");
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker if (!validate_alu_op_mod_combo(alu->mod))
257*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported ALU op modifier combination.");
258*61046927SAndroid Build Coastguard Worker
259*61046927SAndroid Build Coastguard Worker /* Instruction repeat checks. */
260*61046927SAndroid Build Coastguard Worker if (alu->instr.repeat > 1 && !info->dst_repeat_mask &&
261*61046927SAndroid Build Coastguard Worker !info->src_repeat_mask) {
262*61046927SAndroid Build Coastguard Worker validate_log(state, "Repeat set for ALU op without repeat support.");
263*61046927SAndroid Build Coastguard Worker }
264*61046927SAndroid Build Coastguard Worker
265*61046927SAndroid Build Coastguard Worker /* Validate destinations and sources for ungrouped shaders. */
266*61046927SAndroid Build Coastguard Worker if (!state->shader->is_grouped) {
267*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_dsts; ++i) {
268*61046927SAndroid Build Coastguard Worker validate_dst(state,
269*61046927SAndroid Build Coastguard Worker &alu->dst[i],
270*61046927SAndroid Build Coastguard Worker info->supported_dst_types[i],
271*61046927SAndroid Build Coastguard Worker i,
272*61046927SAndroid Build Coastguard Worker info->dst_stride[i],
273*61046927SAndroid Build Coastguard Worker alu->instr.repeat,
274*61046927SAndroid Build Coastguard Worker info->dst_repeat_mask);
275*61046927SAndroid Build Coastguard Worker }
276*61046927SAndroid Build Coastguard Worker
277*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_srcs; ++i) {
278*61046927SAndroid Build Coastguard Worker validate_src(state,
279*61046927SAndroid Build Coastguard Worker &alu->src[i],
280*61046927SAndroid Build Coastguard Worker info->supported_src_types[i],
281*61046927SAndroid Build Coastguard Worker i,
282*61046927SAndroid Build Coastguard Worker info->src_stride[i],
283*61046927SAndroid Build Coastguard Worker alu->instr.repeat,
284*61046927SAndroid Build Coastguard Worker info->src_repeat_mask);
285*61046927SAndroid Build Coastguard Worker }
286*61046927SAndroid Build Coastguard Worker }
287*61046927SAndroid Build Coastguard Worker }
288*61046927SAndroid Build Coastguard Worker
validate_backend_op_mod_combo(uint64_t mods)289*61046927SAndroid Build Coastguard Worker static bool validate_backend_op_mod_combo(uint64_t mods)
290*61046927SAndroid Build Coastguard Worker {
291*61046927SAndroid Build Coastguard Worker rogue_foreach_mod_in_set (mod, mods) {
292*61046927SAndroid Build Coastguard Worker const rogue_backend_op_mod_info *info = &rogue_backend_op_mod_infos[mod];
293*61046927SAndroid Build Coastguard Worker
294*61046927SAndroid Build Coastguard Worker /* Check if any excluded op mods have been included. */
295*61046927SAndroid Build Coastguard Worker if (info->exclude & mods)
296*61046927SAndroid Build Coastguard Worker return false;
297*61046927SAndroid Build Coastguard Worker
298*61046927SAndroid Build Coastguard Worker /* Check if any required op mods have been missed. */
299*61046927SAndroid Build Coastguard Worker if (info->require && !(info->require & mods))
300*61046927SAndroid Build Coastguard Worker return false;
301*61046927SAndroid Build Coastguard Worker }
302*61046927SAndroid Build Coastguard Worker
303*61046927SAndroid Build Coastguard Worker return true;
304*61046927SAndroid Build Coastguard Worker }
305*61046927SAndroid Build Coastguard Worker
validate_backend_instr(rogue_validation_state * state,const rogue_backend_instr * backend)306*61046927SAndroid Build Coastguard Worker static void validate_backend_instr(rogue_validation_state *state,
307*61046927SAndroid Build Coastguard Worker const rogue_backend_instr *backend)
308*61046927SAndroid Build Coastguard Worker {
309*61046927SAndroid Build Coastguard Worker if (backend->op == ROGUE_BACKEND_OP_INVALID ||
310*61046927SAndroid Build Coastguard Worker backend->op >= ROGUE_BACKEND_OP_COUNT)
311*61046927SAndroid Build Coastguard Worker validate_log(state, "Unknown backend op 0x%x encountered.", backend->op);
312*61046927SAndroid Build Coastguard Worker
313*61046927SAndroid Build Coastguard Worker const rogue_backend_op_info *info = &rogue_backend_op_infos[backend->op];
314*61046927SAndroid Build Coastguard Worker
315*61046927SAndroid Build Coastguard Worker /* Check if instruction modifiers are valid. */
316*61046927SAndroid Build Coastguard Worker if (!rogue_mods_supported(backend->mod, info->supported_op_mods))
317*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported backend op modifiers.");
318*61046927SAndroid Build Coastguard Worker
319*61046927SAndroid Build Coastguard Worker if (!validate_backend_op_mod_combo(backend->mod))
320*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported backend op modifier combination.");
321*61046927SAndroid Build Coastguard Worker
322*61046927SAndroid Build Coastguard Worker /* Instruction repeat checks. */
323*61046927SAndroid Build Coastguard Worker if (backend->instr.repeat > 1 && !info->dst_repeat_mask &&
324*61046927SAndroid Build Coastguard Worker !info->src_repeat_mask) {
325*61046927SAndroid Build Coastguard Worker validate_log(state, "Repeat set for backend op without repeat support.");
326*61046927SAndroid Build Coastguard Worker }
327*61046927SAndroid Build Coastguard Worker
328*61046927SAndroid Build Coastguard Worker /* Validate destinations and sources for ungrouped shaders. */
329*61046927SAndroid Build Coastguard Worker if (!state->shader->is_grouped) {
330*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_dsts; ++i) {
331*61046927SAndroid Build Coastguard Worker validate_dst(state,
332*61046927SAndroid Build Coastguard Worker &backend->dst[i],
333*61046927SAndroid Build Coastguard Worker info->supported_dst_types[i],
334*61046927SAndroid Build Coastguard Worker i,
335*61046927SAndroid Build Coastguard Worker info->dst_stride[i],
336*61046927SAndroid Build Coastguard Worker backend->instr.repeat,
337*61046927SAndroid Build Coastguard Worker info->dst_repeat_mask);
338*61046927SAndroid Build Coastguard Worker }
339*61046927SAndroid Build Coastguard Worker
340*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_srcs; ++i) {
341*61046927SAndroid Build Coastguard Worker validate_src(state,
342*61046927SAndroid Build Coastguard Worker &backend->src[i],
343*61046927SAndroid Build Coastguard Worker info->supported_src_types[i],
344*61046927SAndroid Build Coastguard Worker i,
345*61046927SAndroid Build Coastguard Worker info->src_stride[i],
346*61046927SAndroid Build Coastguard Worker backend->instr.repeat,
347*61046927SAndroid Build Coastguard Worker info->src_repeat_mask);
348*61046927SAndroid Build Coastguard Worker }
349*61046927SAndroid Build Coastguard Worker }
350*61046927SAndroid Build Coastguard Worker }
351*61046927SAndroid Build Coastguard Worker
validate_ctrl_op_mod_combo(uint64_t mods)352*61046927SAndroid Build Coastguard Worker static bool validate_ctrl_op_mod_combo(uint64_t mods)
353*61046927SAndroid Build Coastguard Worker {
354*61046927SAndroid Build Coastguard Worker rogue_foreach_mod_in_set (mod, mods) {
355*61046927SAndroid Build Coastguard Worker const rogue_ctrl_op_mod_info *info = &rogue_ctrl_op_mod_infos[mod];
356*61046927SAndroid Build Coastguard Worker
357*61046927SAndroid Build Coastguard Worker /* Check if any excluded op mods have been included. */
358*61046927SAndroid Build Coastguard Worker if (info->exclude & mods)
359*61046927SAndroid Build Coastguard Worker return false;
360*61046927SAndroid Build Coastguard Worker
361*61046927SAndroid Build Coastguard Worker /* Check if any required op mods have been missed. */
362*61046927SAndroid Build Coastguard Worker if (info->require && !(info->require & mods))
363*61046927SAndroid Build Coastguard Worker return false;
364*61046927SAndroid Build Coastguard Worker }
365*61046927SAndroid Build Coastguard Worker
366*61046927SAndroid Build Coastguard Worker return true;
367*61046927SAndroid Build Coastguard Worker }
368*61046927SAndroid Build Coastguard Worker
369*61046927SAndroid Build Coastguard Worker /* Returns true if instruction can end block. */
validate_ctrl_instr(rogue_validation_state * state,const rogue_ctrl_instr * ctrl)370*61046927SAndroid Build Coastguard Worker static bool validate_ctrl_instr(rogue_validation_state *state,
371*61046927SAndroid Build Coastguard Worker const rogue_ctrl_instr *ctrl)
372*61046927SAndroid Build Coastguard Worker {
373*61046927SAndroid Build Coastguard Worker if (ctrl->op == ROGUE_CTRL_OP_INVALID || ctrl->op >= ROGUE_CTRL_OP_COUNT)
374*61046927SAndroid Build Coastguard Worker validate_log(state, "Unknown ctrl op 0x%x encountered.", ctrl->op);
375*61046927SAndroid Build Coastguard Worker
376*61046927SAndroid Build Coastguard Worker /* TODO: Validate rest, check blocks, etc. */
377*61046927SAndroid Build Coastguard Worker const rogue_ctrl_op_info *info = &rogue_ctrl_op_infos[ctrl->op];
378*61046927SAndroid Build Coastguard Worker
379*61046927SAndroid Build Coastguard Worker if (info->has_target && !ctrl->target_block)
380*61046927SAndroid Build Coastguard Worker validate_log(state, "Ctrl op expected target block, but none provided.");
381*61046927SAndroid Build Coastguard Worker else if (!info->has_target && ctrl->target_block)
382*61046927SAndroid Build Coastguard Worker validate_log(state,
383*61046927SAndroid Build Coastguard Worker "Ctrl op did not expect target block, but one provided.");
384*61046927SAndroid Build Coastguard Worker
385*61046927SAndroid Build Coastguard Worker /* Check if instruction modifiers are valid. */
386*61046927SAndroid Build Coastguard Worker if (!rogue_mods_supported(ctrl->mod, info->supported_op_mods))
387*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported CTRL op modifiers.");
388*61046927SAndroid Build Coastguard Worker
389*61046927SAndroid Build Coastguard Worker if (!validate_ctrl_op_mod_combo(ctrl->mod))
390*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported CTRL op modifier combination.");
391*61046927SAndroid Build Coastguard Worker
392*61046927SAndroid Build Coastguard Worker /* Instruction repeat checks. */
393*61046927SAndroid Build Coastguard Worker if (ctrl->instr.repeat > 1 && !info->dst_repeat_mask &&
394*61046927SAndroid Build Coastguard Worker !info->src_repeat_mask) {
395*61046927SAndroid Build Coastguard Worker validate_log(state, "Repeat set for CTRL op without repeat support.");
396*61046927SAndroid Build Coastguard Worker }
397*61046927SAndroid Build Coastguard Worker
398*61046927SAndroid Build Coastguard Worker /* Validate destinations and sources for ungrouped shaders. */
399*61046927SAndroid Build Coastguard Worker if (!state->shader->is_grouped) {
400*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_dsts; ++i) {
401*61046927SAndroid Build Coastguard Worker validate_dst(state,
402*61046927SAndroid Build Coastguard Worker &ctrl->dst[i],
403*61046927SAndroid Build Coastguard Worker info->supported_dst_types[i],
404*61046927SAndroid Build Coastguard Worker i,
405*61046927SAndroid Build Coastguard Worker info->dst_stride[i],
406*61046927SAndroid Build Coastguard Worker ctrl->instr.repeat,
407*61046927SAndroid Build Coastguard Worker info->dst_repeat_mask);
408*61046927SAndroid Build Coastguard Worker }
409*61046927SAndroid Build Coastguard Worker
410*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_srcs; ++i) {
411*61046927SAndroid Build Coastguard Worker validate_src(state,
412*61046927SAndroid Build Coastguard Worker &ctrl->src[i],
413*61046927SAndroid Build Coastguard Worker info->supported_src_types[i],
414*61046927SAndroid Build Coastguard Worker i,
415*61046927SAndroid Build Coastguard Worker info->src_stride[i],
416*61046927SAndroid Build Coastguard Worker ctrl->instr.repeat,
417*61046927SAndroid Build Coastguard Worker info->src_repeat_mask);
418*61046927SAndroid Build Coastguard Worker }
419*61046927SAndroid Build Coastguard Worker }
420*61046927SAndroid Build Coastguard Worker
421*61046927SAndroid Build Coastguard Worker /* nop.end counts as a end-of-block instruction. */
422*61046927SAndroid Build Coastguard Worker if (rogue_instr_is_nop_end(&ctrl->instr))
423*61046927SAndroid Build Coastguard Worker return true;
424*61046927SAndroid Build Coastguard Worker
425*61046927SAndroid Build Coastguard Worker /* Control instructions have no end flag to set. */
426*61046927SAndroid Build Coastguard Worker if (ctrl->instr.end)
427*61046927SAndroid Build Coastguard Worker validate_log(state, "CTRL ops have no end flag.");
428*61046927SAndroid Build Coastguard Worker
429*61046927SAndroid Build Coastguard Worker return info->ends_block;
430*61046927SAndroid Build Coastguard Worker }
431*61046927SAndroid Build Coastguard Worker
validate_bitwise_op_mod_combo(uint64_t mods)432*61046927SAndroid Build Coastguard Worker static bool validate_bitwise_op_mod_combo(uint64_t mods)
433*61046927SAndroid Build Coastguard Worker {
434*61046927SAndroid Build Coastguard Worker rogue_foreach_mod_in_set (mod, mods) {
435*61046927SAndroid Build Coastguard Worker const rogue_bitwise_op_mod_info *info = &rogue_bitwise_op_mod_infos[mod];
436*61046927SAndroid Build Coastguard Worker
437*61046927SAndroid Build Coastguard Worker /* Check if any excluded op mods have been included. */
438*61046927SAndroid Build Coastguard Worker if (info->exclude & mods)
439*61046927SAndroid Build Coastguard Worker return false;
440*61046927SAndroid Build Coastguard Worker
441*61046927SAndroid Build Coastguard Worker /* Check if any required op mods have been missed. */
442*61046927SAndroid Build Coastguard Worker if (info->require && !(info->require & mods))
443*61046927SAndroid Build Coastguard Worker return false;
444*61046927SAndroid Build Coastguard Worker }
445*61046927SAndroid Build Coastguard Worker
446*61046927SAndroid Build Coastguard Worker return true;
447*61046927SAndroid Build Coastguard Worker }
448*61046927SAndroid Build Coastguard Worker
validate_bitwise_instr(rogue_validation_state * state,const rogue_bitwise_instr * bitwise)449*61046927SAndroid Build Coastguard Worker static void validate_bitwise_instr(rogue_validation_state *state,
450*61046927SAndroid Build Coastguard Worker const rogue_bitwise_instr *bitwise)
451*61046927SAndroid Build Coastguard Worker {
452*61046927SAndroid Build Coastguard Worker if (bitwise->op == ROGUE_BITWISE_OP_INVALID ||
453*61046927SAndroid Build Coastguard Worker bitwise->op >= ROGUE_BITWISE_OP_COUNT)
454*61046927SAndroid Build Coastguard Worker validate_log(state, "Unknown bitwise op 0x%x encountered.", bitwise->op);
455*61046927SAndroid Build Coastguard Worker
456*61046927SAndroid Build Coastguard Worker const rogue_bitwise_op_info *info = &rogue_bitwise_op_infos[bitwise->op];
457*61046927SAndroid Build Coastguard Worker
458*61046927SAndroid Build Coastguard Worker /* Check if instruction modifiers are valid. */
459*61046927SAndroid Build Coastguard Worker if (!rogue_mods_supported(bitwise->mod, info->supported_op_mods))
460*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported bitwise op modifiers.");
461*61046927SAndroid Build Coastguard Worker
462*61046927SAndroid Build Coastguard Worker if (!validate_bitwise_op_mod_combo(bitwise->mod))
463*61046927SAndroid Build Coastguard Worker validate_log(state, "Unsupported bitwise op modifier combination.");
464*61046927SAndroid Build Coastguard Worker
465*61046927SAndroid Build Coastguard Worker /* Instruction repeat checks. */
466*61046927SAndroid Build Coastguard Worker if (bitwise->instr.repeat > 1 && !info->dst_repeat_mask &&
467*61046927SAndroid Build Coastguard Worker !info->src_repeat_mask) {
468*61046927SAndroid Build Coastguard Worker validate_log(state, "Repeat set for bitwise op without repeat support.");
469*61046927SAndroid Build Coastguard Worker }
470*61046927SAndroid Build Coastguard Worker
471*61046927SAndroid Build Coastguard Worker /* Validate destinations and sources for ungrouped shaders. */
472*61046927SAndroid Build Coastguard Worker if (!state->shader->is_grouped) {
473*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_dsts; ++i) {
474*61046927SAndroid Build Coastguard Worker validate_dst(state,
475*61046927SAndroid Build Coastguard Worker &bitwise->dst[i],
476*61046927SAndroid Build Coastguard Worker info->supported_dst_types[i],
477*61046927SAndroid Build Coastguard Worker i,
478*61046927SAndroid Build Coastguard Worker info->dst_stride[i],
479*61046927SAndroid Build Coastguard Worker bitwise->instr.repeat,
480*61046927SAndroid Build Coastguard Worker info->dst_repeat_mask);
481*61046927SAndroid Build Coastguard Worker }
482*61046927SAndroid Build Coastguard Worker
483*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < info->num_srcs; ++i) {
484*61046927SAndroid Build Coastguard Worker validate_src(state,
485*61046927SAndroid Build Coastguard Worker &bitwise->src[i],
486*61046927SAndroid Build Coastguard Worker info->supported_src_types[i],
487*61046927SAndroid Build Coastguard Worker i,
488*61046927SAndroid Build Coastguard Worker info->src_stride[i],
489*61046927SAndroid Build Coastguard Worker bitwise->instr.repeat,
490*61046927SAndroid Build Coastguard Worker info->src_repeat_mask);
491*61046927SAndroid Build Coastguard Worker }
492*61046927SAndroid Build Coastguard Worker }
493*61046927SAndroid Build Coastguard Worker }
494*61046927SAndroid Build Coastguard Worker
495*61046927SAndroid Build Coastguard Worker /* Returns true if instruction can end block. */
validate_instr(rogue_validation_state * state,const rogue_instr * instr)496*61046927SAndroid Build Coastguard Worker static bool validate_instr(rogue_validation_state *state,
497*61046927SAndroid Build Coastguard Worker const rogue_instr *instr)
498*61046927SAndroid Build Coastguard Worker {
499*61046927SAndroid Build Coastguard Worker state->ctx.instr = instr;
500*61046927SAndroid Build Coastguard Worker
501*61046927SAndroid Build Coastguard Worker bool ends_block = false;
502*61046927SAndroid Build Coastguard Worker
503*61046927SAndroid Build Coastguard Worker switch (instr->type) {
504*61046927SAndroid Build Coastguard Worker case ROGUE_INSTR_TYPE_ALU:
505*61046927SAndroid Build Coastguard Worker validate_alu_instr(state, rogue_instr_as_alu(instr));
506*61046927SAndroid Build Coastguard Worker break;
507*61046927SAndroid Build Coastguard Worker
508*61046927SAndroid Build Coastguard Worker case ROGUE_INSTR_TYPE_BACKEND:
509*61046927SAndroid Build Coastguard Worker validate_backend_instr(state, rogue_instr_as_backend(instr));
510*61046927SAndroid Build Coastguard Worker break;
511*61046927SAndroid Build Coastguard Worker
512*61046927SAndroid Build Coastguard Worker case ROGUE_INSTR_TYPE_CTRL:
513*61046927SAndroid Build Coastguard Worker ends_block = validate_ctrl_instr(state, rogue_instr_as_ctrl(instr));
514*61046927SAndroid Build Coastguard Worker break;
515*61046927SAndroid Build Coastguard Worker
516*61046927SAndroid Build Coastguard Worker case ROGUE_INSTR_TYPE_BITWISE:
517*61046927SAndroid Build Coastguard Worker validate_bitwise_instr(state, rogue_instr_as_bitwise(instr));
518*61046927SAndroid Build Coastguard Worker break;
519*61046927SAndroid Build Coastguard Worker
520*61046927SAndroid Build Coastguard Worker default:
521*61046927SAndroid Build Coastguard Worker validate_log(state,
522*61046927SAndroid Build Coastguard Worker "Unknown instruction type 0x%x encountered.",
523*61046927SAndroid Build Coastguard Worker instr->type);
524*61046927SAndroid Build Coastguard Worker }
525*61046927SAndroid Build Coastguard Worker
526*61046927SAndroid Build Coastguard Worker /* If the last instruction isn't control flow but has the end flag set, it
527*61046927SAndroid Build Coastguard Worker * can end a block. */
528*61046927SAndroid Build Coastguard Worker if (!ends_block)
529*61046927SAndroid Build Coastguard Worker ends_block = instr->end;
530*61046927SAndroid Build Coastguard Worker
531*61046927SAndroid Build Coastguard Worker state->ctx.instr = NULL;
532*61046927SAndroid Build Coastguard Worker
533*61046927SAndroid Build Coastguard Worker return ends_block;
534*61046927SAndroid Build Coastguard Worker }
535*61046927SAndroid Build Coastguard Worker
536*61046927SAndroid Build Coastguard Worker /* Returns true if instruction can end block. */
validate_instr_group(rogue_validation_state * state,const rogue_instr_group * group)537*61046927SAndroid Build Coastguard Worker static bool validate_instr_group(rogue_validation_state *state,
538*61046927SAndroid Build Coastguard Worker const rogue_instr_group *group)
539*61046927SAndroid Build Coastguard Worker {
540*61046927SAndroid Build Coastguard Worker state->ctx.group = group;
541*61046927SAndroid Build Coastguard Worker /* TODO: Validate group properties. */
542*61046927SAndroid Build Coastguard Worker /* TODO: Check for pseudo-instructions. */
543*61046927SAndroid Build Coastguard Worker
544*61046927SAndroid Build Coastguard Worker bool ends_block = false;
545*61046927SAndroid Build Coastguard Worker
546*61046927SAndroid Build Coastguard Worker /* Validate instructions in group. */
547*61046927SAndroid Build Coastguard Worker /* TODO: Check util_last_bit group_phases < bla bla */
548*61046927SAndroid Build Coastguard Worker rogue_foreach_phase_in_set (p, group->header.phases) {
549*61046927SAndroid Build Coastguard Worker const rogue_instr *instr = group->instrs[p];
550*61046927SAndroid Build Coastguard Worker
551*61046927SAndroid Build Coastguard Worker if (!instr)
552*61046927SAndroid Build Coastguard Worker validate_log(state, "Missing instruction where phase was set.");
553*61046927SAndroid Build Coastguard Worker
554*61046927SAndroid Build Coastguard Worker /* TODO NEXT: Groups that have control instructions should only have a
555*61046927SAndroid Build Coastguard Worker * single instruction. */
556*61046927SAndroid Build Coastguard Worker ends_block = validate_instr(state, instr);
557*61046927SAndroid Build Coastguard Worker }
558*61046927SAndroid Build Coastguard Worker
559*61046927SAndroid Build Coastguard Worker state->ctx.group = NULL;
560*61046927SAndroid Build Coastguard Worker
561*61046927SAndroid Build Coastguard Worker if (group->header.alu != ROGUE_ALU_CONTROL)
562*61046927SAndroid Build Coastguard Worker return group->header.end;
563*61046927SAndroid Build Coastguard Worker
564*61046927SAndroid Build Coastguard Worker return ends_block;
565*61046927SAndroid Build Coastguard Worker }
566*61046927SAndroid Build Coastguard Worker
validate_block(rogue_validation_state * state,const rogue_block * block)567*61046927SAndroid Build Coastguard Worker static void validate_block(rogue_validation_state *state,
568*61046927SAndroid Build Coastguard Worker const rogue_block *block)
569*61046927SAndroid Build Coastguard Worker {
570*61046927SAndroid Build Coastguard Worker /* TODO: Validate block properties. */
571*61046927SAndroid Build Coastguard Worker state->ctx.block = block;
572*61046927SAndroid Build Coastguard Worker
573*61046927SAndroid Build Coastguard Worker if (list_is_empty(&block->instrs)) {
574*61046927SAndroid Build Coastguard Worker validate_log(state, "Block is empty.");
575*61046927SAndroid Build Coastguard Worker state->ctx.block = NULL;
576*61046927SAndroid Build Coastguard Worker return;
577*61046927SAndroid Build Coastguard Worker }
578*61046927SAndroid Build Coastguard Worker
579*61046927SAndroid Build Coastguard Worker unsigned block_ends = 0;
580*61046927SAndroid Build Coastguard Worker struct list_head *block_end = NULL;
581*61046927SAndroid Build Coastguard Worker struct list_head *last = block->instrs.prev;
582*61046927SAndroid Build Coastguard Worker
583*61046927SAndroid Build Coastguard Worker /* Validate instructions/groups in block. */
584*61046927SAndroid Build Coastguard Worker if (!block->shader->is_grouped) {
585*61046927SAndroid Build Coastguard Worker rogue_foreach_instr_in_block (instr, block) {
586*61046927SAndroid Build Coastguard Worker bool ends_block = validate_instr(state, instr);
587*61046927SAndroid Build Coastguard Worker block_ends += ends_block;
588*61046927SAndroid Build Coastguard Worker block_end = ends_block ? &instr->link : block_end;
589*61046927SAndroid Build Coastguard Worker }
590*61046927SAndroid Build Coastguard Worker } else {
591*61046927SAndroid Build Coastguard Worker rogue_foreach_instr_group_in_block (group, block) {
592*61046927SAndroid Build Coastguard Worker bool ends_block = validate_instr_group(state, group);
593*61046927SAndroid Build Coastguard Worker block_ends += ends_block;
594*61046927SAndroid Build Coastguard Worker block_end = ends_block ? &group->link : block_end;
595*61046927SAndroid Build Coastguard Worker }
596*61046927SAndroid Build Coastguard Worker }
597*61046927SAndroid Build Coastguard Worker
598*61046927SAndroid Build Coastguard Worker if (!block_ends || block_ends > 1)
599*61046927SAndroid Build Coastguard Worker validate_log(state,
600*61046927SAndroid Build Coastguard Worker "Block must end with a single control flow instruction.");
601*61046927SAndroid Build Coastguard Worker else if (block_end != last)
602*61046927SAndroid Build Coastguard Worker validate_log(
603*61046927SAndroid Build Coastguard Worker state,
604*61046927SAndroid Build Coastguard Worker "Control flow instruction is present prior to the end of the block.");
605*61046927SAndroid Build Coastguard Worker
606*61046927SAndroid Build Coastguard Worker state->ctx.block = NULL;
607*61046927SAndroid Build Coastguard Worker }
608*61046927SAndroid Build Coastguard Worker
validate_reg_use(rogue_validation_state * state,const rogue_reg_use * use,uint64_t supported_io_srcs)609*61046927SAndroid Build Coastguard Worker static void validate_reg_use(rogue_validation_state *state,
610*61046927SAndroid Build Coastguard Worker const rogue_reg_use *use,
611*61046927SAndroid Build Coastguard Worker uint64_t supported_io_srcs)
612*61046927SAndroid Build Coastguard Worker {
613*61046927SAndroid Build Coastguard Worker /* No restrictions. */
614*61046927SAndroid Build Coastguard Worker if (!supported_io_srcs)
615*61046927SAndroid Build Coastguard Worker return;
616*61046927SAndroid Build Coastguard Worker
617*61046927SAndroid Build Coastguard Worker const rogue_instr *instr = use->instr;
618*61046927SAndroid Build Coastguard Worker
619*61046927SAndroid Build Coastguard Worker rogue_foreach_phase_in_set (p, rogue_instr_supported_phases(instr)) {
620*61046927SAndroid Build Coastguard Worker enum rogue_io io_src = rogue_instr_src_io_src(instr, p, use->src_index);
621*61046927SAndroid Build Coastguard Worker if (io_src == ROGUE_IO_INVALID)
622*61046927SAndroid Build Coastguard Worker validate_log(state, "Register used where no source is present.");
623*61046927SAndroid Build Coastguard Worker
624*61046927SAndroid Build Coastguard Worker if (!rogue_io_supported(io_src, supported_io_srcs))
625*61046927SAndroid Build Coastguard Worker validate_log(state,
626*61046927SAndroid Build Coastguard Worker "Register class unsupported in S%u.",
627*61046927SAndroid Build Coastguard Worker io_src - ROGUE_IO_S0); /* TODO: Either add info here to
628*61046927SAndroid Build Coastguard Worker get register class and print as
629*61046927SAndroid Build Coastguard Worker string, or add info to
630*61046927SAndroid Build Coastguard Worker rogue_validation_state. */
631*61046927SAndroid Build Coastguard Worker }
632*61046927SAndroid Build Coastguard Worker }
633*61046927SAndroid Build Coastguard Worker
validate_reg_state(rogue_validation_state * state,rogue_shader * shader)634*61046927SAndroid Build Coastguard Worker static void validate_reg_state(rogue_validation_state *state,
635*61046927SAndroid Build Coastguard Worker rogue_shader *shader)
636*61046927SAndroid Build Coastguard Worker {
637*61046927SAndroid Build Coastguard Worker BITSET_WORD *regs_used = NULL;
638*61046927SAndroid Build Coastguard Worker
639*61046927SAndroid Build Coastguard Worker for (enum rogue_reg_class class = 0; class < ROGUE_REG_CLASS_COUNT;
640*61046927SAndroid Build Coastguard Worker ++class) {
641*61046927SAndroid Build Coastguard Worker const rogue_reg_info *info = &rogue_reg_infos[class];
642*61046927SAndroid Build Coastguard Worker if (info->num)
643*61046927SAndroid Build Coastguard Worker regs_used =
644*61046927SAndroid Build Coastguard Worker rzalloc_size(state, sizeof(*regs_used) * BITSET_WORDS(info->num));
645*61046927SAndroid Build Coastguard Worker
646*61046927SAndroid Build Coastguard Worker rogue_foreach_reg (reg, shader, class) {
647*61046927SAndroid Build Coastguard Worker /* Ensure that the range restrictions are satisfied. */
648*61046927SAndroid Build Coastguard Worker if (info->num && reg->index >= info->num)
649*61046927SAndroid Build Coastguard Worker validate_log(state, "%s register index out of range.", info->name);
650*61046927SAndroid Build Coastguard Worker
651*61046927SAndroid Build Coastguard Worker /* Ensure that only registers of this class are in the regs list. */
652*61046927SAndroid Build Coastguard Worker if (reg->class != class)
653*61046927SAndroid Build Coastguard Worker validate_log(state,
654*61046927SAndroid Build Coastguard Worker "%s register found in %s register list.",
655*61046927SAndroid Build Coastguard Worker rogue_reg_infos[reg->class].name,
656*61046927SAndroid Build Coastguard Worker info->name);
657*61046927SAndroid Build Coastguard Worker
658*61046927SAndroid Build Coastguard Worker /* Track the registers used in the class. */
659*61046927SAndroid Build Coastguard Worker if (info->num)
660*61046927SAndroid Build Coastguard Worker BITSET_SET(regs_used, reg->index);
661*61046927SAndroid Build Coastguard Worker
662*61046927SAndroid Build Coastguard Worker /* Check register cache entry. */
663*61046927SAndroid Build Coastguard Worker rogue_reg **reg_cached =
664*61046927SAndroid Build Coastguard Worker util_sparse_array_get(&shader->reg_cache[class], reg->index);
665*61046927SAndroid Build Coastguard Worker if (!reg_cached || !*reg_cached)
666*61046927SAndroid Build Coastguard Worker validate_log(state,
667*61046927SAndroid Build Coastguard Worker "Missing %s register %u cache entry.",
668*61046927SAndroid Build Coastguard Worker info->name,
669*61046927SAndroid Build Coastguard Worker reg->index);
670*61046927SAndroid Build Coastguard Worker else if (*reg_cached != reg || (*reg_cached)->index != reg->index ||
671*61046927SAndroid Build Coastguard Worker (*reg_cached)->class != reg->class)
672*61046927SAndroid Build Coastguard Worker validate_log(state,
673*61046927SAndroid Build Coastguard Worker "Mismatching %s register %u cache entry.",
674*61046927SAndroid Build Coastguard Worker info->name,
675*61046927SAndroid Build Coastguard Worker reg->index);
676*61046927SAndroid Build Coastguard Worker else if (reg_cached != reg->cached)
677*61046927SAndroid Build Coastguard Worker validate_log(state,
678*61046927SAndroid Build Coastguard Worker "Mismatching %s register %u cache entry pointer.",
679*61046927SAndroid Build Coastguard Worker info->name,
680*61046927SAndroid Build Coastguard Worker reg->index);
681*61046927SAndroid Build Coastguard Worker
682*61046927SAndroid Build Coastguard Worker /* Validate register uses. */
683*61046927SAndroid Build Coastguard Worker const rogue_reg_info *reg_info = &rogue_reg_infos[class];
684*61046927SAndroid Build Coastguard Worker rogue_foreach_reg_use (use, reg)
685*61046927SAndroid Build Coastguard Worker validate_reg_use(state, use, reg_info->supported_io_srcs);
686*61046927SAndroid Build Coastguard Worker }
687*61046927SAndroid Build Coastguard Worker
688*61046927SAndroid Build Coastguard Worker /* Check that the registers used matches the usage list. */
689*61046927SAndroid Build Coastguard Worker if (info->num && memcmp(shader->regs_used[class],
690*61046927SAndroid Build Coastguard Worker regs_used,
691*61046927SAndroid Build Coastguard Worker sizeof(*regs_used) * BITSET_WORDS(info->num)))
692*61046927SAndroid Build Coastguard Worker validate_log(state, "Incorrect %s register usage list.", info->name);
693*61046927SAndroid Build Coastguard Worker
694*61046927SAndroid Build Coastguard Worker ralloc_free(regs_used);
695*61046927SAndroid Build Coastguard Worker }
696*61046927SAndroid Build Coastguard Worker
697*61046927SAndroid Build Coastguard Worker /* Check that SSA registers aren't being written to more than once. */
698*61046927SAndroid Build Coastguard Worker rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_SSA)
699*61046927SAndroid Build Coastguard Worker if (list_length(®->writes) > 1)
700*61046927SAndroid Build Coastguard Worker validate_log(state,
701*61046927SAndroid Build Coastguard Worker "SSA register %u is written to more than once.",
702*61046927SAndroid Build Coastguard Worker reg->index);
703*61046927SAndroid Build Coastguard Worker
704*61046927SAndroid Build Coastguard Worker rogue_foreach_regarray (regarray, shader) {
705*61046927SAndroid Build Coastguard Worker /* Validate regarray contents. */
706*61046927SAndroid Build Coastguard Worker validate_regarray(state, regarray);
707*61046927SAndroid Build Coastguard Worker
708*61046927SAndroid Build Coastguard Worker /* Check regarray cache entry. */
709*61046927SAndroid Build Coastguard Worker uint64_t key = rogue_regarray_cache_key(regarray->size,
710*61046927SAndroid Build Coastguard Worker regarray->regs[0]->class,
711*61046927SAndroid Build Coastguard Worker regarray->regs[0]->index,
712*61046927SAndroid Build Coastguard Worker false,
713*61046927SAndroid Build Coastguard Worker 0);
714*61046927SAndroid Build Coastguard Worker rogue_regarray **regarray_cached =
715*61046927SAndroid Build Coastguard Worker util_sparse_array_get(&shader->regarray_cache, key);
716*61046927SAndroid Build Coastguard Worker if (!regarray_cached || !*regarray_cached)
717*61046927SAndroid Build Coastguard Worker validate_log(state, "Missing regarray cache entry.");
718*61046927SAndroid Build Coastguard Worker else if (*regarray_cached != regarray ||
719*61046927SAndroid Build Coastguard Worker (*regarray_cached)->size != regarray->size ||
720*61046927SAndroid Build Coastguard Worker (*regarray_cached)->parent != regarray->parent ||
721*61046927SAndroid Build Coastguard Worker (*regarray_cached)->regs != regarray->regs)
722*61046927SAndroid Build Coastguard Worker validate_log(state, "Mismatching regarray cache entry.");
723*61046927SAndroid Build Coastguard Worker else if (regarray_cached != regarray->cached)
724*61046927SAndroid Build Coastguard Worker validate_log(state, "Mismatching regarray cache entry pointer.");
725*61046927SAndroid Build Coastguard Worker
726*61046927SAndroid Build Coastguard Worker if (regarray->parent && (regarray->parent->size <= regarray->size ||
727*61046927SAndroid Build Coastguard Worker regarray->parent->parent))
728*61046927SAndroid Build Coastguard Worker validate_log(state, "Invalid sub-regarray.");
729*61046927SAndroid Build Coastguard Worker }
730*61046927SAndroid Build Coastguard Worker }
731*61046927SAndroid Build Coastguard Worker
732*61046927SAndroid Build Coastguard Worker PUBLIC
rogue_validate_shader(rogue_shader * shader,const char * when)733*61046927SAndroid Build Coastguard Worker bool rogue_validate_shader(rogue_shader *shader, const char *when)
734*61046927SAndroid Build Coastguard Worker {
735*61046927SAndroid Build Coastguard Worker if (ROGUE_DEBUG(VLD_SKIP))
736*61046927SAndroid Build Coastguard Worker return true;
737*61046927SAndroid Build Coastguard Worker
738*61046927SAndroid Build Coastguard Worker bool errors_present;
739*61046927SAndroid Build Coastguard Worker
740*61046927SAndroid Build Coastguard Worker rogue_validation_state *state = create_validation_state(shader, when);
741*61046927SAndroid Build Coastguard Worker
742*61046927SAndroid Build Coastguard Worker validate_reg_state(state, shader);
743*61046927SAndroid Build Coastguard Worker
744*61046927SAndroid Build Coastguard Worker /* TODO: Ensure there is at least one block (with at least an end
745*61046927SAndroid Build Coastguard Worker * instruction!) */
746*61046927SAndroid Build Coastguard Worker rogue_foreach_block (block, shader)
747*61046927SAndroid Build Coastguard Worker validate_block(state, block);
748*61046927SAndroid Build Coastguard Worker
749*61046927SAndroid Build Coastguard Worker errors_present = validate_print_errors(state);
750*61046927SAndroid Build Coastguard Worker
751*61046927SAndroid Build Coastguard Worker ralloc_free(state);
752*61046927SAndroid Build Coastguard Worker
753*61046927SAndroid Build Coastguard Worker return !errors_present;
754*61046927SAndroid Build Coastguard Worker }
755