1 /*
2 * Copyright 2021 Alyssa Rosenzweig
3 * Copyright 2019-2020 Collabora, Ltd.
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "agx_builder.h"
8 #include "agx_compiler.h"
9
10 static void
agx_print_sized(char prefix,unsigned value,enum agx_size size,FILE * fp)11 agx_print_sized(char prefix, unsigned value, enum agx_size size, FILE *fp)
12 {
13 switch (size) {
14 case AGX_SIZE_16:
15 fprintf(fp, "%c%u%c", prefix, value >> 1, (value & 1) ? 'h' : 'l');
16 return;
17 case AGX_SIZE_32:
18 assert((value & 1) == 0);
19 fprintf(fp, "%c%u", prefix, value >> 1);
20 return;
21 case AGX_SIZE_64:
22 assert((value & 1) == 0);
23 fprintf(fp, "%c%u:%c%u", prefix, value >> 1, prefix, (value >> 1) + 1);
24 return;
25 }
26
27 unreachable("Invalid size");
28 }
29
30 static void
agx_print_reg(agx_index index,unsigned value,FILE * fp)31 agx_print_reg(agx_index index, unsigned value, FILE *fp)
32 {
33 agx_print_sized('r', value, index.size, fp);
34
35 if (agx_channels(index) > 1) {
36 unsigned last =
37 value + agx_size_align_16(index.size) * (agx_channels(index) - 1);
38
39 fprintf(fp, "...");
40
41 if (index.memory)
42 fprintf(fp, "m");
43 agx_print_sized('r', last, index.size, fp);
44 }
45 }
46
47 void
agx_print_index(agx_index index,bool is_float,FILE * fp)48 agx_print_index(agx_index index, bool is_float, FILE *fp)
49 {
50 if (index.memory)
51 fprintf(fp, "m");
52
53 switch (index.type) {
54 case AGX_INDEX_NULL:
55 fprintf(fp, "_");
56 return;
57
58 case AGX_INDEX_NORMAL:
59 if (index.cache)
60 fprintf(fp, "$");
61
62 if (index.discard)
63 fprintf(fp, "`");
64
65 if (index.kill)
66 fprintf(fp, "*");
67
68 fprintf(fp, "%u", index.value);
69 break;
70
71 case AGX_INDEX_IMMEDIATE:
72 if (is_float) {
73 assert(index.value < 0x100);
74 fprintf(fp, "#%f", agx_minifloat_decode(index.value));
75 } else {
76 fprintf(fp, "#%u", index.value);
77 }
78
79 break;
80
81 case AGX_INDEX_UNDEF:
82 fprintf(fp, "undef");
83 break;
84
85 case AGX_INDEX_UNIFORM:
86 agx_print_sized('u', index.value, index.size, fp);
87 break;
88
89 case AGX_INDEX_REGISTER:
90 agx_print_reg(index, index.value, fp);
91 break;
92
93 default:
94 unreachable("Invalid index type");
95 }
96
97 if (index.type == AGX_INDEX_NORMAL) {
98 /* Print length suffixes if not implied */
99 if (index.size == AGX_SIZE_16)
100 fprintf(fp, "h");
101 else if (index.size == AGX_SIZE_64)
102 fprintf(fp, "d");
103
104 /* Print assigned register if we have one */
105 if (index.has_reg) {
106 fprintf(fp, "(");
107 if (index.memory)
108 fprintf(fp, "m");
109
110 agx_print_reg(index, index.reg, fp);
111 fprintf(fp, ")");
112 }
113 }
114
115 if (index.abs)
116 fprintf(fp, ".abs");
117
118 if (index.neg)
119 fprintf(fp, ".neg");
120 }
121
122 static struct agx_opcode_info
agx_get_opcode_info_for_print(const agx_instr * I)123 agx_get_opcode_info_for_print(const agx_instr *I)
124 {
125 struct agx_opcode_info info = agx_opcodes_info[I->op];
126
127 if (I->op == AGX_OPCODE_BITOP) {
128 const char *bitops[16] = {
129 [AGX_BITOP_NOR] = "nor", [AGX_BITOP_ANDN2] = "andn2",
130 [AGX_BITOP_ANDN1] = "andn1", [AGX_BITOP_XOR] = "xor",
131 [AGX_BITOP_NAND] = "nand", [AGX_BITOP_AND] = "and",
132 [AGX_BITOP_XNOR] = "xnor", [AGX_BITOP_ORN2] = "orn2",
133 [AGX_BITOP_ORN1] = "orn1", [AGX_BITOP_OR] = "or",
134 };
135
136 if (bitops[I->truth_table] != NULL) {
137 info.name = bitops[I->truth_table];
138 info.immediates &= ~AGX_IMMEDIATE_TRUTH_TABLE;
139 }
140 }
141
142 return info;
143 }
144
145 void
agx_print_instr(const agx_instr * I,FILE * fp)146 agx_print_instr(const agx_instr *I, FILE *fp)
147 {
148 assert(I->op < AGX_NUM_OPCODES);
149 struct agx_opcode_info info = agx_get_opcode_info_for_print(I);
150 bool print_comma = false;
151
152 fprintf(fp, " ");
153
154 agx_foreach_dest(I, d) {
155 if (print_comma)
156 fprintf(fp, ", ");
157 else
158 print_comma = true;
159
160 agx_print_index(I->dest[d], false, fp);
161 }
162
163 if (I->nr_dests) {
164 fprintf(fp, " = ");
165 print_comma = false;
166 }
167
168 fprintf(fp, "%s", info.name);
169
170 if (I->saturate)
171 fprintf(fp, ".sat");
172
173 if (I->last)
174 fprintf(fp, ".last");
175
176 fprintf(fp, " ");
177
178 agx_foreach_src(I, s) {
179 if (print_comma)
180 fprintf(fp, ", ");
181 else
182 print_comma = true;
183
184 agx_print_index(I->src[s],
185 agx_opcodes_info[I->op].is_float &&
186 !(s >= 2 && I->op == AGX_OPCODE_FCMPSEL),
187 fp);
188 }
189
190 if (I->mask) {
191 fprintf(fp, ", ");
192
193 for (unsigned i = 0; i < 4; ++i) {
194 if (I->mask & (1 << i))
195 fprintf(fp, "%c", "xyzw"[i]);
196 }
197 }
198
199 /* TODO: Do better for enums, truth tables, etc */
200 if (info.immediates) {
201 if (print_comma)
202 fprintf(fp, ", ");
203 else
204 print_comma = true;
205
206 fprintf(fp, "#%" PRIx64, I->imm);
207 }
208
209 if (info.immediates & AGX_IMMEDIATE_DIM) {
210 if (print_comma)
211 fprintf(fp, ", ");
212 else
213 print_comma = true;
214
215 fputs(agx_dim_as_str(I->dim), fp);
216 }
217
218 if (info.immediates & AGX_IMMEDIATE_SCOREBOARD) {
219 if (print_comma)
220 fprintf(fp, ", ");
221 else
222 print_comma = true;
223
224 fprintf(fp, "slot %u", I->scoreboard);
225 }
226
227 if (info.immediates & AGX_IMMEDIATE_NEST) {
228 if (print_comma)
229 fprintf(fp, ", ");
230 else
231 print_comma = true;
232
233 fprintf(fp, "n=%u", I->nest);
234 }
235
236 if ((info.immediates & AGX_IMMEDIATE_INVERT_COND) && I->invert_cond) {
237 if (print_comma)
238 fprintf(fp, ", ");
239 else
240 print_comma = true;
241
242 fprintf(fp, "inv");
243 }
244
245 fprintf(fp, "\n");
246 }
247
248 void
agx_print_block(const agx_block * block,FILE * fp)249 agx_print_block(const agx_block *block, FILE *fp)
250 {
251 fprintf(fp, "block%u {\n", block->index);
252
253 agx_foreach_instr_in_block(block, ins)
254 agx_print_instr(ins, fp);
255
256 fprintf(fp, "}");
257
258 if (block->successors[0]) {
259 fprintf(fp, " -> ");
260
261 agx_foreach_successor(block, succ)
262 fprintf(fp, "block%u ", succ->index);
263 }
264
265 if (block->predecessors.size) {
266 fprintf(fp, " from");
267
268 agx_foreach_predecessor(block, pred)
269 fprintf(fp, " block%u", (*pred)->index);
270 }
271
272 fprintf(fp, "\n\n");
273 }
274
275 void
agx_print_shader(const agx_context * ctx,FILE * fp)276 agx_print_shader(const agx_context *ctx, FILE *fp)
277 {
278 agx_foreach_block(ctx, block)
279 agx_print_block(block, fp);
280 }
281