1 /*
2 * Copyright © 2024 Imagination Technologies Ltd.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 /**
8 * \file pco_validate.c
9 *
10 * \brief PCO validation functions.
11 */
12
13 #include "pco.h"
14 #include "pco_internal.h"
15 #include "util/bitset.h"
16 #include "util/macros.h"
17 #include "util/ralloc.h"
18
19 #include <inttypes.h>
20 #include <stdio.h>
21
22 enum ref_cursor {
23 REF_CURSOR_NONE,
24 REF_CURSOR_INSTR_DEST,
25 REF_CURSOR_INSTR_SRC,
26 REF_CURSOR_IGRP_SRC,
27 REF_CURSOR_IGRP_ISS,
28 REF_CURSOR_IGRP_DEST,
29 };
30
31 /** Validation state. */
32 struct val_state {
33 const char *when; /** Description of the validation being done. */
34 pco_shader *shader; /** The shader being validated. */
35 pco_func *func; /** Current function being validated. */
36 pco_cf_node *cf_node; /** Current cf node being validated. */
37 pco_igrp *igrp; /** Current instruction group being validated. */
38 enum pco_op_phase phase; /** Phase of the instruction being validated. */
39 pco_instr *instr; /** Current instruction being validated. */
40 pco_ref *ref; /** Current reference being validated. */
41 enum ref_cursor ref_cursor; /** Current reference cursor. */
42 };
43
44 /**
45 * \brief Asserts a condition, printing an error and aborting on failure.
46 *
47 * \param[in] state Validation state.
48 * \param[in] cond Assertion condition.
49 * \param[in] cond_str Assertion condition string.
50 * \param[in] fmt Format string.
51 */
pco_assert(struct val_state * state,bool cond,const char * cond_str,const char * fmt,...)52 static void pco_assert(struct val_state *state,
53 bool cond,
54 const char *cond_str,
55 const char *fmt,
56 ...)
57 {
58 if (cond)
59 return;
60
61 printf("PCO validation failed with assertion \"%s\" - ", cond_str);
62
63 va_list args;
64 va_start(args, fmt);
65 vprintf(fmt, args);
66 va_end(args);
67
68 printf(" - while validating");
69
70 if (state->ref_cursor != REF_CURSOR_NONE) {
71 switch (state->ref_cursor) {
72 case REF_CURSOR_INSTR_DEST:
73 printf(" instr dest #%" PRIuPTR, state->ref - state->instr->dest);
74 break;
75
76 case REF_CURSOR_INSTR_SRC:
77 printf(" instr src #%" PRIuPTR, state->ref - state->instr->src);
78 break;
79
80 default:
81 unreachable();
82 }
83
84 printf(" (");
85 pco_print_ref(state->shader, *state->ref);
86 printf(")");
87 }
88
89 if (state->cf_node) {
90 printf(" ");
91 pco_print_cf_node_name(state->shader, state->cf_node);
92 }
93
94 if (state->igrp) {
95 printf(" igrp ");
96 pco_print_igrp(state->shader, state->igrp);
97 }
98
99 if (state->instr) {
100 printf(" instr ");
101 pco_print_instr(state->shader, state->instr);
102 }
103
104 if (state->func) {
105 printf(" ");
106 pco_print_cf_node_name(state->shader, &state->func->cf_node);
107 }
108
109 printf(".\n");
110
111 pco_print_shader_info(state->shader);
112
113 abort();
114 }
115
116 #define PCO_ASSERT(state, cond, fmt, ...) \
117 pco_assert(state, cond, #cond, fmt, ##__VA_ARGS__)
118
119 /**
120 * \brief Validates SSA assignments and uses.
121 *
122 * \param[in,out] state Validation state.
123 */
pco_validate_ssa(struct val_state * state)124 static void pco_validate_ssa(struct val_state *state)
125 {
126 BITSET_WORD *ssa_writes;
127 pco_foreach_func_in_shader (func, state->shader) {
128 state->func = func;
129
130 ssa_writes = rzalloc_array_size(NULL,
131 sizeof(*ssa_writes),
132 BITSET_WORDS(func->next_ssa));
133
134 /* Ensure sources have been defined before they're used. */
135 state->ref_cursor = REF_CURSOR_INSTR_SRC;
136 pco_foreach_instr_in_func (instr, func) {
137 state->cf_node = &instr->parent_block->cf_node;
138 state->instr = instr;
139 pco_foreach_instr_src_ssa (psrc, instr) {
140 state->ref = psrc;
141 PCO_ASSERT(state,
142 BITSET_TEST(ssa_writes, psrc->val),
143 "SSA source used before being defined");
144 }
145
146 /* Ensure destinations are only defined once. */
147 state->ref_cursor = REF_CURSOR_INSTR_DEST;
148 pco_foreach_instr_dest_ssa (pdest, instr) {
149 state->ref = pdest;
150 PCO_ASSERT(state,
151 !BITSET_TEST(ssa_writes, pdest->val),
152 "SSA destination defined to more than once");
153 BITSET_SET(ssa_writes, pdest->val);
154 }
155 }
156
157 ralloc_free(ssa_writes);
158
159 state->func = NULL;
160 state->ref = NULL;
161 }
162 }
163
164 /**
165 * \brief Validates a PCO shader.
166 *
167 * \param[in] shader PCO shader.
168 * \param[in] when When the validation check is being run.
169 */
pco_validate_shader(UNUSED pco_shader * shader,UNUSED const char * when)170 void pco_validate_shader(UNUSED pco_shader *shader, UNUSED const char *when)
171 {
172 #ifndef NDEBUG
173 if (PCO_DEBUG(VAL_SKIP))
174 return;
175
176 struct val_state state = {
177 .when = when,
178 .shader = shader,
179 .phase = -1,
180 };
181
182 if (!shader->is_grouped)
183 pco_validate_ssa(&state);
184
185 puts("finishme: pco_validate_shader");
186 #endif /* NDEBUG */
187 }
188