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