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
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
113static void
114dump_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
125static void
126dump_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
133static const char *
134dump_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
149static void
150dump_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
179static void
180dump_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
195static 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
244static void
245dump_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
267static void
268dump_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
290static void
291dump_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
312static void
313dump_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
343static void
344dump_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
386static void
387dump_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
426static void
427dump_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
436static void
437dump_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
446static void
447dump_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
453static void
454dump_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
465static void
466dump_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
482static void
483dump_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
490static void
491dump_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
499static void
500dump_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
510static void
511dump_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
524static void
525dump_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
538static void
539dump_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
553static void
554dump_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
565static void
566dump_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
577static 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
587static const char *rmwsync_str[] = {
588   [DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread",
589   [DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread",
590};
591
592static 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
606static void
607dump_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
620static void
621dump_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
631static void
632dump_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
642static void
643dump_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
656static void
657dump_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
687static void
688dump_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
712static void
713mask_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
722static 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
730static 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
747static 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
753static 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
762static 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