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
38struct dxil_dumper {
39   struct _mesa_string_buffer *buf;
40   int current_indent;
41};
42
43struct 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
51void dxil_dump_free(struct dxil_dumper *d)
52{
53   _mesa_string_buffer_destroy(d->buf);
54   d->buf = 0;
55   free(d);
56}
57
58void 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
66static
67void dxil_dump_indention_inc(struct dxil_dumper *d)
68{
69   ++d->current_indent;
70}
71
72static
73void dxil_dump_indention_dec(struct dxil_dumper *d)
74{
75   --d->current_indent;
76   assert(d->current_indent >= 0);
77}
78
79static
80void 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
86void
87dxil_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
108static void
109dump_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
120static void
121dump_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
128static const char *
129dump_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
144static void
145dump_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
174static void
175dump_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
190static 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
239static void
240dump_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
262static void
263dump_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
285static void
286dump_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
307static void
308dump_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
338static void
339dump_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
381static void
382dump_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
421static void
422dump_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
431static void
432dump_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
441static void
442dump_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
448static void
449dump_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
460static void
461dump_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
477static void
478dump_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
485static void
486dump_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
494static void
495dump_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
505static void
506dump_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
519static void
520dump_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
533static void
534dump_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
548static void
549dump_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
560static void
561dump_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
572static 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
582static const char *rmwsync_str[] = {
583   [DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread",
584   [DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread",
585};
586
587static 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
601static void
602dump_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
615static void
616dump_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
626static void
627dump_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
637static void
638dump_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
651static void
652dump_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
682static void
683dump_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
707static void
708mask_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
717static 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
725static 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
742static 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
748static 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
757static 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