disassemble.c revision 7ec681f3
1/* Author(s): 2 * Connor Abbott 3 * Alyssa Rosenzweig 4 * 5 * Copyright (c) 2013 Connor Abbott (connor@abbott.cx) 6 * Copyright (c) 2018 Alyssa Rosenzweig (alyssa@rosenzweig.io) 7 * Copyright (C) 2019-2020 Collabora, Ltd. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to deal 11 * in the Software without restriction, including without limitation the rights 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 * THE SOFTWARE. 26 */ 27 28#include <stdio.h> 29#include <stdint.h> 30#include <stdlib.h> 31#include <assert.h> 32#include <inttypes.h> 33#include <ctype.h> 34#include <string.h> 35#include "midgard.h" 36#include "midgard_ops.h" 37#include "midgard_quirks.h" 38#include "disassemble.h" 39#include "helpers.h" 40#include "util/bitscan.h" 41#include "util/half_float.h" 42#include "util/u_math.h" 43 44#define DEFINE_CASE(define, str) case define: { fprintf(fp, str); break; } 45 46/* These are not mapped to hardware values, they just represent the possible 47 * implicit arg modifiers that some midgard opcodes have, which can be decoded 48 * from the opcodes via midgard_{alu,ldst,tex}_special_arg_mod() */ 49typedef enum { 50 midgard_arg_mod_none = 0, 51 midgard_arg_mod_inv, 52 midgard_arg_mod_x2, 53} midgard_special_arg_mod; 54 55typedef struct { 56 unsigned *midg_tags; 57 struct midgard_disasm_stats midg_stats; 58 59 /* For static analysis to ensure all registers are written at least once before 60 * use along the source code path (TODO: does this break done for complex CF?) 61 */ 62 63 uint16_t midg_ever_written; 64} disassemble_context; 65 66/* Transform an expanded writemask (duplicated 8-bit format) into its condensed 67 * form (one bit per component) */ 68 69static inline unsigned 70condense_writemask(unsigned expanded_mask, 71 unsigned bits_per_component) 72{ 73 if (bits_per_component == 8) { 74 /* Duplicate every bit to go from 8 to 16-channel wrmask */ 75 unsigned omask = 0; 76 77 for (unsigned i = 0; i < 8; ++i) { 78 if (expanded_mask & (1 << i)) 79 omask |= (3 << (2 * i)); 80 } 81 82 return omask; 83 } 84 85 unsigned slots_per_component = bits_per_component / 16; 86 unsigned max_comp = (16 * 8) / bits_per_component; 87 unsigned condensed_mask = 0; 88 89 for (unsigned i = 0; i < max_comp; i++) { 90 if (expanded_mask & (1 << (i * slots_per_component))) 91 condensed_mask |= (1 << i); 92 } 93 94 return condensed_mask; 95} 96 97static bool 98print_alu_opcode(FILE *fp, midgard_alu_op op) 99{ 100 if (alu_opcode_props[op].name) 101 fprintf(fp, "%s", alu_opcode_props[op].name); 102 else 103 fprintf(fp, "alu_op_%02X", op); 104 105 /* For constant analysis */ 106 return midgard_is_integer_op(op); 107} 108 109static void 110print_ld_st_opcode(FILE *fp, midgard_load_store_op op) 111{ 112 if (load_store_opcode_props[op].name) 113 fprintf(fp, "%s", load_store_opcode_props[op].name); 114 else 115 fprintf(fp, "ldst_op_%02X", op); 116} 117 118static void 119validate_sampler_type(enum mali_texture_op op, enum mali_sampler_type sampler_type) 120{ 121 if (op == midgard_tex_op_mov || op == midgard_tex_op_barrier) 122 assert(sampler_type == 0); 123 else 124 assert(sampler_type > 0); 125} 126 127static void 128validate_expand_mode(midgard_src_expand_mode expand_mode, 129 midgard_reg_mode reg_mode) 130{ 131 switch (expand_mode) { 132 case midgard_src_passthrough: 133 break; 134 135 case midgard_src_rep_low: 136 assert(reg_mode == midgard_reg_mode_8 || 137 reg_mode == midgard_reg_mode_16); 138 break; 139 140 case midgard_src_rep_high: 141 assert(reg_mode == midgard_reg_mode_8 || 142 reg_mode == midgard_reg_mode_16); 143 break; 144 145 case midgard_src_swap: 146 assert(reg_mode == midgard_reg_mode_8 || 147 reg_mode == midgard_reg_mode_16); 148 break; 149 150 case midgard_src_expand_low: 151 assert(reg_mode != midgard_reg_mode_8); 152 break; 153 154 case midgard_src_expand_high: 155 assert(reg_mode != midgard_reg_mode_8); 156 break; 157 158 case midgard_src_expand_low_swap: 159 assert(reg_mode == midgard_reg_mode_16); 160 break; 161 162 case midgard_src_expand_high_swap: 163 assert(reg_mode == midgard_reg_mode_16); 164 break; 165 166 default: 167 unreachable("Invalid expand mode"); 168 break; 169 } 170} 171 172static void 173print_alu_reg(disassemble_context *ctx, FILE *fp, unsigned reg, bool is_write) 174{ 175 unsigned uniform_reg = 23 - reg; 176 bool is_uniform = false; 177 178 /* For r8-r15, it could be a work or uniform. We distinguish based on 179 * the fact work registers are ALWAYS written before use, but uniform 180 * registers are NEVER written before use. */ 181 182 if ((reg >= 8 && reg < 16) && !(ctx->midg_ever_written & (1 << reg))) 183 is_uniform = true; 184 185 /* r16-r23 are always uniform */ 186 187 if (reg >= 16 && reg <= 23) 188 is_uniform = true; 189 190 /* Update the uniform count appropriately */ 191 192 if (is_uniform) 193 ctx->midg_stats.uniform_count = 194 MAX2(uniform_reg + 1, ctx->midg_stats.uniform_count); 195 196 if (reg == REGISTER_UNUSED || reg == REGISTER_UNUSED + 1) 197 fprintf(fp, "TMP%u", reg - REGISTER_UNUSED); 198 else if (reg == REGISTER_TEXTURE_BASE || reg == REGISTER_TEXTURE_BASE + 1) 199 fprintf(fp, "%s%u", is_write ? "AT" : "TA", reg - REGISTER_TEXTURE_BASE); 200 else if (reg == REGISTER_LDST_BASE || reg == REGISTER_LDST_BASE + 1) 201 fprintf(fp, "AL%u", reg - REGISTER_LDST_BASE); 202 else if (is_uniform) 203 fprintf(fp, "U%u", uniform_reg); 204 else if (reg == 31 && !is_write) 205 fprintf(fp, "PC_SP"); 206 else 207 fprintf(fp, "R%u", reg); 208} 209 210static void 211print_ldst_write_reg(FILE *fp, unsigned reg) 212{ 213 switch (reg) { 214 case 26: 215 case 27: 216 fprintf(fp, "AL%u", reg - REGISTER_LDST_BASE); 217 break; 218 case 28: 219 case 29: 220 fprintf(fp, "AT%u", reg - REGISTER_TEXTURE_BASE); 221 break; 222 case 31: 223 fprintf(fp, "PC_SP"); 224 break; 225 default: 226 fprintf(fp, "R%d", reg); 227 break; 228 } 229} 230 231static void 232print_ldst_read_reg(FILE *fp, unsigned reg) 233{ 234 switch (reg) { 235 case 0: 236 case 1: 237 fprintf(fp, "AL%u", reg); 238 break; 239 case 2: 240 fprintf(fp, "PC_SP"); 241 break; 242 case 3: 243 fprintf(fp, "LOCAL_STORAGE_PTR"); 244 break; 245 case 4: 246 fprintf(fp, "LOCAL_THREAD_ID"); 247 break; 248 case 5: 249 fprintf(fp, "GROUP_ID"); 250 break; 251 case 6: 252 fprintf(fp, "GLOBAL_THREAD_ID"); 253 break; 254 case 7: 255 fprintf(fp, "0"); 256 break; 257 default: 258 unreachable("Invalid load/store register read"); 259 } 260} 261 262static void 263print_tex_reg(FILE *fp, unsigned reg, bool is_write) 264{ 265 char *str = is_write ? "TA" : "AT"; 266 int select = reg & 1; 267 268 switch (reg) { 269 case 0: 270 case 1: 271 fprintf(fp, "R%d", select); 272 break; 273 case 26: 274 case 27: 275 fprintf(fp, "AL%d", select); 276 break; 277 case 28: 278 case 29: 279 fprintf(fp, "%s%d", str, select); 280 break; 281 default: 282 unreachable("Invalid texture register"); 283 } 284} 285 286 287static char *outmod_names_float[4] = { 288 "", 289 ".clamp_0_inf", 290 ".clamp_m1_1", 291 ".clamp_0_1" 292}; 293 294static char *outmod_names_int[4] = { 295 ".ssat", 296 ".usat", 297 ".keeplo", 298 ".keephi" 299}; 300 301static char *srcmod_names_int[4] = { 302 ".sext", 303 ".zext", 304 ".replicate", 305 ".lshift", 306}; 307 308static char *argmod_names[3] = { 309 "", 310 ".inv", 311 ".x2", 312}; 313 314static char *index_format_names[4] = { 315 "", 316 ".u64", 317 ".u32", 318 ".s32" 319}; 320 321static void 322print_outmod(FILE *fp, unsigned outmod, bool is_int) 323{ 324 fprintf(fp, "%s", is_int ? outmod_names_int[outmod] : 325 outmod_names_float[outmod]); 326} 327 328static void 329print_alu_outmod(FILE *fp, unsigned outmod, bool is_int, bool half) 330{ 331 if (is_int && !half) { 332 assert(outmod == midgard_outmod_keeplo); 333 return; 334 } 335 336 if (!is_int && half) 337 fprintf(fp, ".shrink"); 338 339 print_outmod(fp, outmod, is_int); 340} 341 342/* arg == 0 (dest), arg == 1 (src1), arg == 2 (src2) */ 343static midgard_special_arg_mod 344midgard_alu_special_arg_mod(midgard_alu_op op, unsigned arg) { 345 midgard_special_arg_mod mod = midgard_arg_mod_none; 346 347 switch (op) { 348 case midgard_alu_op_ishladd: 349 case midgard_alu_op_ishlsub: 350 if (arg == 1) mod = midgard_arg_mod_x2; 351 break; 352 353 default: 354 break; 355 } 356 357 return mod; 358} 359 360static void 361print_quad_word(FILE *fp, uint32_t *words, unsigned tabs) 362{ 363 unsigned i; 364 365 for (i = 0; i < 4; i++) 366 fprintf(fp, "0x%08X%s ", words[i], i == 3 ? "" : ","); 367 368 fprintf(fp, "\n"); 369} 370 371static const char components[16] = "xyzwefghijklmnop"; 372 373static int 374bits_for_mode(midgard_reg_mode mode) 375{ 376 switch (mode) { 377 case midgard_reg_mode_8: 378 return 8; 379 case midgard_reg_mode_16: 380 return 16; 381 case midgard_reg_mode_32: 382 return 32; 383 case midgard_reg_mode_64: 384 return 64; 385 default: 386 unreachable("Invalid reg mode"); 387 return 0; 388 } 389} 390 391static int 392bits_for_mode_halved(midgard_reg_mode mode, bool half) 393{ 394 unsigned bits = bits_for_mode(mode); 395 396 if (half) 397 bits >>= 1; 398 399 return bits; 400} 401 402static void 403print_vec_selectors_64(FILE *fp, unsigned swizzle, 404 midgard_reg_mode reg_mode, 405 midgard_src_expand_mode expand_mode, 406 unsigned selector_offset, uint8_t mask) 407{ 408 bool expands = INPUT_EXPANDS(expand_mode); 409 410 unsigned comp_skip = expands ? 1 : 2; 411 unsigned mask_bit = 0; 412 for (unsigned i = selector_offset; i < 4; i += comp_skip, mask_bit += 4) { 413 if (!(mask & (1 << mask_bit))) continue; 414 415 unsigned a = (swizzle >> (i * 2)) & 3; 416 417 if (INPUT_EXPANDS(expand_mode)) { 418 fprintf(fp, "%c", components[a]); 419 continue; 420 } 421 422 unsigned b = (swizzle >> ((i+1) * 2)) & 3; 423 424 /* Normally we're adjacent, but if there's an issue, 425 * don't make it ambiguous */ 426 427 if (b == a + 1) 428 fprintf(fp, "%c", a >> 1 ? 'Y' : 'X'); 429 else 430 fprintf(fp, "[%c%c]", components[a], components[b]); 431 } 432} 433 434static void 435print_vec_selectors(FILE *fp, unsigned swizzle, 436 midgard_reg_mode reg_mode, 437 unsigned selector_offset, uint8_t mask, 438 unsigned *mask_offset) 439{ 440 assert(reg_mode != midgard_reg_mode_64); 441 442 unsigned mask_skip = MAX2(bits_for_mode(reg_mode) / 16, 1); 443 444 bool is_vec16 = reg_mode == midgard_reg_mode_8; 445 446 for (unsigned i = 0; i < 4; i++, *mask_offset += mask_skip) { 447 if (!(mask & (1 << *mask_offset))) continue; 448 449 unsigned c = (swizzle >> (i * 2)) & 3; 450 451 /* Vec16 has two components per swizzle selector. */ 452 if (is_vec16) 453 c *= 2; 454 455 c += selector_offset; 456 457 fprintf(fp, "%c", components[c]); 458 if (is_vec16) 459 fprintf(fp, "%c", components[c+1]); 460 } 461} 462 463static void 464print_vec_swizzle(FILE *fp, unsigned swizzle, 465 midgard_src_expand_mode expand, 466 midgard_reg_mode mode, 467 uint8_t mask) 468{ 469 unsigned bits = bits_for_mode_halved(mode, INPUT_EXPANDS(expand)); 470 471 /* Swizzle selectors are divided in two halves that are always 472 * mirrored, the only difference is the starting component offset. 473 * The number represents an offset into the components[] array. */ 474 unsigned first_half = 0; 475 unsigned second_half = (128 / bits) / 2; /* only used for 8 and 16-bit */ 476 477 switch (expand) { 478 case midgard_src_passthrough: 479 if (swizzle == 0xE4) return; /* identity swizzle */ 480 break; 481 482 case midgard_src_expand_low: 483 second_half /= 2; 484 break; 485 486 case midgard_src_expand_high: 487 first_half = second_half; 488 second_half += second_half / 2; 489 break; 490 491 /* The rest of the cases are only used for 8 and 16-bit */ 492 493 case midgard_src_rep_low: 494 second_half = 0; 495 break; 496 497 case midgard_src_rep_high: 498 first_half = second_half; 499 break; 500 501 case midgard_src_swap: 502 first_half = second_half; 503 second_half = 0; 504 break; 505 506 case midgard_src_expand_low_swap: 507 first_half = second_half / 2; 508 second_half = 0; 509 break; 510 511 case midgard_src_expand_high_swap: 512 first_half = second_half + second_half / 2; 513 break; 514 515 default: 516 unreachable("Invalid expand mode"); 517 break; 518 } 519 520 fprintf(fp, "."); 521 522 /* Vec2 are weird so we use a separate function to simplify things. */ 523 if (mode == midgard_reg_mode_64) { 524 print_vec_selectors_64(fp, swizzle, mode, expand, first_half, mask); 525 return; 526 } 527 528 unsigned mask_offs = 0; 529 print_vec_selectors(fp, swizzle, mode, first_half, mask, &mask_offs); 530 if (mode == midgard_reg_mode_8 || mode == midgard_reg_mode_16) 531 print_vec_selectors(fp, swizzle, mode, second_half, mask, &mask_offs); 532} 533 534static void 535print_scalar_constant(FILE *fp, unsigned src_binary, 536 const midgard_constants *consts, 537 midgard_scalar_alu *alu) 538{ 539 midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary; 540 assert(consts != NULL); 541 542 fprintf(fp, "#"); 543 mir_print_constant_component(fp, consts, src->component, 544 src->full ? 545 midgard_reg_mode_32 : midgard_reg_mode_16, 546 false, src->mod, alu->op); 547} 548 549static void 550print_vector_constants(FILE *fp, unsigned src_binary, 551 const midgard_constants *consts, 552 midgard_vector_alu *alu) 553{ 554 midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary; 555 bool expands = INPUT_EXPANDS(src->expand_mode); 556 unsigned bits = bits_for_mode_halved(alu->reg_mode, expands); 557 unsigned max_comp = (sizeof(*consts) * 8) / bits; 558 unsigned comp_mask, num_comp = 0; 559 560 assert(consts); 561 assert(max_comp <= 16); 562 563 comp_mask = effective_writemask(alu->op, condense_writemask(alu->mask, bits)); 564 num_comp = util_bitcount(comp_mask); 565 566 fprintf(fp, "<"); 567 bool first = true; 568 569 for (unsigned i = 0; i < max_comp; ++i) { 570 if (!(comp_mask & (1 << i))) continue; 571 572 unsigned c = (src->swizzle >> (i * 2)) & 3; 573 574 if (bits == 16 && !expands) { 575 bool upper = i >= 4; 576 577 switch (src->expand_mode) { 578 case midgard_src_passthrough: 579 c += upper * 4; 580 break; 581 case midgard_src_rep_low: 582 break; 583 case midgard_src_rep_high: 584 c += 4; 585 break; 586 case midgard_src_swap: 587 c += !upper * 4; 588 break; 589 default: 590 unreachable("invalid expand mode"); 591 break; 592 } 593 } else if (bits == 32 && !expands) { 594 /* Implicitly ok */ 595 } else if (bits == 64 && !expands) { 596 /* Implicitly ok */ 597 } else if (bits == 8 && !expands) { 598 bool upper = i >= 8; 599 600 unsigned index = (i >> 1) & 3; 601 unsigned base = (src->swizzle >> (index * 2)) & 3; 602 c = base * 2; 603 604 switch (src->expand_mode) { 605 case midgard_src_passthrough: 606 c += upper * 8; 607 break; 608 case midgard_src_rep_low: 609 break; 610 case midgard_src_rep_high: 611 c += 8; 612 break; 613 case midgard_src_swap: 614 c += !upper * 8; 615 break; 616 default: 617 unreachable("invalid expand mode"); 618 break; 619 } 620 621 /* We work on twos, actually */ 622 if (i & 1) 623 c++; 624 } else { 625 printf(" (%u)", src->expand_mode); 626 } 627 628 if (first) 629 first = false; 630 else 631 fprintf(fp, ", "); 632 633 mir_print_constant_component(fp, consts, c, alu->reg_mode, 634 expands, src->mod, alu->op); 635 } 636 637 if (num_comp > 1) 638 fprintf(fp, ">"); 639} 640 641static void 642print_srcmod(FILE *fp, bool is_int, bool expands, unsigned mod, bool scalar) 643{ 644 /* Modifiers change meaning depending on the op's context */ 645 646 if (is_int) { 647 if (expands) 648 fprintf(fp, "%s", srcmod_names_int[mod]); 649 } else { 650 if (mod & MIDGARD_FLOAT_MOD_ABS) 651 fprintf(fp, ".abs"); 652 if (mod & MIDGARD_FLOAT_MOD_NEG) 653 fprintf(fp, ".neg"); 654 if (expands) 655 fprintf(fp, ".widen"); 656 } 657} 658 659static void 660print_vector_src(disassemble_context *ctx, FILE *fp, unsigned src_binary, 661 midgard_reg_mode mode, unsigned reg, 662 midgard_shrink_mode shrink_mode, 663 uint8_t src_mask, bool is_int, 664 midgard_special_arg_mod arg_mod) 665{ 666 midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary; 667 668 validate_expand_mode(src->expand_mode, mode); 669 670 print_alu_reg(ctx, fp, reg, false); 671 672 print_vec_swizzle(fp, src->swizzle, src->expand_mode, mode, src_mask); 673 674 fprintf(fp, "%s", argmod_names[arg_mod]); 675 676 print_srcmod(fp, is_int, INPUT_EXPANDS(src->expand_mode), src->mod, false); 677} 678 679static uint16_t 680decode_vector_imm(unsigned src2_reg, unsigned imm) 681{ 682 uint16_t ret; 683 ret = src2_reg << 11; 684 ret |= (imm & 0x7) << 8; 685 ret |= (imm >> 3) & 0xFF; 686 return ret; 687} 688 689static void 690print_immediate(FILE *fp, uint16_t imm, bool is_instruction_int) 691{ 692 if (is_instruction_int) 693 fprintf(fp, "#%u", imm); 694 else 695 fprintf(fp, "#%g", _mesa_half_to_float(imm)); 696} 697 698static void 699update_dest(disassemble_context *ctx, unsigned reg) 700{ 701 /* We should record writes as marking this as a work register. Store 702 * the max register in work_count; we'll add one at the end */ 703 704 if (reg < 16) { 705 ctx->midg_stats.work_count = MAX2(reg, ctx->midg_stats.work_count); 706 ctx->midg_ever_written |= (1 << reg); 707 } 708} 709 710static void 711print_dest(disassemble_context *ctx, FILE *fp, unsigned reg) 712{ 713 update_dest(ctx, reg); 714 print_alu_reg(ctx, fp, reg, true); 715} 716 717/* For 16-bit+ masks, we read off from the 8-bit mask field. For 16-bit (vec8), 718 * it's just one bit per channel, easy peasy. For 32-bit (vec4), it's one bit 719 * per channel with one duplicate bit in the middle. For 64-bit (vec2), it's 720 * one-bit per channel with _3_ duplicate bits in the middle. Basically, just 721 * subdividing the 128-bit word in 16-bit increments. For 64-bit, we uppercase 722 * the mask to make it obvious what happened */ 723 724static void 725print_alu_mask(FILE *fp, uint8_t mask, unsigned bits, midgard_shrink_mode shrink_mode) 726{ 727 /* Skip 'complete' masks */ 728 729 if (shrink_mode == midgard_shrink_mode_none && mask == 0xFF) 730 return; 731 732 fprintf(fp, "."); 733 734 unsigned skip = MAX2(bits / 16, 1); 735 bool uppercase = bits > 32; 736 bool tripped = false; 737 738 /* To apply an upper destination shrink_mode, we "shift" the alphabet. 739 * E.g. with an upper shrink_mode on 32-bit, instead of xyzw, print efgh. 740 * For upper 16-bit, instead of xyzwefgh, print ijklmnop */ 741 742 const char *alphabet = components; 743 744 if (shrink_mode == midgard_shrink_mode_upper) { 745 assert(bits != 8); 746 alphabet += (128 / bits); 747 } 748 749 for (unsigned i = 0; i < 8; i += skip) { 750 bool a = (mask & (1 << i)) != 0; 751 752 for (unsigned j = 1; j < skip; ++j) { 753 bool dupe = (mask & (1 << (i + j))) != 0; 754 tripped |= (dupe != a); 755 } 756 757 if (a) { 758 /* TODO: handle shrinking from 16-bit */ 759 unsigned comp_idx = bits == 8 ? i * 2 : i; 760 char c = alphabet[comp_idx / skip]; 761 762 if (uppercase) { 763 c = toupper(c); 764 assert(c == 'X' || c == 'Y'); 765 } 766 767 fprintf(fp, "%c", c); 768 if (bits == 8) 769 fprintf(fp, "%c", alphabet[comp_idx+1]); 770 } 771 } 772 773 if (tripped) 774 fprintf(fp, " /* %X */", mask); 775} 776 777/* TODO: 16-bit mode */ 778static void 779print_ldst_mask(FILE *fp, unsigned mask, unsigned swizzle) { 780 fprintf(fp, "."); 781 782 for (unsigned i = 0; i < 4; ++i) { 783 bool write = (mask & (1 << i)) != 0; 784 unsigned c = (swizzle >> (i * 2)) & 3; 785 /* We can't omit the swizzle here since many ldst ops have a 786 * combined swizzle/writemask, and it would be ambiguous to not 787 * print the masked-out components. */ 788 fprintf(fp, "%c", write ? components[c] : '~'); 789 } 790} 791 792static void 793print_tex_mask(FILE *fp, unsigned mask, bool upper) 794{ 795 if (mask == 0xF) { 796 if (upper) 797 fprintf(fp, "'"); 798 799 return; 800 } 801 802 fprintf(fp, "."); 803 804 for (unsigned i = 0; i < 4; ++i) { 805 bool a = (mask & (1 << i)) != 0; 806 if (a) 807 fprintf(fp, "%c", components[i + (upper ? 4 : 0)]); 808 } 809} 810 811static void 812print_vector_field(disassemble_context *ctx, FILE *fp, const char *name, 813 uint16_t *words, uint16_t reg_word, 814 const midgard_constants *consts, unsigned tabs, bool verbose) 815{ 816 midgard_reg_info *reg_info = (midgard_reg_info *)®_word; 817 midgard_vector_alu *alu_field = (midgard_vector_alu *) words; 818 midgard_reg_mode mode = alu_field->reg_mode; 819 midgard_alu_op op = alu_field->op; 820 unsigned shrink_mode = alu_field->shrink_mode; 821 bool is_int = midgard_is_integer_op(op); 822 bool is_int_out = midgard_is_integer_out_op(op); 823 824 if (verbose) 825 fprintf(fp, "%s.", name); 826 827 bool is_instruction_int = print_alu_opcode(fp, alu_field->op); 828 829 /* Print lane width */ 830 fprintf(fp, ".%c%d", is_int_out ? 'i' : 'f', bits_for_mode(mode)); 831 832 fprintf(fp, " "); 833 834 /* Mask denoting status of 8-lanes */ 835 uint8_t mask = alu_field->mask; 836 837 /* First, print the destination */ 838 print_dest(ctx, fp, reg_info->out_reg); 839 840 if (shrink_mode != midgard_shrink_mode_none) { 841 bool shrinkable = (mode != midgard_reg_mode_8); 842 bool known = shrink_mode != 0x3; /* Unused value */ 843 844 if (!(shrinkable && known)) 845 fprintf(fp, "/* do%u */ ", shrink_mode); 846 } 847 848 /* Instructions like fdot4 do *not* replicate, ensure the 849 * mask is of only a single component */ 850 851 unsigned rep = GET_CHANNEL_COUNT(alu_opcode_props[op].props); 852 853 if (rep) { 854 unsigned comp_mask = condense_writemask(mask, bits_for_mode(mode)); 855 unsigned num_comp = util_bitcount(comp_mask); 856 if (num_comp != 1) 857 fprintf(fp, "/* err too many components */"); 858 } 859 print_alu_mask(fp, mask, bits_for_mode(mode), shrink_mode); 860 861 /* Print output modifiers */ 862 863 print_alu_outmod(fp, alu_field->outmod, is_int_out, shrink_mode != midgard_shrink_mode_none); 864 865 /* Mask out unused components based on the writemask, but don't mask out 866 * components that are used for interlane instructions like fdot3. */ 867 uint8_t src_mask = 868 rep ? expand_writemask(mask_of(rep), log2(128 / bits_for_mode(mode))) : mask; 869 870 fprintf(fp, ", "); 871 872 if (reg_info->src1_reg == REGISTER_CONSTANT) 873 print_vector_constants(fp, alu_field->src1, consts, alu_field); 874 else { 875 midgard_special_arg_mod argmod = midgard_alu_special_arg_mod(op, 1); 876 print_vector_src(ctx, fp, alu_field->src1, mode, reg_info->src1_reg, 877 shrink_mode, src_mask, is_int, argmod); 878 } 879 880 fprintf(fp, ", "); 881 882 if (reg_info->src2_imm) { 883 uint16_t imm = decode_vector_imm(reg_info->src2_reg, alu_field->src2 >> 2); 884 print_immediate(fp, imm, is_instruction_int); 885 } else if (reg_info->src2_reg == REGISTER_CONSTANT) { 886 print_vector_constants(fp, alu_field->src2, consts, alu_field); 887 } else { 888 midgard_special_arg_mod argmod = midgard_alu_special_arg_mod(op, 2); 889 print_vector_src(ctx, fp, alu_field->src2, mode, reg_info->src2_reg, 890 shrink_mode, src_mask, is_int, argmod); 891 } 892 893 ctx->midg_stats.instruction_count++; 894 fprintf(fp, "\n"); 895} 896 897static void 898print_scalar_src(disassemble_context *ctx, FILE *fp, bool is_int, unsigned src_binary, unsigned reg) 899{ 900 midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary; 901 902 print_alu_reg(ctx, fp, reg, false); 903 904 unsigned c = src->component; 905 906 if (src->full) { 907 assert((c & 1) == 0); 908 c >>= 1; 909 } 910 911 fprintf(fp, ".%c", components[c]); 912 913 print_srcmod(fp, is_int, !src->full, src->mod, true); 914} 915 916static uint16_t 917decode_scalar_imm(unsigned src2_reg, unsigned imm) 918{ 919 uint16_t ret; 920 ret = src2_reg << 11; 921 ret |= (imm & 3) << 9; 922 ret |= (imm & 4) << 6; 923 ret |= (imm & 0x38) << 2; 924 ret |= imm >> 6; 925 return ret; 926} 927 928static void 929print_scalar_field(disassemble_context *ctx, FILE *fp, const char *name, 930 uint16_t *words, uint16_t reg_word, 931 const midgard_constants *consts, unsigned tabs, bool verbose) 932{ 933 midgard_reg_info *reg_info = (midgard_reg_info *)®_word; 934 midgard_scalar_alu *alu_field = (midgard_scalar_alu *) words; 935 bool is_int = midgard_is_integer_op(alu_field->op); 936 bool is_int_out = midgard_is_integer_out_op(alu_field->op); 937 bool full = alu_field->output_full; 938 939 if (alu_field->unknown) 940 fprintf(fp, "scalar ALU unknown bit set\n"); 941 942 if (verbose) 943 fprintf(fp, "%s.", name); 944 945 bool is_instruction_int = print_alu_opcode(fp, alu_field->op); 946 947 /* Print lane width, in this case the lane width is always 32-bit, but 948 * we print it anyway to make it consistent with the other instructions. */ 949 fprintf(fp, ".%c32", is_int_out ? 'i' : 'f'); 950 951 fprintf(fp, " "); 952 953 print_dest(ctx, fp, reg_info->out_reg); 954 unsigned c = alu_field->output_component; 955 956 if (full) { 957 assert((c & 1) == 0); 958 c >>= 1; 959 } 960 961 fprintf(fp, ".%c", components[c]); 962 963 print_alu_outmod(fp, alu_field->outmod, is_int_out, !full); 964 965 fprintf(fp, ", "); 966 967 if (reg_info->src1_reg == REGISTER_CONSTANT) 968 print_scalar_constant(fp, alu_field->src1, consts, alu_field); 969 else 970 print_scalar_src(ctx, fp, is_int, alu_field->src1, reg_info->src1_reg); 971 972 fprintf(fp, ", "); 973 974 if (reg_info->src2_imm) { 975 uint16_t imm = decode_scalar_imm(reg_info->src2_reg, 976 alu_field->src2); 977 print_immediate(fp, imm, is_instruction_int); 978 } else if (reg_info->src2_reg == REGISTER_CONSTANT) { 979 print_scalar_constant(fp, alu_field->src2, consts, alu_field); 980 } else 981 print_scalar_src(ctx, fp, is_int, alu_field->src2, reg_info->src2_reg); 982 983 ctx->midg_stats.instruction_count++; 984 fprintf(fp, "\n"); 985} 986 987static void 988print_branch_op(FILE *fp, unsigned op) 989{ 990 switch (op) { 991 case midgard_jmp_writeout_op_branch_uncond: 992 fprintf(fp, "uncond."); 993 break; 994 995 case midgard_jmp_writeout_op_branch_cond: 996 fprintf(fp, "cond."); 997 break; 998 999 case midgard_jmp_writeout_op_writeout: 1000 fprintf(fp, "write."); 1001 break; 1002 1003 case midgard_jmp_writeout_op_tilebuffer_pending: 1004 fprintf(fp, "tilebuffer."); 1005 break; 1006 1007 case midgard_jmp_writeout_op_discard: 1008 fprintf(fp, "discard."); 1009 break; 1010 1011 default: 1012 fprintf(fp, "unk%u.", op); 1013 break; 1014 } 1015} 1016 1017static void 1018print_branch_cond(FILE *fp, int cond) 1019{ 1020 switch (cond) { 1021 case midgard_condition_write0: 1022 fprintf(fp, "write0"); 1023 break; 1024 1025 case midgard_condition_false: 1026 fprintf(fp, "false"); 1027 break; 1028 1029 case midgard_condition_true: 1030 fprintf(fp, "true"); 1031 break; 1032 1033 case midgard_condition_always: 1034 fprintf(fp, "always"); 1035 break; 1036 1037 default: 1038 fprintf(fp, "unk%X", cond); 1039 break; 1040 } 1041} 1042 1043static bool 1044print_compact_branch_writeout_field(disassemble_context *ctx, FILE *fp, uint16_t word) 1045{ 1046 midgard_jmp_writeout_op op = word & 0x7; 1047 ctx->midg_stats.instruction_count++; 1048 1049 switch (op) { 1050 case midgard_jmp_writeout_op_branch_uncond: { 1051 midgard_branch_uncond br_uncond; 1052 memcpy((char *) &br_uncond, (char *) &word, sizeof(br_uncond)); 1053 fprintf(fp, "br.uncond "); 1054 1055 if (br_uncond.unknown != 1) 1056 fprintf(fp, "unknown:%u, ", br_uncond.unknown); 1057 1058 if (br_uncond.offset >= 0) 1059 fprintf(fp, "+"); 1060 1061 fprintf(fp, "%d -> %s", br_uncond.offset, 1062 midgard_tag_props[br_uncond.dest_tag].name); 1063 fprintf(fp, "\n"); 1064 1065 return br_uncond.offset >= 0; 1066 } 1067 1068 case midgard_jmp_writeout_op_branch_cond: 1069 case midgard_jmp_writeout_op_writeout: 1070 case midgard_jmp_writeout_op_discard: 1071 default: { 1072 midgard_branch_cond br_cond; 1073 memcpy((char *) &br_cond, (char *) &word, sizeof(br_cond)); 1074 1075 fprintf(fp, "br."); 1076 1077 print_branch_op(fp, br_cond.op); 1078 print_branch_cond(fp, br_cond.cond); 1079 1080 fprintf(fp, " "); 1081 1082 if (br_cond.offset >= 0) 1083 fprintf(fp, "+"); 1084 1085 fprintf(fp, "%d -> %s", br_cond.offset, 1086 midgard_tag_props[br_cond.dest_tag].name); 1087 fprintf(fp, "\n"); 1088 1089 return br_cond.offset >= 0; 1090 } 1091 } 1092 1093 return false; 1094} 1095 1096static bool 1097print_extended_branch_writeout_field(disassemble_context *ctx, FILE *fp, uint8_t *words, 1098 unsigned next) 1099{ 1100 midgard_branch_extended br; 1101 memcpy((char *) &br, (char *) words, sizeof(br)); 1102 1103 fprintf(fp, "brx."); 1104 1105 print_branch_op(fp, br.op); 1106 1107 /* Condition codes are a LUT in the general case, but simply repeated 8 times for single-channel conditions.. Check this. */ 1108 1109 bool single_channel = true; 1110 1111 for (unsigned i = 0; i < 16; i += 2) { 1112 single_channel &= (((br.cond >> i) & 0x3) == (br.cond & 0x3)); 1113 } 1114 1115 if (single_channel) 1116 print_branch_cond(fp, br.cond & 0x3); 1117 else 1118 fprintf(fp, "lut%X", br.cond); 1119 1120 if (br.unknown) 1121 fprintf(fp, ".unknown%u", br.unknown); 1122 1123 fprintf(fp, " "); 1124 1125 if (br.offset >= 0) 1126 fprintf(fp, "+"); 1127 1128 fprintf(fp, "%d -> %s\n", br.offset, 1129 midgard_tag_props[br.dest_tag].name); 1130 1131 unsigned I = next + br.offset * 4; 1132 1133 if (ctx->midg_tags[I] && ctx->midg_tags[I] != br.dest_tag) { 1134 fprintf(fp, "\t/* XXX TAG ERROR: jumping to %s but tagged %s \n", 1135 midgard_tag_props[br.dest_tag].name, 1136 midgard_tag_props[ctx->midg_tags[I]].name); 1137 } 1138 1139 ctx->midg_tags[I] = br.dest_tag; 1140 1141 ctx->midg_stats.instruction_count++; 1142 return br.offset >= 0; 1143} 1144 1145static unsigned 1146num_alu_fields_enabled(uint32_t control_word) 1147{ 1148 unsigned ret = 0; 1149 1150 if ((control_word >> 17) & 1) 1151 ret++; 1152 1153 if ((control_word >> 19) & 1) 1154 ret++; 1155 1156 if ((control_word >> 21) & 1) 1157 ret++; 1158 1159 if ((control_word >> 23) & 1) 1160 ret++; 1161 1162 if ((control_word >> 25) & 1) 1163 ret++; 1164 1165 return ret; 1166} 1167 1168static bool 1169print_alu_word(disassemble_context *ctx, FILE *fp, uint32_t *words, 1170 unsigned num_quad_words, unsigned tabs, unsigned next, 1171 bool verbose) 1172{ 1173 uint32_t control_word = words[0]; 1174 uint16_t *beginning_ptr = (uint16_t *)(words + 1); 1175 unsigned num_fields = num_alu_fields_enabled(control_word); 1176 uint16_t *word_ptr = beginning_ptr + num_fields; 1177 unsigned num_words = 2 + num_fields; 1178 const midgard_constants *consts = NULL; 1179 bool branch_forward = false; 1180 1181 if ((control_word >> 17) & 1) 1182 num_words += 3; 1183 1184 if ((control_word >> 19) & 1) 1185 num_words += 2; 1186 1187 if ((control_word >> 21) & 1) 1188 num_words += 3; 1189 1190 if ((control_word >> 23) & 1) 1191 num_words += 2; 1192 1193 if ((control_word >> 25) & 1) 1194 num_words += 3; 1195 1196 if ((control_word >> 26) & 1) 1197 num_words += 1; 1198 1199 if ((control_word >> 27) & 1) 1200 num_words += 3; 1201 1202 if (num_quad_words > (num_words + 7) / 8) { 1203 assert(num_quad_words == (num_words + 15) / 8); 1204 //Assume that the extra quadword is constants 1205 consts = (midgard_constants *)(words + (4 * num_quad_words - 4)); 1206 } 1207 1208 if ((control_word >> 16) & 1) 1209 fprintf(fp, "unknown bit 16 enabled\n"); 1210 1211 if ((control_word >> 17) & 1) { 1212 print_vector_field(ctx, fp, "vmul", word_ptr, *beginning_ptr, consts, tabs, verbose); 1213 beginning_ptr += 1; 1214 word_ptr += 3; 1215 } 1216 1217 if ((control_word >> 18) & 1) 1218 fprintf(fp, "unknown bit 18 enabled\n"); 1219 1220 if ((control_word >> 19) & 1) { 1221 print_scalar_field(ctx, fp, "sadd", word_ptr, *beginning_ptr, consts, tabs, verbose); 1222 beginning_ptr += 1; 1223 word_ptr += 2; 1224 } 1225 1226 if ((control_word >> 20) & 1) 1227 fprintf(fp, "unknown bit 20 enabled\n"); 1228 1229 if ((control_word >> 21) & 1) { 1230 print_vector_field(ctx, fp, "vadd", word_ptr, *beginning_ptr, consts, tabs, verbose); 1231 beginning_ptr += 1; 1232 word_ptr += 3; 1233 } 1234 1235 if ((control_word >> 22) & 1) 1236 fprintf(fp, "unknown bit 22 enabled\n"); 1237 1238 if ((control_word >> 23) & 1) { 1239 print_scalar_field(ctx, fp, "smul", word_ptr, *beginning_ptr, consts, tabs, verbose); 1240 beginning_ptr += 1; 1241 word_ptr += 2; 1242 } 1243 1244 if ((control_word >> 24) & 1) 1245 fprintf(fp, "unknown bit 24 enabled\n"); 1246 1247 if ((control_word >> 25) & 1) { 1248 print_vector_field(ctx, fp, "lut", word_ptr, *beginning_ptr, consts, tabs, verbose); 1249 word_ptr += 3; 1250 } 1251 1252 if ((control_word >> 26) & 1) { 1253 branch_forward |= print_compact_branch_writeout_field(ctx, fp, *word_ptr); 1254 word_ptr += 1; 1255 } 1256 1257 if ((control_word >> 27) & 1) { 1258 branch_forward |= print_extended_branch_writeout_field(ctx, fp, (uint8_t *) word_ptr, next); 1259 word_ptr += 3; 1260 } 1261 1262 if (consts) 1263 fprintf(fp, "uconstants 0x%X, 0x%X, 0x%X, 0x%X\n", 1264 consts->u32[0], consts->u32[1], 1265 consts->u32[2], consts->u32[3]); 1266 1267 return branch_forward; 1268} 1269 1270/* TODO: how can we use this now that we know that these params can't be known 1271 * before run time in every single case? Maybe just use it in the cases we can? */ 1272UNUSED static void 1273print_varying_parameters(FILE *fp, midgard_load_store_word *word) 1274{ 1275 midgard_varying_params p = midgard_unpack_varying_params(*word); 1276 1277 /* If a varying, there are qualifiers */ 1278 if (p.flat_shading) 1279 fprintf(fp, ".flat"); 1280 1281 if (p.perspective_correction) 1282 fprintf(fp, ".correction"); 1283 1284 if (p.centroid_mapping) 1285 fprintf(fp, ".centroid"); 1286 1287 if (p.interpolate_sample) 1288 fprintf(fp, ".sample"); 1289 1290 switch (p.modifier) { 1291 case midgard_varying_mod_perspective_y: 1292 fprintf(fp, ".perspectivey"); 1293 break; 1294 case midgard_varying_mod_perspective_z: 1295 fprintf(fp, ".perspectivez"); 1296 break; 1297 case midgard_varying_mod_perspective_w: 1298 fprintf(fp, ".perspectivew"); 1299 break; 1300 default: 1301 unreachable("invalid varying modifier"); 1302 break; 1303 } 1304} 1305 1306static bool 1307is_op_varying(unsigned op) 1308{ 1309 switch (op) { 1310 case midgard_op_st_vary_16: 1311 case midgard_op_st_vary_32: 1312 case midgard_op_st_vary_32i: 1313 case midgard_op_st_vary_32u: 1314 case midgard_op_ld_vary_16: 1315 case midgard_op_ld_vary_32: 1316 case midgard_op_ld_vary_32i: 1317 case midgard_op_ld_vary_32u: 1318 return true; 1319 } 1320 1321 return false; 1322} 1323 1324static bool 1325is_op_attribute(unsigned op) 1326{ 1327 switch (op) { 1328 case midgard_op_ld_attr_16: 1329 case midgard_op_ld_attr_32: 1330 case midgard_op_ld_attr_32i: 1331 case midgard_op_ld_attr_32u: 1332 return true; 1333 } 1334 1335 return false; 1336} 1337 1338/* Helper to print integer well-formatted, but only when non-zero. */ 1339static void 1340midgard_print_sint(FILE *fp, int n) 1341{ 1342 if (n > 0) 1343 fprintf(fp, " + 0x%X", n); 1344 else if (n < 0) 1345 fprintf(fp, " - 0x%X", -n); 1346} 1347 1348static void 1349update_stats(signed *stat, unsigned address) 1350{ 1351 if (*stat >= 0) 1352 *stat = MAX2(*stat, address + 1); 1353} 1354 1355static void 1356print_load_store_instr(disassemble_context *ctx, FILE *fp, uint64_t data, bool verbose) 1357{ 1358 midgard_load_store_word *word = (midgard_load_store_word *) &data; 1359 1360 print_ld_st_opcode(fp, word->op); 1361 1362 if (word->op == midgard_op_trap) { 1363 fprintf(fp, " 0x%X\n", word->signed_offset); 1364 return; 1365 } 1366 1367 /* Print opcode modifiers */ 1368 1369 if (OP_USES_ATTRIB(word->op)) { 1370 /* Print non-default attribute tables */ 1371 bool default_secondary = 1372 (word->op == midgard_op_st_vary_32) || 1373 (word->op == midgard_op_st_vary_16) || 1374 (word->op == midgard_op_st_vary_32u) || 1375 (word->op == midgard_op_st_vary_32i) || 1376 (word->op == midgard_op_ld_vary_32) || 1377 (word->op == midgard_op_ld_vary_16) || 1378 (word->op == midgard_op_ld_vary_32u) || 1379 (word->op == midgard_op_ld_vary_32i); 1380 1381 bool default_primary = 1382 (word->op == midgard_op_ld_attr_32) || 1383 (word->op == midgard_op_ld_attr_16) || 1384 (word->op == midgard_op_ld_attr_32u) || 1385 (word->op == midgard_op_ld_attr_32i); 1386 1387 bool has_default = (default_secondary || default_primary); 1388 bool is_secondary = (word->index_format >> 1); 1389 1390 if (has_default && (is_secondary != default_secondary)) 1391 fprintf(fp, ".%s", is_secondary ? "secondary" : "primary"); 1392 } else if (word->op == midgard_op_ld_cubemap_coords || OP_IS_PROJECTION(word->op)) 1393 fprintf(fp, ".%s", word->bitsize_toggle ? "f32" : "f16"); 1394 1395 fprintf(fp, " "); 1396 1397 /* src/dest register */ 1398 1399 if (!OP_IS_STORE(word->op)) { 1400 print_ldst_write_reg(fp, word->reg); 1401 1402 /* Some opcodes don't have a swizzable src register, and 1403 * instead the swizzle is applied before the result is written 1404 * to the dest reg. For these ops, we combine the writemask 1405 * with the swizzle to display them in the disasm compactly. */ 1406 unsigned swizzle = word->swizzle; 1407 if ((OP_IS_REG2REG_LDST(word->op) && 1408 word->op != midgard_op_lea && 1409 word->op != midgard_op_lea_image) || OP_IS_ATOMIC(word->op)) 1410 swizzle = 0xE4; 1411 print_ldst_mask(fp, word->mask, swizzle); 1412 } else { 1413 print_ldst_read_reg(fp, word->reg); 1414 print_vec_swizzle(fp, word->swizzle, midgard_src_passthrough, 1415 midgard_reg_mode_32, 0xFF); 1416 } 1417 1418 /* ld_ubo args */ 1419 if (OP_IS_UBO_READ(word->op)) { 1420 if (word->signed_offset & 1) { /* buffer index imm */ 1421 unsigned imm = midgard_unpack_ubo_index_imm(*word); 1422 fprintf(fp, ", %u", imm); 1423 } else { /* buffer index from reg */ 1424 fprintf(fp, ", "); 1425 print_ldst_read_reg(fp, word->arg_reg); 1426 fprintf(fp, ".%c", components[word->arg_comp]); 1427 } 1428 1429 fprintf(fp, ", "); 1430 print_ldst_read_reg(fp, word->index_reg); 1431 fprintf(fp, ".%c", components[word->index_comp]); 1432 if (word->index_shift) 1433 fprintf(fp, " lsl %u", word->index_shift); 1434 midgard_print_sint(fp, UNPACK_LDST_UBO_OFS(word->signed_offset)); 1435 } 1436 1437 /* mem addr expression */ 1438 if (OP_HAS_ADDRESS(word->op)) { 1439 fprintf(fp, ", "); 1440 bool first = true; 1441 1442 /* Skip printing zero */ 1443 if (word->arg_reg != 7 || verbose) { 1444 print_ldst_read_reg(fp, word->arg_reg); 1445 fprintf(fp, ".u%d.%c", 1446 word->bitsize_toggle ? 64 : 32, components[word->arg_comp]); 1447 first = false; 1448 } 1449 1450 if ((word->op < midgard_op_atomic_cmpxchg || 1451 word->op > midgard_op_atomic_cmpxchg64_be) && 1452 word->index_reg != 0x7) { 1453 if (!first) 1454 fprintf(fp, " + "); 1455 1456 print_ldst_read_reg(fp, word->index_reg); 1457 fprintf(fp, "%s.%c", 1458 index_format_names[word->index_format], 1459 components[word->index_comp]); 1460 if (word->index_shift) 1461 fprintf(fp, " lsl %u", word->index_shift); 1462 } 1463 1464 midgard_print_sint(fp, word->signed_offset); 1465 } 1466 1467 /* src reg for reg2reg ldst opcodes */ 1468 if (OP_IS_REG2REG_LDST(word->op)) { 1469 fprintf(fp, ", "); 1470 print_ldst_read_reg(fp, word->arg_reg); 1471 print_vec_swizzle(fp, word->swizzle, midgard_src_passthrough, 1472 midgard_reg_mode_32, 0xFF); 1473 } 1474 1475 /* atomic ops encode the source arg where the ldst swizzle would be. */ 1476 if (OP_IS_ATOMIC(word->op)) { 1477 unsigned src = (word->swizzle >> 2) & 0x7; 1478 unsigned src_comp = word->swizzle & 0x3; 1479 fprintf(fp, ", "); 1480 print_ldst_read_reg(fp, src); 1481 fprintf(fp, ".%c", components[src_comp]); 1482 } 1483 1484 /* CMPXCHG encodes the extra comparison arg where the index reg would be. */ 1485 if (word->op >= midgard_op_atomic_cmpxchg && 1486 word->op <= midgard_op_atomic_cmpxchg64_be) { 1487 fprintf(fp, ", "); 1488 print_ldst_read_reg(fp, word->index_reg); 1489 fprintf(fp, ".%c", components[word->index_comp]); 1490 } 1491 1492 /* index reg for attr/vary/images, selector for ld/st_special */ 1493 if (OP_IS_SPECIAL(word->op) || OP_USES_ATTRIB(word->op)) { 1494 fprintf(fp, ", "); 1495 print_ldst_read_reg(fp, word->index_reg); 1496 fprintf(fp, ".%c", components[word->index_comp]); 1497 if (word->index_shift) 1498 fprintf(fp, " lsl %u", word->index_shift); 1499 midgard_print_sint(fp, UNPACK_LDST_ATTRIB_OFS(word->signed_offset)); 1500 } 1501 1502 /* vertex reg for attrib/varying ops, coord reg for image ops */ 1503 if (OP_USES_ATTRIB(word->op)) { 1504 fprintf(fp, ", "); 1505 print_ldst_read_reg(fp, word->arg_reg); 1506 1507 if (OP_IS_IMAGE(word->op)) 1508 fprintf(fp, ".u%d", word->bitsize_toggle ? 64 : 32); 1509 1510 fprintf(fp, ".%c", components[word->arg_comp]); 1511 1512 if (word->bitsize_toggle && !OP_IS_IMAGE(word->op)) 1513 midgard_print_sint(fp, UNPACK_LDST_VERTEX_OFS(word->signed_offset)); 1514 } 1515 1516 /* TODO: properly decode format specifier for PACK/UNPACK ops */ 1517 if (OP_IS_PACK_COLOUR(word->op) || OP_IS_UNPACK_COLOUR(word->op)) { 1518 fprintf(fp, ", "); 1519 unsigned format_specifier = (word->signed_offset << 4) | word->index_shift; 1520 fprintf(fp, "0x%X", format_specifier); 1521 } 1522 1523 fprintf(fp, "\n"); 1524 1525 /* Debugging stuff */ 1526 1527 if (is_op_varying(word->op)) { 1528 /* Do some analysis: check if direct access */ 1529 1530 if (word->index_reg == 0x7 && ctx->midg_stats.varying_count >= 0) 1531 update_stats(&ctx->midg_stats.varying_count, 1532 UNPACK_LDST_ATTRIB_OFS(word->signed_offset)); 1533 else 1534 ctx->midg_stats.varying_count = -16; 1535 } else if (is_op_attribute(word->op)) { 1536 if (word->index_reg == 0x7 && ctx->midg_stats.attribute_count >= 0) 1537 update_stats(&ctx->midg_stats.attribute_count, 1538 UNPACK_LDST_ATTRIB_OFS(word->signed_offset)); 1539 else 1540 ctx->midg_stats.attribute_count = -16; 1541 } 1542 1543 if (!OP_IS_STORE(word->op)) 1544 update_dest(ctx, word->reg); 1545 1546 if (OP_IS_UBO_READ(word->op)) 1547 update_stats(&ctx->midg_stats.uniform_buffer_count, 1548 UNPACK_LDST_UBO_OFS(word->signed_offset)); 1549 1550 ctx->midg_stats.instruction_count++; 1551} 1552 1553static void 1554print_load_store_word(disassemble_context *ctx, FILE *fp, uint32_t *word, bool verbose) 1555{ 1556 midgard_load_store *load_store = (midgard_load_store *) word; 1557 1558 if (load_store->word1 != 3) { 1559 print_load_store_instr(ctx, fp, load_store->word1, verbose); 1560 } 1561 1562 if (load_store->word2 != 3) { 1563 print_load_store_instr(ctx, fp, load_store->word2, verbose); 1564 } 1565} 1566 1567static void 1568print_texture_reg_select(FILE *fp, uint8_t u, unsigned base) 1569{ 1570 midgard_tex_register_select sel; 1571 memcpy(&sel, &u, sizeof(u)); 1572 1573 print_tex_reg(fp, base + sel.select, false); 1574 1575 unsigned component = sel.component; 1576 1577 /* Use the upper half in half-reg mode */ 1578 if (sel.upper) { 1579 assert(!sel.full); 1580 component += 4; 1581 } 1582 1583 fprintf(fp, ".%c.%d", components[component], sel.full ? 32 : 16); 1584 1585 assert(sel.zero == 0); 1586} 1587 1588static void 1589print_texture_format(FILE *fp, int format) 1590{ 1591 /* Act like a modifier */ 1592 fprintf(fp, "."); 1593 1594 switch (format) { 1595 DEFINE_CASE(1, "1d"); 1596 DEFINE_CASE(2, "2d"); 1597 DEFINE_CASE(3, "3d"); 1598 DEFINE_CASE(0, "cube"); 1599 1600 default: 1601 unreachable("Bad format"); 1602 } 1603} 1604 1605static bool 1606midgard_op_has_helpers(unsigned op) 1607{ 1608 switch (op) { 1609 case midgard_tex_op_normal: 1610 case midgard_tex_op_derivative: 1611 return true; 1612 default: 1613 return false; 1614 } 1615} 1616 1617static void 1618print_texture_op(FILE *fp, unsigned op) 1619{ 1620 if (tex_opcode_props[op].name) 1621 fprintf(fp, "%s", tex_opcode_props[op].name); 1622 else 1623 fprintf(fp, "tex_op_%02X", op); 1624} 1625 1626static bool 1627texture_op_takes_bias(unsigned op) 1628{ 1629 return op == midgard_tex_op_normal; 1630} 1631 1632static char 1633sampler_type_name(enum mali_sampler_type t) 1634{ 1635 switch (t) { 1636 case MALI_SAMPLER_FLOAT: 1637 return 'f'; 1638 case MALI_SAMPLER_UNSIGNED: 1639 return 'u'; 1640 case MALI_SAMPLER_SIGNED: 1641 return 'i'; 1642 default: 1643 return '?'; 1644 } 1645 1646} 1647 1648static void 1649print_texture_barrier(FILE *fp, uint32_t *word) 1650{ 1651 midgard_texture_barrier_word *barrier = (midgard_texture_barrier_word *) word; 1652 1653 if (barrier->type != TAG_TEXTURE_4_BARRIER) 1654 fprintf(fp, "/* barrier tag %X != tex/bar */ ", barrier->type); 1655 1656 if (!barrier->cont) 1657 fprintf(fp, "/* cont missing? */"); 1658 1659 if (!barrier->last) 1660 fprintf(fp, "/* last missing? */"); 1661 1662 if (barrier->zero1) 1663 fprintf(fp, "/* zero1 = 0x%X */ ", barrier->zero1); 1664 1665 if (barrier->zero2) 1666 fprintf(fp, "/* zero2 = 0x%X */ ", barrier->zero2); 1667 1668 if (barrier->zero3) 1669 fprintf(fp, "/* zero3 = 0x%X */ ", barrier->zero3); 1670 1671 if (barrier->zero4) 1672 fprintf(fp, "/* zero4 = 0x%X */ ", barrier->zero4); 1673 1674 if (barrier->zero5) 1675 fprintf(fp, "/* zero4 = 0x%" PRIx64 " */ ", barrier->zero5); 1676 1677 if (barrier->out_of_order) 1678 fprintf(fp, ".ooo%u", barrier->out_of_order); 1679 1680 fprintf(fp, "\n"); 1681} 1682 1683#undef DEFINE_CASE 1684 1685static const char * 1686texture_mode(enum mali_texture_mode mode) 1687{ 1688 switch (mode) { 1689 case TEXTURE_NORMAL: return ""; 1690 case TEXTURE_SHADOW: return ".shadow"; 1691 case TEXTURE_GATHER_SHADOW: return ".gather.shadow"; 1692 case TEXTURE_GATHER_X: return ".gatherX"; 1693 case TEXTURE_GATHER_Y: return ".gatherY"; 1694 case TEXTURE_GATHER_Z: return ".gatherZ"; 1695 case TEXTURE_GATHER_W: return ".gatherW"; 1696 default: return "unk"; 1697 } 1698} 1699 1700static const char * 1701derivative_mode(enum mali_derivative_mode mode) 1702{ 1703 switch (mode) { 1704 case TEXTURE_DFDX: return ".x"; 1705 case TEXTURE_DFDY: return ".y"; 1706 default: return "unk"; 1707 } 1708} 1709 1710static void 1711print_texture_word(disassemble_context *ctx, FILE *fp, uint32_t *word, 1712 unsigned tabs, unsigned in_reg_base, unsigned out_reg_base) 1713{ 1714 midgard_texture_word *texture = (midgard_texture_word *) word; 1715 ctx->midg_stats.helper_invocations |= midgard_op_has_helpers(texture->op); 1716 validate_sampler_type(texture->op, texture->sampler_type); 1717 1718 /* Broad category of texture operation in question */ 1719 print_texture_op(fp, texture->op); 1720 1721 /* Barriers use a dramatically different code path */ 1722 if (texture->op == midgard_tex_op_barrier) { 1723 print_texture_barrier(fp, word); 1724 return; 1725 } else if (texture->type == TAG_TEXTURE_4_BARRIER) 1726 fprintf (fp, "/* nonbarrier had tex/bar tag */ "); 1727 else if (texture->type == TAG_TEXTURE_4_VTX) 1728 fprintf (fp, ".vtx"); 1729 1730 if (texture->op == midgard_tex_op_derivative) 1731 fprintf(fp, "%s", derivative_mode(texture->mode)); 1732 else 1733 fprintf(fp, "%s", texture_mode(texture->mode)); 1734 1735 /* Specific format in question */ 1736 print_texture_format(fp, texture->format); 1737 1738 /* Instruction "modifiers" parallel the ALU instructions. */ 1739 1740 if (texture->cont) 1741 fprintf(fp, ".cont"); 1742 1743 if (texture->last) 1744 fprintf(fp, ".last"); 1745 1746 if (texture->out_of_order) 1747 fprintf(fp, ".ooo%u", texture->out_of_order); 1748 1749 fprintf(fp, " "); 1750 print_tex_reg(fp, out_reg_base + texture->out_reg_select, true); 1751 print_tex_mask(fp, texture->mask, texture->out_upper); 1752 fprintf(fp, ".%c%d", texture->sampler_type == MALI_SAMPLER_FLOAT ? 'f' : 'i', 1753 texture->out_full ? 32 : 16); 1754 assert(!(texture->out_full && texture->out_upper)); 1755 1756 /* Output modifiers are only valid for float texture operations */ 1757 if (texture->sampler_type == MALI_SAMPLER_FLOAT) 1758 print_outmod(fp, texture->outmod, false); 1759 1760 fprintf(fp, ", "); 1761 1762 /* Depending on whether we read from textures directly or indirectly, 1763 * we may be able to update our analysis */ 1764 1765 if (texture->texture_register) { 1766 fprintf(fp, "texture["); 1767 print_texture_reg_select(fp, texture->texture_handle, in_reg_base); 1768 fprintf(fp, "], "); 1769 1770 /* Indirect, tut tut */ 1771 ctx->midg_stats.texture_count = -16; 1772 } else { 1773 fprintf(fp, "texture%u, ", texture->texture_handle); 1774 update_stats(&ctx->midg_stats.texture_count, texture->texture_handle); 1775 } 1776 1777 /* Print the type, GL style */ 1778 fprintf(fp, "%csampler", sampler_type_name(texture->sampler_type)); 1779 1780 if (texture->sampler_register) { 1781 fprintf(fp, "["); 1782 print_texture_reg_select(fp, texture->sampler_handle, in_reg_base); 1783 fprintf(fp, "]"); 1784 1785 ctx->midg_stats.sampler_count = -16; 1786 } else { 1787 fprintf(fp, "%u", texture->sampler_handle); 1788 update_stats(&ctx->midg_stats.sampler_count, texture->sampler_handle); 1789 } 1790 1791 print_vec_swizzle(fp, texture->swizzle, midgard_src_passthrough, midgard_reg_mode_32, 0xFF); 1792 1793 fprintf(fp, ", "); 1794 1795 midgard_src_expand_mode exp = 1796 texture->in_reg_upper ? midgard_src_expand_high : midgard_src_passthrough; 1797 print_tex_reg(fp, in_reg_base + texture->in_reg_select, false); 1798 print_vec_swizzle(fp, texture->in_reg_swizzle, exp, midgard_reg_mode_32, 0xFF); 1799 fprintf(fp, ".%d", texture->in_reg_full ? 32 : 16); 1800 assert(!(texture->in_reg_full && texture->in_reg_upper)); 1801 1802 /* There is *always* an offset attached. Of 1803 * course, that offset is just immediate #0 for a 1804 * GLES call that doesn't take an offset. If there 1805 * is a non-negative non-zero offset, this is 1806 * specified in immediate offset mode, with the 1807 * values in the offset_* fields as immediates. If 1808 * this is a negative offset, we instead switch to 1809 * a register offset mode, where the offset_* 1810 * fields become register triplets */ 1811 1812 if (texture->offset_register) { 1813 fprintf(fp, " + "); 1814 1815 bool full = texture->offset & 1; 1816 bool select = texture->offset & 2; 1817 bool upper = texture->offset & 4; 1818 unsigned swizzle = texture->offset >> 3; 1819 midgard_src_expand_mode exp = 1820 upper ? midgard_src_expand_high : midgard_src_passthrough; 1821 1822 print_tex_reg(fp, in_reg_base + select, false); 1823 print_vec_swizzle(fp, swizzle, exp, midgard_reg_mode_32, 0xFF); 1824 fprintf(fp, ".%d", full ? 32 : 16); 1825 assert(!(texture->out_full && texture->out_upper)); 1826 1827 fprintf(fp, ", "); 1828 } else if (texture->offset) { 1829 /* Only select ops allow negative immediate offsets, verify */ 1830 1831 signed offset_x = (texture->offset & 0xF); 1832 signed offset_y = ((texture->offset >> 4) & 0xF); 1833 signed offset_z = ((texture->offset >> 8) & 0xF); 1834 1835 bool neg_x = offset_x < 0; 1836 bool neg_y = offset_y < 0; 1837 bool neg_z = offset_z < 0; 1838 bool any_neg = neg_x || neg_y || neg_z; 1839 1840 if (any_neg && texture->op != midgard_tex_op_fetch) 1841 fprintf(fp, "/* invalid negative */ "); 1842 1843 /* Regardless, just print the immediate offset */ 1844 1845 fprintf(fp, " + <%d, %d, %d>, ", offset_x, offset_y, offset_z); 1846 } else { 1847 fprintf(fp, ", "); 1848 } 1849 1850 char lod_operand = texture_op_takes_bias(texture->op) ? '+' : '='; 1851 1852 if (texture->lod_register) { 1853 fprintf(fp, "lod %c ", lod_operand); 1854 print_texture_reg_select(fp, texture->bias, in_reg_base); 1855 fprintf(fp, ", "); 1856 1857 if (texture->bias_int) 1858 fprintf(fp, " /* bias_int = 0x%X */", texture->bias_int); 1859 } else if (texture->op == midgard_tex_op_fetch) { 1860 /* For texel fetch, the int LOD is in the fractional place and 1861 * there is no fraction. We *always* have an explicit LOD, even 1862 * if it's zero. */ 1863 1864 if (texture->bias_int) 1865 fprintf(fp, " /* bias_int = 0x%X */ ", texture->bias_int); 1866 1867 fprintf(fp, "lod = %u, ", texture->bias); 1868 } else if (texture->bias || texture->bias_int) { 1869 signed bias_int = texture->bias_int; 1870 float bias_frac = texture->bias / 256.0f; 1871 float bias = bias_int + bias_frac; 1872 1873 bool is_bias = texture_op_takes_bias(texture->op); 1874 char sign = (bias >= 0.0) ? '+' : '-'; 1875 char operand = is_bias ? sign : '='; 1876 1877 fprintf(fp, "lod %c %f, ", operand, fabsf(bias)); 1878 } 1879 1880 fprintf(fp, "\n"); 1881 1882 /* While not zero in general, for these simple instructions the 1883 * following unknowns are zero, so we don't include them */ 1884 1885 if (texture->unknown4 || 1886 texture->unknown8) { 1887 fprintf(fp, "// unknown4 = 0x%x\n", texture->unknown4); 1888 fprintf(fp, "// unknown8 = 0x%x\n", texture->unknown8); 1889 } 1890 1891 ctx->midg_stats.instruction_count++; 1892} 1893 1894struct midgard_disasm_stats 1895disassemble_midgard(FILE *fp, uint8_t *code, size_t size, unsigned gpu_id, bool verbose) 1896{ 1897 uint32_t *words = (uint32_t *) code; 1898 unsigned num_words = size / 4; 1899 int tabs = 0; 1900 1901 bool branch_forward = false; 1902 1903 int last_next_tag = -1; 1904 1905 unsigned i = 0; 1906 1907 disassemble_context ctx = { 1908 .midg_tags = calloc(sizeof(ctx.midg_tags[0]), num_words), 1909 .midg_stats = {0}, 1910 .midg_ever_written = 0, 1911 }; 1912 1913 while (i < num_words) { 1914 unsigned tag = words[i] & 0xF; 1915 unsigned next_tag = (words[i] >> 4) & 0xF; 1916 unsigned num_quad_words = midgard_tag_props[tag].size; 1917 1918 if (ctx.midg_tags[i] && ctx.midg_tags[i] != tag) { 1919 fprintf(fp, "\t/* XXX: TAG ERROR branch, got %s expected %s */\n", 1920 midgard_tag_props[tag].name, 1921 midgard_tag_props[ctx.midg_tags[i]].name); 1922 } 1923 1924 ctx.midg_tags[i] = tag; 1925 1926 /* Check the tag. The idea is to ensure that next_tag is 1927 * *always* recoverable from the disassembly, such that we may 1928 * safely omit printing next_tag. To show this, we first 1929 * consider that next tags are semantically off-byone -- we end 1930 * up parsing tag n during step n+1. So, we ensure after we're 1931 * done disassembling the next tag of the final bundle is BREAK 1932 * and warn otherwise. We also ensure that the next tag is 1933 * never INVALID. Beyond that, since the last tag is checked 1934 * outside the loop, we can check one tag prior. If equal to 1935 * the current tag (which is unique), we're done. Otherwise, we 1936 * print if that tag was > TAG_BREAK, which implies the tag was 1937 * not TAG_BREAK or TAG_INVALID. But we already checked for 1938 * TAG_INVALID, so it's just if the last tag was TAG_BREAK that 1939 * we're silent. So we throw in a print for break-next on at 1940 * the end of the bundle (if it's not the final bundle, which 1941 * we already check for above), disambiguating this case as 1942 * well. Hence in all cases we are unambiguous, QED. */ 1943 1944 if (next_tag == TAG_INVALID) 1945 fprintf(fp, "\t/* XXX: invalid next tag */\n"); 1946 1947 if (last_next_tag > TAG_BREAK && last_next_tag != tag) { 1948 fprintf(fp, "\t/* XXX: TAG ERROR sequence, got %s expexted %s */\n", 1949 midgard_tag_props[tag].name, 1950 midgard_tag_props[last_next_tag].name); 1951 } 1952 1953 last_next_tag = next_tag; 1954 1955 /* Tags are unique in the following way: 1956 * 1957 * INVALID, BREAK, UNKNOWN_*: verbosely printed 1958 * TEXTURE_4_BARRIER: verified by barrier/!barrier op 1959 * TEXTURE_4_VTX: .vtx tag printed 1960 * TEXTURE_4: tetxure lack of barriers or .vtx 1961 * TAG_LOAD_STORE_4: only load/store 1962 * TAG_ALU_4/8/12/16: by number of instructions/constants 1963 * TAG_ALU_4_8/12/16_WRITEOUT: ^^ with .writeout tag 1964 */ 1965 1966 switch (tag) { 1967 case TAG_TEXTURE_4_VTX ... TAG_TEXTURE_4_BARRIER: { 1968 bool interpipe_aliasing = 1969 midgard_get_quirks(gpu_id) & MIDGARD_INTERPIPE_REG_ALIASING; 1970 1971 print_texture_word(&ctx, fp, &words[i], tabs, 1972 interpipe_aliasing ? 0 : REG_TEX_BASE, 1973 interpipe_aliasing ? REGISTER_LDST_BASE : REG_TEX_BASE); 1974 break; 1975 } 1976 1977 case TAG_LOAD_STORE_4: 1978 print_load_store_word(&ctx, fp, &words[i], verbose); 1979 break; 1980 1981 case TAG_ALU_4 ... TAG_ALU_16_WRITEOUT: 1982 branch_forward = print_alu_word(&ctx, fp, &words[i], num_quad_words, tabs, i + 4*num_quad_words, verbose); 1983 1984 /* TODO: infer/verify me */ 1985 if (tag >= TAG_ALU_4_WRITEOUT) 1986 fprintf(fp, "writeout\n"); 1987 1988 break; 1989 1990 default: 1991 fprintf(fp, "Unknown word type %u:\n", words[i] & 0xF); 1992 num_quad_words = 1; 1993 print_quad_word(fp, &words[i], tabs); 1994 fprintf(fp, "\n"); 1995 break; 1996 } 1997 1998 /* We are parsing per bundle anyway. Add before we start 1999 * breaking out so we don't miss the final bundle. */ 2000 2001 ctx.midg_stats.bundle_count++; 2002 ctx.midg_stats.quadword_count += num_quad_words; 2003 2004 /* Include a synthetic "break" instruction at the end of the 2005 * bundle to signify that if, absent a branch, the shader 2006 * execution will stop here. Stop disassembly at such a break 2007 * based on a heuristic */ 2008 2009 if (next_tag == TAG_BREAK) { 2010 if (branch_forward) { 2011 fprintf(fp, "break\n"); 2012 } else { 2013 fprintf(fp, "\n"); 2014 break; 2015 } 2016 } 2017 2018 fprintf(fp, "\n"); 2019 2020 i += 4 * num_quad_words; 2021 } 2022 2023 if (last_next_tag != TAG_BREAK) { 2024 fprintf(fp, "/* XXX: shader ended with tag %s */\n", 2025 midgard_tag_props[last_next_tag].name); 2026 } 2027 2028 free(ctx.midg_tags); 2029 2030 /* We computed work_count as max_work_registers, so add one to get the 2031 * count. If no work registers are written, you still have one work 2032 * reported, which is exactly what the hardware expects */ 2033 2034 ctx.midg_stats.work_count++; 2035 2036 return ctx.midg_stats; 2037} 2038