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