1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is 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
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "dxil_dump.h"
25 #include "dxil_internal.h"
26
27 #define DIXL_DUMP_DECL
28 #include "dxil_dump_decls.h"
29
30 #include "dxil_module.h"
31
32
33 #include "util/string_buffer.h"
34 #include "util/list.h"
35
36 #include <stdio.h>
37
38 struct dxil_dumper {
39 struct _mesa_string_buffer *buf;
40 int current_indent;
41 };
42
dxil_dump_create(void)43 struct dxil_dumper *dxil_dump_create(void)
44 {
45 struct dxil_dumper *d = calloc(1, sizeof(struct dxil_dumper));
46 d->buf = _mesa_string_buffer_create(NULL, 1024);
47 d->current_indent = 0;
48 return d;
49 }
50
dxil_dump_free(struct dxil_dumper * d)51 void dxil_dump_free(struct dxil_dumper *d)
52 {
53 _mesa_string_buffer_destroy(d->buf);
54 d->buf = 0;
55 free(d);
56 }
57
dxil_dump_buf_to_file(struct dxil_dumper * d,FILE * f)58 void dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f)
59 {
60 assert(f);
61 assert(d);
62 assert(d->buf);
63 fprintf(f, "%s", d->buf->buf);
64 }
65
66 static
dxil_dump_indention_inc(struct dxil_dumper * d)67 void dxil_dump_indention_inc(struct dxil_dumper *d)
68 {
69 ++d->current_indent;
70 }
71
72 static
dxil_dump_indention_dec(struct dxil_dumper * d)73 void dxil_dump_indention_dec(struct dxil_dumper *d)
74 {
75 --d->current_indent;
76 assert(d->current_indent >= 0);
77 }
78
79 static
dxil_dump_indent(struct dxil_dumper * d)80 void dxil_dump_indent(struct dxil_dumper *d)
81 {
82 for (int i = 0; i < 2 * d->current_indent; ++i)
83 _mesa_string_buffer_append_char(d->buf, ' ');
84 }
85
86 void
dxil_dump_module(struct dxil_dumper * d,struct dxil_module * m)87 dxil_dump_module(struct dxil_dumper *d, struct dxil_module *m)
88 {
89 assert(m);
90 assert(d);
91
92 _mesa_string_buffer_printf(d->buf, "DXIL MODULE:\n");
93 dump_metadata(d, m);
94 dump_shader_info(d, &m->info);
95 dump_types(d, &m->type_list);
96 dump_gvars(d, &m->gvar_list);
97 dump_funcs(d, &m->func_list);
98 dump_attr_set_list(d, &m->attr_set_list);
99 dump_constants(d, &m->const_list);
100
101 struct dxil_func_def *func_def;
102 LIST_FOR_EACH_ENTRY(func_def, &m->func_def_list, head) {
103 dump_instrs(d, &func_def->instr_list);
104 }
105
106 dump_mdnodes(d, &m->mdnode_list);
107 dump_named_nodes(d, &m->md_named_node_list);
108 dump_io_signatures(d->buf, m);
109 dump_psv(d->buf, m);
110 _mesa_string_buffer_printf(d->buf, "END DXIL MODULE\n");
111 }
112
113 static void
dump_metadata(struct dxil_dumper * d,struct dxil_module * m)114 dump_metadata(struct dxil_dumper *d, struct dxil_module *m)
115 {
116 _mesa_string_buffer_printf(d->buf, "Shader: %s\n",
117 dump_shader_string(m->shader_kind));
118
119 _mesa_string_buffer_printf(d->buf, "Version: %d.%d\n",
120 m->major_version, m->minor_version);
121
122 dump_features(d->buf, &m->feats);
123 }
124
125 static void
dump_shader_info(struct dxil_dumper * d,struct dxil_shader_info * info)126 dump_shader_info(struct dxil_dumper *d, struct dxil_shader_info *info)
127 {
128 _mesa_string_buffer_append(d->buf, "Shader Info:\n");
129 if (info->has_out_position)
130 _mesa_string_buffer_append(d->buf, " has_out_position\n");
131 }
132
133 static const char *
dump_shader_string(enum dxil_shader_kind kind)134 dump_shader_string(enum dxil_shader_kind kind)
135 {
136 #define SHADER_STR(X) case DXIL_ ## X ## _SHADER: return #X
137
138 switch (kind) {
139 SHADER_STR(VERTEX);
140 SHADER_STR(PIXEL);
141 SHADER_STR(GEOMETRY);
142 SHADER_STR(COMPUTE);
143 default:
144 return "UNSUPPORTED";
145 }
146 #undef SHADER_STR
147 }
148
149 static void
dump_features(struct _mesa_string_buffer * buf,struct dxil_features * feat)150 dump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat)
151 {
152 _mesa_string_buffer_printf(buf, "Features:\n");
153 #define PRINT_FEAT(F) if (feat->F) _mesa_string_buffer_printf(buf, " %s\n", #F)
154 PRINT_FEAT(doubles);
155 PRINT_FEAT(cs_4x_raw_sb);
156 PRINT_FEAT(uavs_at_every_stage);
157 PRINT_FEAT(use_64uavs);
158 PRINT_FEAT(min_precision);
159 PRINT_FEAT(dx11_1_double_extensions);
160 PRINT_FEAT(dx11_1_shader_extensions);
161 PRINT_FEAT(dx9_comparison_filtering);
162 PRINT_FEAT(tiled_resources);
163 PRINT_FEAT(stencil_ref);
164 PRINT_FEAT(inner_coverage);
165 PRINT_FEAT(typed_uav_load_additional_formats);
166 PRINT_FEAT(rovs);
167 PRINT_FEAT(array_layer_from_vs_or_ds);
168 PRINT_FEAT(wave_ops);
169 PRINT_FEAT(int64_ops);
170 PRINT_FEAT(view_id);
171 PRINT_FEAT(barycentrics);
172 PRINT_FEAT(native_low_precision);
173 PRINT_FEAT(shading_rate);
174 PRINT_FEAT(raytracing_tier_1_1);
175 PRINT_FEAT(sampler_feedback);
176 #undef PRINT_FEAT
177 }
178
179 static void
dump_types(struct dxil_dumper * d,struct list_head * list)180 dump_types(struct dxil_dumper *d, struct list_head *list)
181 {
182 if (!list_length(list))
183 return;
184
185 _mesa_string_buffer_append(d->buf, "Types:\n");
186 dxil_dump_indention_inc(d);
187 list_for_each_entry(struct dxil_type, type, list, head) {
188 dxil_dump_indent(d);
189 dump_type(d, type);
190 _mesa_string_buffer_append(d->buf, "\n");
191 }
192 dxil_dump_indention_dec(d);
193 }
194
dump_type_name(struct dxil_dumper * d,const struct dxil_type * type)195 static void dump_type_name(struct dxil_dumper *d, const struct dxil_type *type)
196 {
197 if (!type) {
198 _mesa_string_buffer_append(d->buf, "(type error)");
199 return;
200 }
201
202 switch (type->type) {
203 case TYPE_VOID:
204 _mesa_string_buffer_append(d->buf, "void");
205 break;
206 case TYPE_INTEGER:
207 _mesa_string_buffer_printf(d->buf, "int%d", type->int_bits);
208 break;
209 case TYPE_FLOAT:
210 _mesa_string_buffer_printf(d->buf, "float%d", type->float_bits);
211 break;
212 case TYPE_POINTER:
213 dump_type_name(d, type->ptr_target_type);
214 _mesa_string_buffer_append(d->buf, "*");
215 break;
216 case TYPE_STRUCT:
217 _mesa_string_buffer_printf(d->buf, "struct %s", type->struct_def.name);
218 break;
219 case TYPE_ARRAY:
220 dump_type_name(d, type->array_or_vector_def.elem_type);
221 _mesa_string_buffer_printf(d->buf, "[%d]", type->array_or_vector_def.num_elems);
222 break;
223 case TYPE_FUNCTION:
224 _mesa_string_buffer_append(d->buf, "(");
225 dump_type_name(d, type->function_def.ret_type);
226 _mesa_string_buffer_append(d->buf, ")(");
227 for (size_t i = 0; i < type->function_def.args.num_types; ++i) {
228 if (i > 0)
229 _mesa_string_buffer_append(d->buf, ", ");
230 dump_type_name(d, type->function_def.args.types[i]);
231 }
232 _mesa_string_buffer_append(d->buf, ")");
233 break;
234 case TYPE_VECTOR:
235 _mesa_string_buffer_append(d->buf, "vector<");
236 dump_type_name(d, type->array_or_vector_def.elem_type);
237 _mesa_string_buffer_printf(d->buf, ", %d>", type->array_or_vector_def.num_elems);
238 break;
239 default:
240 _mesa_string_buffer_printf(d->buf, "unknown type %d", type->type);
241 }
242 }
243
244 static void
dump_type(struct dxil_dumper * d,const struct dxil_type * type)245 dump_type(struct dxil_dumper *d, const struct dxil_type *type)
246 {
247 switch (type->type) {
248 case TYPE_STRUCT:
249 _mesa_string_buffer_printf(d->buf, "struct %s {\n", type->struct_def.name);
250 dxil_dump_indention_inc(d);
251
252 for (size_t i = 0; i < type->struct_def.elem.num_types; ++i) {
253 dxil_dump_indent(d);
254 dump_type(d, type->struct_def.elem.types[i]);
255 _mesa_string_buffer_append(d->buf, "\n");
256 }
257 dxil_dump_indention_dec(d);
258 dxil_dump_indent(d);
259 _mesa_string_buffer_append(d->buf, "}\n");
260 break;
261 default:
262 dump_type_name(d, type);
263 break;
264 }
265 }
266
267 static void
dump_gvars(struct dxil_dumper * d,struct list_head * list)268 dump_gvars(struct dxil_dumper *d, struct list_head *list)
269 {
270 if (!list_length(list))
271 return;
272
273 _mesa_string_buffer_append(d->buf, "Global variables:\n");
274 dxil_dump_indention_inc(d);
275 list_for_each_entry(struct dxil_gvar, gvar, list, head) {
276 dxil_dump_indent(d);
277 _mesa_string_buffer_printf(d->buf, "address_space(%d) ", gvar->as);
278 if (gvar->constant)
279 _mesa_string_buffer_append(d->buf, "const ");
280 if (gvar->align)
281 _mesa_string_buffer_append(d->buf, "align ");
282 if (gvar->initializer)
283 _mesa_string_buffer_printf(d->buf, "init_id:%d\n", gvar->initializer->id);
284 dump_type_name(d, gvar->type);
285 _mesa_string_buffer_printf(d->buf, " val_id:%d\n", gvar->value.id);
286 }
287 dxil_dump_indention_dec(d);
288 }
289
290 static void
dump_funcs(struct dxil_dumper * d,struct list_head * list)291 dump_funcs(struct dxil_dumper *d, struct list_head *list)
292 {
293 if (!list_length(list))
294 return;
295
296 _mesa_string_buffer_append(d->buf, "Functions:\n");
297 dxil_dump_indention_inc(d);
298 list_for_each_entry(struct dxil_func, func, list, head) {
299 dxil_dump_indent(d);
300 if (func->decl)
301 _mesa_string_buffer_append(d->buf, "declare ");
302 _mesa_string_buffer_append(d->buf, func->name);
303 _mesa_string_buffer_append_char(d->buf, ' ');
304 dump_type_name(d, func->type);
305 if (func->attr_set)
306 _mesa_string_buffer_printf(d->buf, " #%d", func->attr_set);
307 _mesa_string_buffer_append_char(d->buf, '\n');
308 }
309 dxil_dump_indention_dec(d);
310 }
311
312 static void
dump_attr_set_list(struct dxil_dumper * d,struct list_head * list)313 dump_attr_set_list(struct dxil_dumper *d, struct list_head *list)
314 {
315 if (!list_length(list))
316 return;
317
318 _mesa_string_buffer_append(d->buf, "Attribute set:\n");
319 dxil_dump_indention_inc(d);
320 int attr_id = 1;
321 list_for_each_entry(struct attrib_set, attr, list, head) {
322 _mesa_string_buffer_printf(d->buf, " #%d: {", attr_id++);
323 for (unsigned i = 0; i < attr->num_attrs; ++i) {
324 if (i > 0)
325 _mesa_string_buffer_append_char(d->buf, ' ');
326
327 assert(attr->attrs[i].type == DXIL_ATTR_ENUM);
328 const char *value = "";
329 switch (attr->attrs[i].kind) {
330 case DXIL_ATTR_KIND_NONE: value = "none"; break;
331 case DXIL_ATTR_KIND_NO_UNWIND: value = "nounwind"; break;
332 case DXIL_ATTR_KIND_READ_NONE: value = "readnone"; break;
333 case DXIL_ATTR_KIND_READ_ONLY: value = "readonly"; break;
334 case DXIL_ATTR_KIND_NO_DUPLICATE: value = "noduplicate"; break;
335 }
336 _mesa_string_buffer_append(d->buf, value);
337 }
338 _mesa_string_buffer_append(d->buf, "}\n");
339 }
340 dxil_dump_indention_dec(d);
341 }
342
343 static void
dump_constants(struct dxil_dumper * d,struct list_head * list)344 dump_constants(struct dxil_dumper *d, struct list_head *list)
345 {
346 if (!list_length(list))
347 return;
348
349 _mesa_string_buffer_append(d->buf, "Constants:\n");
350 dxil_dump_indention_inc(d);
351 list_for_each_entry(struct dxil_const, cnst, list, head) {
352 _mesa_string_buffer_append_char(d->buf, ' ');
353 dump_value(d, &cnst->value);
354 _mesa_string_buffer_append(d->buf, " = ");
355 dump_type_name(d, cnst->value.type);
356 if (!cnst->undef) {
357 switch (cnst->value.type->type) {
358 case TYPE_FLOAT:
359 _mesa_string_buffer_printf(d->buf, " %10.5f\n", cnst->float_value);
360 break;
361 case TYPE_INTEGER:
362 _mesa_string_buffer_printf(d->buf, " %d\n", cnst->int_value);
363 break;
364 case TYPE_ARRAY:
365 _mesa_string_buffer_append(d->buf, "{");
366 for (unsigned i = 0;
367 i < cnst->value.type->array_or_vector_def.num_elems; i++) {
368 _mesa_string_buffer_printf(d->buf, " %%%d",
369 cnst->array_values[i]->id);
370 dump_type_name(d, cnst->value.type);
371 if (i != cnst->value.type->array_or_vector_def.num_elems - 1)
372 _mesa_string_buffer_append(d->buf, ",");
373 _mesa_string_buffer_append(d->buf, " ");
374 }
375 _mesa_string_buffer_append(d->buf, "}\n");
376 break;
377 default:
378 unreachable("Unsupported const type");
379 }
380 } else
381 _mesa_string_buffer_append(d->buf, " undef\n");
382 }
383 dxil_dump_indention_dec(d);
384 }
385
386 static void
dump_instrs(struct dxil_dumper * d,struct list_head * list)387 dump_instrs(struct dxil_dumper *d, struct list_head *list)
388 {
389 _mesa_string_buffer_append(d->buf, "Shader body:\n");
390 dxil_dump_indention_inc(d);
391
392 list_for_each_entry(struct dxil_instr, instr, list, head) {
393
394 dxil_dump_indent(d);
395 if (instr->has_value) {
396 dump_value(d, &instr->value);
397 _mesa_string_buffer_append(d->buf, " = ");
398 } else {
399 _mesa_string_buffer_append_char(d->buf, ' ');
400 }
401
402 switch (instr->type) {
403 case INSTR_BINOP: dump_instr_binop(d, &instr->binop); break;
404 case INSTR_CMP: dump_instr_cmp(d, &instr->cmp);break;
405 case INSTR_SELECT:dump_instr_select(d, &instr->select); break;
406 case INSTR_CAST: dump_instr_cast(d, &instr->cast); break;
407 case INSTR_CALL: dump_instr_call(d, &instr->call); break;
408 case INSTR_RET: dump_instr_ret(d, &instr->ret); break;
409 case INSTR_EXTRACTVAL: dump_instr_extractval(d, &instr->extractval); break;
410 case INSTR_BR: dump_instr_branch(d, &instr->br); break;
411 case INSTR_PHI: dump_instr_phi(d, &instr->phi); break;
412 case INSTR_ALLOCA: dump_instr_alloca(d, &instr->alloca); break;
413 case INSTR_GEP: dump_instr_gep(d, &instr->gep); break;
414 case INSTR_LOAD: dump_instr_load(d, &instr->load); break;
415 case INSTR_STORE: dump_instr_store(d, &instr->store); break;
416 case INSTR_ATOMICRMW: dump_instr_atomicrmw(d, &instr->atomicrmw); break;
417 default:
418 _mesa_string_buffer_printf(d->buf, "unknown instruction type %d", instr->type);
419 }
420
421 _mesa_string_buffer_append(d->buf, "\n");
422 }
423 dxil_dump_indention_dec(d);
424 }
425
426 static void
dump_instr_binop(struct dxil_dumper * d,struct dxil_instr_binop * binop)427 dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop)
428 {
429 const char *str = binop->opcode < DXIL_BINOP_INSTR_COUNT ?
430 binop_strings[binop->opcode] : "INVALID";
431
432 _mesa_string_buffer_printf(d->buf, "%s ", str);
433 dump_instr_print_operands(d, 2, binop->operands);
434 }
435
436 static void
dump_instr_cmp(struct dxil_dumper * d,struct dxil_instr_cmp * cmp)437 dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp)
438 {
439 const char *str = cmp->pred < DXIL_CMP_INSTR_COUNT ?
440 pred_strings[cmp->pred] : "INVALID";
441
442 _mesa_string_buffer_printf(d->buf, "%s ", str);
443 dump_instr_print_operands(d, 2, cmp->operands);
444 }
445
446 static void
dump_instr_select(struct dxil_dumper * d,struct dxil_instr_select * select)447 dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select)
448 {
449 _mesa_string_buffer_append(d->buf, "sel ");
450 dump_instr_print_operands(d, 3, select->operands);
451 }
452
453 static void
dump_instr_cast(struct dxil_dumper * d,struct dxil_instr_cast * cast)454 dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast)
455 {
456 const char *str = cast->opcode < DXIL_CAST_INSTR_COUNT ?
457 cast_opcode_strings[cast->opcode] : "INVALID";
458
459 _mesa_string_buffer_printf(d->buf, "%s.", str);
460 dump_type_name(d, cast->type);
461 _mesa_string_buffer_append_char(d->buf, ' ');
462 dump_value(d, cast->value);
463 }
464
465 static void
dump_instr_call(struct dxil_dumper * d,struct dxil_instr_call * call)466 dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call)
467 {
468 assert(call->num_args == call->func->type->function_def.args.num_types);
469 struct dxil_type **func_arg_types = call->func->type->function_def.args.types;
470
471 _mesa_string_buffer_printf(d->buf, "%s(", call->func->name);
472 for (unsigned i = 0; i < call->num_args; ++i) {
473 if (i > 0)
474 _mesa_string_buffer_append(d->buf, ", ");
475 dump_type_name(d, func_arg_types[i]);
476 _mesa_string_buffer_append_char(d->buf, ' ');
477 dump_value(d, call->args[i]);
478 }
479 _mesa_string_buffer_append_char(d->buf, ')');
480 }
481
482 static void
dump_instr_ret(struct dxil_dumper * d,struct dxil_instr_ret * ret)483 dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret)
484 {
485 _mesa_string_buffer_append(d->buf, "ret ");
486 if (ret->value)
487 dump_value(d, ret->value);
488 }
489
490 static void
dump_instr_extractval(struct dxil_dumper * d,struct dxil_instr_extractval * extr)491 dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *extr)
492 {
493 _mesa_string_buffer_append(d->buf, "extractvalue ");
494 dump_type_name(d, extr->type);
495 dump_value(d, extr->src);
496 _mesa_string_buffer_printf(d->buf, ", %d", extr->idx);
497 }
498
499 static void
dump_instr_branch(struct dxil_dumper * d,struct dxil_instr_br * br)500 dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br)
501 {
502 _mesa_string_buffer_append(d->buf, "branch ");
503 if (br->cond)
504 dump_value(d, br->cond);
505 else
506 _mesa_string_buffer_append(d->buf, " (uncond)");
507 _mesa_string_buffer_printf(d->buf, " %d %d", br->succ[0], br->succ[1]);
508 }
509
510 static void
dump_instr_phi(struct dxil_dumper * d,struct dxil_instr_phi * phi)511 dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi)
512 {
513 _mesa_string_buffer_append(d->buf, "phi ");
514 dump_type_name(d, phi->type);
515 struct dxil_phi_src *src = phi->incoming;
516 for (unsigned i = 0; i < phi->num_incoming; ++i, ++src) {
517 if (i > 0)
518 _mesa_string_buffer_append(d->buf, ", ");
519 dump_value(d, src->value);
520 _mesa_string_buffer_printf(d->buf, "(%d)", src->block);
521 }
522 }
523
524 static void
dump_instr_alloca(struct dxil_dumper * d,struct dxil_instr_alloca * alloca)525 dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca)
526 {
527 _mesa_string_buffer_append(d->buf, "alloca ");
528 dump_type_name(d, alloca->alloc_type);
529 _mesa_string_buffer_append(d->buf, ", ");
530 dump_type_name(d, alloca->size_type);
531 _mesa_string_buffer_append(d->buf, ", ");
532 dump_value(d, alloca->size);
533 unsigned align_mask = (1 << 6 ) - 1;
534 unsigned align = alloca->align & align_mask;
535 _mesa_string_buffer_printf(d->buf, ", %d", 1 << (align - 1));
536 }
537
538 static void
dump_instr_gep(struct dxil_dumper * d,struct dxil_instr_gep * gep)539 dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep)
540 {
541 _mesa_string_buffer_append(d->buf, "getelementptr ");
542 if (gep->inbounds)
543 _mesa_string_buffer_append(d->buf, "inbounds ");
544 dump_type_name(d, gep->source_elem_type);
545 _mesa_string_buffer_append(d->buf, ", ");
546 for (unsigned i = 0; i < gep->num_operands; ++i) {
547 if (i > 0)
548 _mesa_string_buffer_append(d->buf, ", ");
549 dump_value(d, gep->operands[i]);
550 }
551 }
552
553 static void
dump_instr_load(struct dxil_dumper * d,struct dxil_instr_load * load)554 dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *load)
555 {
556 _mesa_string_buffer_append(d->buf, "load ");
557 if (load->is_volatile)
558 _mesa_string_buffer_append(d->buf, " volatile");
559 dump_type_name(d, load->type);
560 _mesa_string_buffer_append(d->buf, ", ");
561 dump_value(d, load->ptr);
562 _mesa_string_buffer_printf(d->buf, ", %d", load->align);
563 }
564
565 static void
dump_instr_store(struct dxil_dumper * d,struct dxil_instr_store * store)566 dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store)
567 {
568 _mesa_string_buffer_append(d->buf, "store ");
569 if (store->is_volatile)
570 _mesa_string_buffer_append(d->buf, " volatile");
571 dump_value(d, store->value);
572 _mesa_string_buffer_append(d->buf, ", ");
573 dump_value(d, store->ptr);
574 _mesa_string_buffer_printf(d->buf, ", %d", store->align);
575 }
576
577 static const char *rmworder_str[] = {
578 [DXIL_ATOMIC_ORDERING_NOTATOMIC] = "not-atomic",
579 [DXIL_ATOMIC_ORDERING_UNORDERED] = "unordered",
580 [DXIL_ATOMIC_ORDERING_MONOTONIC] = "monotonic",
581 [DXIL_ATOMIC_ORDERING_ACQUIRE] = "acquire",
582 [DXIL_ATOMIC_ORDERING_RELEASE] = "release",
583 [DXIL_ATOMIC_ORDERING_ACQREL] = "acqrel",
584 [DXIL_ATOMIC_ORDERING_SEQCST] = "seqcst",
585 };
586
587 static const char *rmwsync_str[] = {
588 [DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread",
589 [DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread",
590 };
591
592 static const char *rmwop_str[] = {
593 [DXIL_RMWOP_XCHG] = "xchg",
594 [DXIL_RMWOP_ADD] = "add",
595 [DXIL_RMWOP_SUB] = "sub",
596 [DXIL_RMWOP_AND] = "and",
597 [DXIL_RMWOP_NAND] = "nand",
598 [DXIL_RMWOP_OR] = "or",
599 [DXIL_RMWOP_XOR] = "xor",
600 [DXIL_RMWOP_MAX] = "max",
601 [DXIL_RMWOP_MIN] = "min",
602 [DXIL_RMWOP_UMAX] = "umax",
603 [DXIL_RMWOP_UMIN] = "umin",
604 };
605
606 static void
dump_instr_atomicrmw(struct dxil_dumper * d,struct dxil_instr_atomicrmw * rmw)607 dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw)
608 {
609 _mesa_string_buffer_printf(d->buf, "atomicrmw.%s ", rmwop_str[rmw->op]);
610
611 if (rmw->is_volatile)
612 _mesa_string_buffer_append(d->buf, " volatile");
613 dump_value(d, rmw->value);
614 _mesa_string_buffer_append(d->buf, ", ");
615 dump_value(d, rmw->ptr);
616 _mesa_string_buffer_printf(d->buf, ", ordering(%s)", rmworder_str[rmw->ordering]);
617 _mesa_string_buffer_printf(d->buf, ", sync_scope(%s)", rmwsync_str[rmw->syncscope]);
618 }
619
620 static void
dump_instr_print_operands(struct dxil_dumper * d,int num,const struct dxil_value * val[])621 dump_instr_print_operands(struct dxil_dumper *d, int num,
622 const struct dxil_value *val[])
623 {
624 for (int i = 0; i < num; ++i) {
625 if (i > 0)
626 _mesa_string_buffer_append(d->buf, ", ");
627 dump_value(d, val[i]);
628 }
629 }
630
631 static void
dump_value(struct dxil_dumper * d,const struct dxil_value * val)632 dump_value(struct dxil_dumper *d, const struct dxil_value *val)
633 {
634 if (val->id < 10)
635 _mesa_string_buffer_append(d->buf, " ");
636 if (val->id < 100)
637 _mesa_string_buffer_append(d->buf, " ");
638 _mesa_string_buffer_printf(d->buf, "%%%d", val->id);
639 dump_type_name(d, val->type);
640 }
641
642 static void
dump_mdnodes(struct dxil_dumper * d,struct list_head * list)643 dump_mdnodes(struct dxil_dumper *d, struct list_head *list)
644 {
645 if (!list_length(list))
646 return;
647
648 _mesa_string_buffer_append(d->buf, "MD-Nodes:\n");
649 dxil_dump_indention_inc(d);
650 list_for_each_entry(struct dxil_mdnode, node, list, head) {
651 dump_mdnode(d, node);
652 }
653 dxil_dump_indention_dec(d);
654 }
655
656 static void
dump_mdnode(struct dxil_dumper * d,const struct dxil_mdnode * node)657 dump_mdnode(struct dxil_dumper *d, const struct dxil_mdnode *node)
658 {
659 dxil_dump_indent(d);
660 switch (node->type) {
661 case MD_STRING:
662 _mesa_string_buffer_printf(d->buf, "S:%s\n", node->string);
663 break;
664 case MD_VALUE:
665 _mesa_string_buffer_append(d->buf, "V:");
666 dump_type_name(d, node->value.type);
667 _mesa_string_buffer_append_char(d->buf, ' ');
668 dump_value(d, node->value.value);
669 _mesa_string_buffer_append_char(d->buf, '\n');
670 break;
671 case MD_NODE:
672 _mesa_string_buffer_append(d->buf, " \\\n");
673 dxil_dump_indention_inc(d);
674 for (size_t i = 0; i < node->node.num_subnodes; ++i) {
675 if (node->node.subnodes[i])
676 dump_mdnode(d, node->node.subnodes[i]);
677 else {
678 dxil_dump_indent(d);
679 _mesa_string_buffer_append(d->buf, "(nullptr)\n");
680 }
681 }
682 dxil_dump_indention_dec(d);
683 break;
684 }
685 }
686
687 static void
dump_named_nodes(struct dxil_dumper * d,struct list_head * list)688 dump_named_nodes(struct dxil_dumper *d, struct list_head *list)
689 {
690 if (!list_length(list))
691 return;
692
693 _mesa_string_buffer_append(d->buf, "Named Nodes:\n");
694 dxil_dump_indention_inc(d);
695 list_for_each_entry(struct dxil_named_node, node, list, head) {
696 dxil_dump_indent(d);
697 _mesa_string_buffer_printf(d->buf, "%s:\n", node->name);
698 dxil_dump_indention_inc(d);
699 for (size_t i = 0; i < node->num_subnodes; ++i) {
700 if (node->subnodes[i])
701 dump_mdnode(d, node->subnodes[i]);
702 else {
703 dxil_dump_indent(d);
704 _mesa_string_buffer_append(d->buf, "(nullptr)\n");
705 }
706 }
707 dxil_dump_indention_dec(d);
708 }
709 dxil_dump_indention_dec(d);
710 }
711
712 static void
mask_to_string(uint32_t mask,char str[5])713 mask_to_string(uint32_t mask, char str[5])
714 {
715 const char *mc = "xyzw";
716 for (int i = 0; i < 4 && mask; ++i) {
717 str[i] = (mask & (1 << i)) ? mc[i] : '_';
718 }
719 str[4] = 0;
720 }
721
dump_io_signatures(struct _mesa_string_buffer * buf,struct dxil_module * m)722 static void dump_io_signatures(struct _mesa_string_buffer *buf, struct dxil_module *m)
723 {
724 _mesa_string_buffer_append(buf, "\nInput signature:\n");
725 dump_io_signature(buf, m->num_sig_inputs, m->inputs);
726 _mesa_string_buffer_append(buf, "\nOutput signature:\n");
727 dump_io_signature(buf, m->num_sig_outputs, m->outputs);
728 }
729
dump_io_signature(struct _mesa_string_buffer * buf,unsigned num,struct dxil_signature_record * io)730 static void dump_io_signature(struct _mesa_string_buffer *buf, unsigned num,
731 struct dxil_signature_record *io)
732 {
733 _mesa_string_buffer_append(buf, " SEMANTIC-NAME Index Mask Reg SysValue Format\n");
734 _mesa_string_buffer_append(buf, "----------------------------------------------\n");
735 for (unsigned i = 0; i < num; ++i, ++io) {
736 for (unsigned j = 0; j < io->num_elements; ++j) {
737 char mask[5] = "";
738 mask_to_string(io->elements[j].mask, mask);
739 _mesa_string_buffer_printf(buf, "%-15s %3d %4s %3d %-8s %-7s\n",
740 io->name, io->elements[j].semantic_index,
741 mask, io->elements[j].reg, io->sysvalue,
742 component_type_as_string(io->elements[j].comp_type));
743 }
744 }
745 }
746
component_type_as_string(uint32_t type)747 static const char *component_type_as_string(uint32_t type)
748 {
749 return (type < DXIL_PROG_SIG_COMP_TYPE_COUNT) ?
750 dxil_type_strings[type] : "invalid";
751 }
752
dump_psv(struct _mesa_string_buffer * buf,struct dxil_module * m)753 static void dump_psv(struct _mesa_string_buffer *buf,
754 struct dxil_module *m)
755 {
756 _mesa_string_buffer_append(buf, "\nPipeline State Validation\nInputs:\n");
757 dump_psv_io(buf, m, m->num_sig_inputs, m->psv_inputs);
758 _mesa_string_buffer_append(buf, "\nOutputs:\n");
759 dump_psv_io(buf, m, m->num_sig_outputs, m->psv_outputs);
760 }
761
dump_psv_io(struct _mesa_string_buffer * buf,struct dxil_module * m,unsigned num,struct dxil_psv_signature_element * io)762 static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m,
763 unsigned num, struct dxil_psv_signature_element *io)
764 {
765 _mesa_string_buffer_append(buf, " SEMANTIC-NAME Rows Cols Kind Comp-Type Interp dynmask+stream Indices\n");
766 _mesa_string_buffer_append(buf, "----------------------------------------------\n");
767 for (unsigned i = 0; i < num; ++i, ++io) {
768 _mesa_string_buffer_printf(buf, "%-14s %d+%d %d+%d %4d %-7s %-4d %-9d [",
769 m->sem_string_table->buf + io->semantic_name_offset,
770 (int)io->start_row, (int)io->rows,
771 (int)((io->cols_and_start & 0xf) >> 4),
772 (int)(io->cols_and_start & 0xf),
773 (int)io->semantic_kind,
774 component_type_as_string(io->component_type),
775 (int)io->interpolation_mode,
776 (int)io->dynamic_mask_and_stream);
777 for (int k = 0; k < io->rows; ++k) {
778 if (k > 0)
779 _mesa_string_buffer_append(buf, ", ");
780 _mesa_string_buffer_printf(buf,"%d ", m->sem_index_table.data[io->start_row + k]);
781 }
782 _mesa_string_buffer_append(buf, "]\n");
783 }
784 }
785