xref: /aosp_15_r20/external/mesa3d/src/imagination/rogue/rogue_validate.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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(&reg->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