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