xref: /aosp_15_r20/external/mesa3d/src/microsoft/compiler/dxil_dump.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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, "[%zu]", 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, ", %zu>", 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          if (attr->attrs[i].type == DXIL_ATTR_ENUM) {
328             const char *value = "";
329             switch (attr->attrs[i].key.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          } else if (attr->attrs[i].type == DXIL_ATTR_STRING) {
338             _mesa_string_buffer_append_char(d->buf, '"');
339             _mesa_string_buffer_append(d->buf, attr->attrs[i].key.str);
340             _mesa_string_buffer_append_char(d->buf, '"');
341          } else if (attr->attrs[i].type == DXIL_ATTR_STRING_VALUE) {
342             _mesa_string_buffer_append_char(d->buf, '"');
343             _mesa_string_buffer_append(d->buf, attr->attrs[i].key.str);
344             _mesa_string_buffer_append(d->buf, "\"=\"");
345             _mesa_string_buffer_append(d->buf, attr->attrs[i].value.str);
346             _mesa_string_buffer_append_char(d->buf, '"');
347          }
348       }
349       _mesa_string_buffer_append(d->buf, "}\n");
350    }
351    dxil_dump_indention_dec(d);
352 }
353 
354 static void
dump_constants(struct dxil_dumper * d,struct list_head * list)355 dump_constants(struct dxil_dumper *d, struct list_head *list)
356 {
357    if (!list_length(list))
358       return;
359 
360    _mesa_string_buffer_append(d->buf, "Constants:\n");
361    dxil_dump_indention_inc(d);
362    list_for_each_entry(struct dxil_const, cnst, list, head) {
363       _mesa_string_buffer_append_char(d->buf, ' ');
364       dump_value(d, &cnst->value);
365       _mesa_string_buffer_append(d->buf, " = ");
366       dump_type_name(d, cnst->value.type);
367       if (!cnst->undef) {
368          switch (cnst->value.type->type) {
369          case TYPE_FLOAT:
370             _mesa_string_buffer_printf(d->buf, " %10.5f\n", cnst->float_value);
371             break;
372          case TYPE_INTEGER:
373             _mesa_string_buffer_printf(d->buf, " %" PRIdMAX "\n", cnst->int_value);
374             break;
375          case TYPE_ARRAY:
376             _mesa_string_buffer_append(d->buf, "{");
377             for (unsigned i = 0;
378                  i < cnst->value.type->array_or_vector_def.num_elems; i++) {
379                _mesa_string_buffer_printf(d->buf, " %%%d",
380                                           cnst->array_values[i]->id);
381                dump_type_name(d, cnst->value.type);
382                if (i != cnst->value.type->array_or_vector_def.num_elems - 1)
383                   _mesa_string_buffer_append(d->buf, ",");
384                _mesa_string_buffer_append(d->buf, " ");
385             }
386             _mesa_string_buffer_append(d->buf, "}\n");
387             break;
388          case TYPE_STRUCT:
389             _mesa_string_buffer_append(d->buf, "{");
390             for (unsigned i = 0;
391                  i < cnst->value.type->struct_def.elem.num_types; i++) {
392                _mesa_string_buffer_printf(d->buf, " %%%d",
393                                           cnst->struct_values[i]->id);
394                dump_type_name(d, cnst->struct_values[i]->type);
395                if (i != cnst->value.type->struct_def.elem.num_types - 1)
396                   _mesa_string_buffer_append(d->buf, ",");
397                _mesa_string_buffer_append(d->buf, " ");
398             }
399             _mesa_string_buffer_append(d->buf, "}\n");
400             break;
401          default:
402             unreachable("Unsupported const type");
403          }
404       } else
405          _mesa_string_buffer_append(d->buf, " undef\n");
406    }
407    dxil_dump_indention_dec(d);
408 }
409 
410 static void
dump_instrs(struct dxil_dumper * d,struct list_head * list)411 dump_instrs(struct dxil_dumper *d, struct list_head *list)
412 {
413    _mesa_string_buffer_append(d->buf, "Shader body:\n");
414    dxil_dump_indention_inc(d);
415 
416    list_for_each_entry(struct dxil_instr, instr, list, head) {
417 
418       dxil_dump_indent(d);
419       if (instr->has_value) {
420          dump_value(d, &instr->value);
421          _mesa_string_buffer_append(d->buf, " = ");
422       } else {
423          _mesa_string_buffer_append_char(d->buf, ' ');
424       }
425 
426       switch (instr->type) {
427       case INSTR_BINOP: dump_instr_binop(d, &instr->binop); break;
428       case INSTR_CMP:   dump_instr_cmp(d, &instr->cmp);break;
429       case INSTR_SELECT:dump_instr_select(d, &instr->select); break;
430       case INSTR_CAST:  dump_instr_cast(d, &instr->cast); break;
431       case INSTR_CALL:  dump_instr_call(d, &instr->call); break;
432       case INSTR_RET:   dump_instr_ret(d, &instr->ret); break;
433       case INSTR_EXTRACTVAL: dump_instr_extractval(d, &instr->extractval); break;
434       case INSTR_BR:  dump_instr_branch(d, &instr->br); break;
435       case INSTR_PHI:  dump_instr_phi(d, &instr->phi); break;
436       case INSTR_ALLOCA: dump_instr_alloca(d, &instr->alloca); break;
437       case INSTR_GEP: dump_instr_gep(d, &instr->gep); break;
438       case INSTR_LOAD: dump_instr_load(d, &instr->load); break;
439       case INSTR_STORE: dump_instr_store(d, &instr->store); break;
440       case INSTR_ATOMICRMW: dump_instr_atomicrmw(d, &instr->atomicrmw); break;
441       default:
442          _mesa_string_buffer_printf(d->buf, "unknown instruction type %d", instr->type);
443       }
444 
445       _mesa_string_buffer_append(d->buf, "\n");
446    }
447    dxil_dump_indention_dec(d);
448 }
449 
450 static void
dump_instr_binop(struct dxil_dumper * d,struct dxil_instr_binop * binop)451 dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop)
452 {
453    const char *str = binop->opcode < DXIL_BINOP_INSTR_COUNT ?
454                         binop_strings[binop->opcode] : "INVALID";
455 
456    _mesa_string_buffer_printf(d->buf, "%s ", str);
457    dump_instr_print_operands(d, 2, binop->operands);
458 }
459 
460 static void
dump_instr_cmp(struct dxil_dumper * d,struct dxil_instr_cmp * cmp)461 dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp)
462 {
463    const char *str = cmp->pred < DXIL_CMP_INSTR_COUNT ?
464                         pred_strings[cmp->pred] : "INVALID";
465 
466    _mesa_string_buffer_printf(d->buf, "%s ", str);
467    dump_instr_print_operands(d, 2, cmp->operands);
468 }
469 
470 static void
dump_instr_select(struct dxil_dumper * d,struct dxil_instr_select * select)471 dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select)
472 {
473    _mesa_string_buffer_append(d->buf, "sel ");
474    dump_instr_print_operands(d, 3, select->operands);
475 }
476 
477 static void
dump_instr_cast(struct dxil_dumper * d,struct dxil_instr_cast * cast)478 dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast)
479 {
480    const char *str = cast->opcode < DXIL_CAST_INSTR_COUNT ?
481                         cast_opcode_strings[cast->opcode] : "INVALID";
482 
483    _mesa_string_buffer_printf(d->buf, "%s.", str);
484    dump_type_name(d, cast->type);
485    _mesa_string_buffer_append_char(d->buf, ' ');
486    dump_value(d, cast->value);
487 }
488 
489 static void
dump_instr_call(struct dxil_dumper * d,struct dxil_instr_call * call)490 dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call)
491 {
492    assert(call->num_args == call->func->type->function_def.args.num_types);
493    struct dxil_type **func_arg_types = call->func->type->function_def.args.types;
494 
495    _mesa_string_buffer_printf(d->buf, "%s(", call->func->name);
496    for (unsigned i = 0; i < call->num_args; ++i) {
497       if (i > 0)
498          _mesa_string_buffer_append(d->buf, ", ");
499       dump_type_name(d, func_arg_types[i]);
500       _mesa_string_buffer_append_char(d->buf, ' ');
501       dump_value(d, call->args[i]);
502    }
503    _mesa_string_buffer_append_char(d->buf, ')');
504 }
505 
506 static void
dump_instr_ret(struct dxil_dumper * d,struct dxil_instr_ret * ret)507 dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret)
508 {
509    _mesa_string_buffer_append(d->buf, "ret ");
510    if (ret->value)
511       dump_value(d, ret->value);
512 }
513 
514 static void
dump_instr_extractval(struct dxil_dumper * d,struct dxil_instr_extractval * extr)515 dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *extr)
516 {
517    _mesa_string_buffer_append(d->buf, "extractvalue ");
518    dump_type_name(d, extr->type);
519    dump_value(d, extr->src);
520    _mesa_string_buffer_printf(d->buf, ", %d", extr->idx);
521 }
522 
523 static void
dump_instr_branch(struct dxil_dumper * d,struct dxil_instr_br * br)524 dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br)
525 {
526    _mesa_string_buffer_append(d->buf, "branch ");
527    if (br->cond)
528       dump_value(d, br->cond);
529    else
530       _mesa_string_buffer_append(d->buf, " (uncond)");
531    _mesa_string_buffer_printf(d->buf, " %d %d", br->succ[0], br->succ[1]);
532 }
533 
534 static void
dump_instr_phi(struct dxil_dumper * d,struct dxil_instr_phi * phi)535 dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi)
536 {
537    _mesa_string_buffer_append(d->buf, "phi ");
538    dump_type_name(d, phi->type);
539    struct dxil_phi_src *src = phi->incoming;
540    for (unsigned i = 0; i < phi->num_incoming; ++i, ++src) {
541       if (i > 0)
542          _mesa_string_buffer_append(d->buf, ", ");
543       dump_value(d, src->value);
544       _mesa_string_buffer_printf(d->buf, "(%d)", src->block);
545    }
546 }
547 
548 static void
dump_instr_alloca(struct dxil_dumper * d,struct dxil_instr_alloca * alloca)549 dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca)
550 {
551    _mesa_string_buffer_append(d->buf, "alloca ");
552    dump_type_name(d, alloca->alloc_type);
553    _mesa_string_buffer_append(d->buf, ", ");
554    dump_type_name(d, alloca->size_type);
555    _mesa_string_buffer_append(d->buf, ", ");
556    dump_value(d, alloca->size);
557    unsigned align_mask = (1 << 6 ) - 1;
558    unsigned align = alloca->align & align_mask;
559    _mesa_string_buffer_printf(d->buf, ", %d", 1 << (align - 1));
560 }
561 
562 static void
dump_instr_gep(struct dxil_dumper * d,struct dxil_instr_gep * gep)563 dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep)
564 {
565    _mesa_string_buffer_append(d->buf, "getelementptr ");
566    if (gep->inbounds)
567       _mesa_string_buffer_append(d->buf, "inbounds ");
568    dump_type_name(d, gep->source_elem_type);
569    _mesa_string_buffer_append(d->buf, ", ");
570    for (unsigned i = 0; i < gep->num_operands; ++i) {
571       if (i > 0)
572          _mesa_string_buffer_append(d->buf, ", ");
573       dump_value(d, gep->operands[i]);
574    }
575 }
576 
577 static void
dump_instr_load(struct dxil_dumper * d,struct dxil_instr_load * load)578 dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *load)
579 {
580    _mesa_string_buffer_append(d->buf, "load ");
581    if (load->is_volatile)
582       _mesa_string_buffer_append(d->buf, " volatile");
583    dump_type_name(d, load->type);
584    _mesa_string_buffer_append(d->buf, ", ");
585    dump_value(d, load->ptr);
586    _mesa_string_buffer_printf(d->buf, ", %d", load->align);
587 }
588 
589 static void
dump_instr_store(struct dxil_dumper * d,struct dxil_instr_store * store)590 dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store)
591 {
592    _mesa_string_buffer_append(d->buf, "store ");
593    if (store->is_volatile)
594       _mesa_string_buffer_append(d->buf, " volatile");
595    dump_value(d, store->value);
596    _mesa_string_buffer_append(d->buf, ", ");
597    dump_value(d, store->ptr);
598    _mesa_string_buffer_printf(d->buf, ", %d", store->align);
599 }
600 
601 static const char *rmworder_str[] = {
602    [DXIL_ATOMIC_ORDERING_NOTATOMIC] = "not-atomic",
603    [DXIL_ATOMIC_ORDERING_UNORDERED] = "unordered",
604    [DXIL_ATOMIC_ORDERING_MONOTONIC] = "monotonic",
605    [DXIL_ATOMIC_ORDERING_ACQUIRE] = "acquire",
606    [DXIL_ATOMIC_ORDERING_RELEASE] = "release",
607    [DXIL_ATOMIC_ORDERING_ACQREL] = "acqrel",
608    [DXIL_ATOMIC_ORDERING_SEQCST] = "seqcst",
609 };
610 
611 static const char *rmwsync_str[] = {
612    [DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread",
613    [DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread",
614 };
615 
616 static const char *rmwop_str[] = {
617    [DXIL_RMWOP_XCHG] = "xchg",
618    [DXIL_RMWOP_ADD] = "add",
619    [DXIL_RMWOP_SUB] = "sub",
620    [DXIL_RMWOP_AND] = "and",
621    [DXIL_RMWOP_NAND] = "nand",
622    [DXIL_RMWOP_OR] = "or",
623    [DXIL_RMWOP_XOR] = "xor",
624    [DXIL_RMWOP_MAX] = "max",
625    [DXIL_RMWOP_MIN] = "min",
626    [DXIL_RMWOP_UMAX] = "umax",
627    [DXIL_RMWOP_UMIN] = "umin",
628 };
629 
630 static void
dump_instr_atomicrmw(struct dxil_dumper * d,struct dxil_instr_atomicrmw * rmw)631 dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw)
632 {
633    _mesa_string_buffer_printf(d->buf, "atomicrmw.%s ", rmwop_str[rmw->op]);
634 
635    if (rmw->is_volatile)
636       _mesa_string_buffer_append(d->buf, " volatile");
637    dump_value(d, rmw->value);
638    _mesa_string_buffer_append(d->buf, ", ");
639    dump_value(d, rmw->ptr);
640    _mesa_string_buffer_printf(d->buf, ", ordering(%s)", rmworder_str[rmw->ordering]);
641    _mesa_string_buffer_printf(d->buf, ", sync_scope(%s)", rmwsync_str[rmw->syncscope]);
642 }
643 
644 static void
dump_instr_print_operands(struct dxil_dumper * d,int num,const struct dxil_value * val[])645 dump_instr_print_operands(struct dxil_dumper *d, int num,
646                           const struct dxil_value *val[])
647 {
648    for (int i = 0; i < num; ++i) {
649       if (i > 0)
650          _mesa_string_buffer_append(d->buf, ", ");
651       dump_value(d, val[i]);
652    }
653 }
654 
655 static void
dump_value(struct dxil_dumper * d,const struct dxil_value * val)656 dump_value(struct dxil_dumper *d, const struct dxil_value *val)
657 {
658    if (val->id < 10)
659       _mesa_string_buffer_append(d->buf, " ");
660    if (val->id < 100)
661       _mesa_string_buffer_append(d->buf, " ");
662    _mesa_string_buffer_printf(d->buf, "%%%d", val->id);
663   dump_type_name(d, val->type);
664 }
665 
666 static void
dump_mdnodes(struct dxil_dumper * d,struct list_head * list)667 dump_mdnodes(struct dxil_dumper *d, struct list_head *list)
668 {
669    if (!list_length(list))
670       return;
671 
672    _mesa_string_buffer_append(d->buf, "MD-Nodes:\n");
673    dxil_dump_indention_inc(d);
674    list_for_each_entry(struct dxil_mdnode, node, list, head) {
675       dump_mdnode(d, node);
676    }
677    dxil_dump_indention_dec(d);
678 }
679 
680 static void
dump_mdnode(struct dxil_dumper * d,const struct dxil_mdnode * node)681 dump_mdnode(struct dxil_dumper *d, const struct dxil_mdnode *node)
682 {
683    dxil_dump_indent(d);
684    switch (node->type) {
685    case MD_STRING:
686       _mesa_string_buffer_printf(d->buf, "S:%s\n", node->string);
687       break;
688    case MD_VALUE:
689       _mesa_string_buffer_append(d->buf, "V:");
690       dump_type_name(d, node->value.type);
691       _mesa_string_buffer_append_char(d->buf, ' ');
692       dump_value(d, node->value.value);
693       _mesa_string_buffer_append_char(d->buf, '\n');
694       break;
695    case MD_NODE:
696       _mesa_string_buffer_append(d->buf, " \\\n");
697       dxil_dump_indention_inc(d);
698       for (size_t i = 0; i < node->node.num_subnodes; ++i) {
699          if (node->node.subnodes[i])
700             dump_mdnode(d, node->node.subnodes[i]);
701          else {
702             dxil_dump_indent(d);
703             _mesa_string_buffer_append(d->buf, "(nullptr)\n");
704          }
705       }
706       dxil_dump_indention_dec(d);
707       break;
708    }
709 }
710 
711 static void
dump_named_nodes(struct dxil_dumper * d,struct list_head * list)712 dump_named_nodes(struct dxil_dumper *d, struct list_head *list)
713 {
714    if (!list_length(list))
715       return;
716 
717    _mesa_string_buffer_append(d->buf, "Named Nodes:\n");
718    dxil_dump_indention_inc(d);
719    list_for_each_entry(struct dxil_named_node, node, list, head) {
720       dxil_dump_indent(d);
721       _mesa_string_buffer_printf(d->buf, "%s:\n", node->name);
722       dxil_dump_indention_inc(d);
723       for (size_t i = 0; i < node->num_subnodes; ++i) {
724          if (node->subnodes[i])
725             dump_mdnode(d, node->subnodes[i]);
726          else {
727             dxil_dump_indent(d);
728             _mesa_string_buffer_append(d->buf, "(nullptr)\n");
729          }
730       }
731       dxil_dump_indention_dec(d);
732    }
733    dxil_dump_indention_dec(d);
734 }
735 
736 static void
mask_to_string(uint32_t mask,char str[5])737 mask_to_string(uint32_t mask, char str[5])
738 {
739    const char *mc = "xyzw";
740    for (int i = 0; i < 4 && mask; ++i) {
741       str[i] = (mask & (1 << i)) ? mc[i] : '_';
742    }
743    str[4] = 0;
744 }
745 
dump_io_signatures(struct _mesa_string_buffer * buf,struct dxil_module * m)746 static void dump_io_signatures(struct _mesa_string_buffer *buf, struct dxil_module *m)
747 {
748    _mesa_string_buffer_append(buf, "\nInput signature:\n");
749    dump_io_signature(buf, m->num_sig_inputs, m->inputs);
750    _mesa_string_buffer_append(buf, "\nOutput signature:\n");
751    dump_io_signature(buf, m->num_sig_outputs, m->outputs);
752 }
753 
dump_io_signature(struct _mesa_string_buffer * buf,unsigned num,struct dxil_signature_record * io)754 static void dump_io_signature(struct _mesa_string_buffer *buf, unsigned num,
755                               struct dxil_signature_record *io)
756 {
757    _mesa_string_buffer_append(buf, " SEMANTIC-NAME Index Mask Reg SysValue Format\n");
758    _mesa_string_buffer_append(buf, "----------------------------------------------\n");
759    for (unsigned i = 0; i < num; ++i, ++io)  {
760       for (unsigned j = 0; j < io->num_elements; ++j) {
761          char mask[5] = "";
762          mask_to_string(io->elements[j].mask, mask);
763          _mesa_string_buffer_printf(buf, "%-15s %3d %4s %3d %-8s %-7s\n",
764                                     io->name, io->elements[j].semantic_index,
765                                     mask, io->elements[j].reg, io->sysvalue,
766                                     component_type_as_string(io->elements[j].comp_type));
767       }
768    }
769 }
770 
component_type_as_string(uint32_t type)771 static const char *component_type_as_string(uint32_t type)
772 {
773    return  (type < DXIL_PROG_SIG_COMP_TYPE_COUNT) ?
774             dxil_type_strings[type] : "invalid";
775 }
776 
dump_psv(struct _mesa_string_buffer * buf,struct dxil_module * m)777 static void dump_psv(struct _mesa_string_buffer *buf,
778                      struct dxil_module *m)
779 {
780    _mesa_string_buffer_append(buf, "\nPipeline State Validation\nInputs:\n");
781    dump_psv_io(buf, m, m->num_sig_inputs, m->psv_inputs);
782    _mesa_string_buffer_append(buf, "\nOutputs:\n");
783    dump_psv_io(buf, m, m->num_sig_outputs, m->psv_outputs);
784 }
785 
dump_psv_io(struct _mesa_string_buffer * buf,struct dxil_module * m,unsigned num,struct dxil_psv_signature_element * io)786 static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m,
787                         unsigned num, struct dxil_psv_signature_element *io)
788 {
789    _mesa_string_buffer_append(buf, " SEMANTIC-NAME Rows Cols Kind Comp-Type Interp dynmask+stream Indices\n");
790    _mesa_string_buffer_append(buf, "----------------------------------------------\n");
791    for (unsigned  i = 0; i < num; ++i, ++io)  {
792       _mesa_string_buffer_printf(buf, "%-14s %d+%d  %d+%d %4d   %-7s    %-4d        %-9d [",
793               m->sem_string_table->buf + io->semantic_name_offset,
794               (int)io->start_row, (int)io->rows,
795               (int)((io->cols_and_start & 0xf) >> 4),
796               (int)(io->cols_and_start & 0xf),
797               (int)io->semantic_kind,
798               component_type_as_string(io->component_type),
799               (int)io->interpolation_mode,
800               (int)io->dynamic_mask_and_stream);
801       for (int k = 0; k < io->rows; ++k) {
802          if (k > 0)
803             _mesa_string_buffer_append(buf, ", ");
804          _mesa_string_buffer_printf(buf,"%d ", m->sem_index_table.data[io->start_row  + k]);
805       }
806       _mesa_string_buffer_append(buf, "]\n");
807    }
808 }
809