1/* 2 * Copyright (c) 2013 Rob Clark <robdclark@gmail.com> 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include <assert.h> 25#include <stdbool.h> 26#include <stdint.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30 31#include <util/log.h> 32#include <util/u_debug.h> 33 34#include "isa/isa.h" 35 36#include "disasm.h" 37#include "instr-a3xx.h" 38 39static enum debug_t debug; 40 41static const char *levels[] = { 42 "", 43 "\t", 44 "\t\t", 45 "\t\t\t", 46 "\t\t\t\t", 47 "\t\t\t\t\t", 48 "\t\t\t\t\t\t", 49 "\t\t\t\t\t\t\t", 50 "\t\t\t\t\t\t\t\t", 51 "\t\t\t\t\t\t\t\t\t", 52 "x", 53 "x", 54 "x", 55 "x", 56 "x", 57 "x", 58}; 59 60struct disasm_ctx { 61 FILE *out; 62 struct isa_decode_options *options; 63 unsigned level; 64 unsigned extra_cycles; 65 66 /** 67 * nop_count/has_end used to detect the real end of shader. Since 68 * in some cases there can be a epilogue following an `end` we look 69 * for a sequence of `nop`s following the `end` 70 */ 71 int nop_count; /* number of nop's since non-nop instruction: */ 72 bool has_end; /* have we seen end instruction */ 73 74 int cur_n; /* current instr # */ 75 int cur_opc_cat; /* current opc_cat */ 76 77 int sfu_delay; 78 79 /** 80 * State accumulated decoding fields of the current instruction, 81 * handled after decoding is complete (ie. at start of next instr) 82 */ 83 struct { 84 bool ss; 85 uint8_t nop; 86 uint8_t repeat; 87 } last; 88 89 /** 90 * State accumulated decoding fields of src or dst register 91 */ 92 struct { 93 bool half; 94 bool r; 95 enum { 96 FILE_GPR = 1, 97 FILE_CONST = 2, 98 } file; 99 unsigned num; 100 } reg; 101 102 struct shader_stats *stats; 103}; 104 105static void 106print_stats(struct disasm_ctx *ctx) 107{ 108 if (ctx->options->gpu_id >= 600) { 109 /* handle MERGEREGS case.. this isn't *entirely* accurate, as 110 * you can have shader stages not using merged register file, 111 * but it is good enough for a guestimate: 112 */ 113 unsigned n = (ctx->stats->halfreg + 1) / 2; 114 115 ctx->stats->halfreg = 0; 116 ctx->stats->fullreg = MAX2(ctx->stats->fullreg, n); 117 } 118 119 unsigned instructions = ctx->cur_n + ctx->extra_cycles + 1; 120 121 fprintf(ctx->out, "%sStats:\n", levels[ctx->level]); 122 fprintf(ctx->out, 123 "%s- shaderdb: %u instr, %u nops, %u non-nops, %u mov, %u cov\n", 124 levels[ctx->level], instructions, ctx->stats->nops, 125 instructions - ctx->stats->nops, ctx->stats->mov_count, 126 ctx->stats->cov_count); 127 128 fprintf(ctx->out, 129 "%s- shaderdb: %u last-baryf, %d half, %d full, %u constlen\n", 130 levels[ctx->level], ctx->stats->last_baryf, 131 DIV_ROUND_UP(ctx->stats->halfreg, 4), 132 DIV_ROUND_UP(ctx->stats->fullreg, 4), 133 DIV_ROUND_UP(ctx->stats->constlen, 4)); 134 135 fprintf( 136 ctx->out, 137 "%s- shaderdb: %u cat0, %u cat1, %u cat2, %u cat3, %u cat4, %u cat5, %u cat6, %u cat7\n", 138 levels[ctx->level], ctx->stats->instrs_per_cat[0], 139 ctx->stats->instrs_per_cat[1], ctx->stats->instrs_per_cat[2], 140 ctx->stats->instrs_per_cat[3], ctx->stats->instrs_per_cat[4], 141 ctx->stats->instrs_per_cat[5], ctx->stats->instrs_per_cat[6], 142 ctx->stats->instrs_per_cat[7]); 143 144 fprintf(ctx->out, "%s- shaderdb: %u sstall, %u (ss), %u (sy)\n", 145 levels[ctx->level], ctx->stats->sstall, ctx->stats->ss, 146 ctx->stats->sy); 147} 148 149/* size of largest OPC field of all the instruction categories: */ 150#define NOPC_BITS 6 151 152static const struct opc_info { 153 const char *name; 154} opcs[1 << (3 + NOPC_BITS)] = { 155#define OPC(cat, opc, name) [(opc)] = {#name} 156 /* clang-format off */ 157 /* category 0: */ 158 OPC(0, OPC_NOP, nop), 159 OPC(0, OPC_B, b), 160 OPC(0, OPC_JUMP, jump), 161 OPC(0, OPC_CALL, call), 162 OPC(0, OPC_RET, ret), 163 OPC(0, OPC_KILL, kill), 164 OPC(0, OPC_DEMOTE, demote), 165 OPC(0, OPC_END, end), 166 OPC(0, OPC_EMIT, emit), 167 OPC(0, OPC_CUT, cut), 168 OPC(0, OPC_CHMASK, chmask), 169 OPC(0, OPC_CHSH, chsh), 170 OPC(0, OPC_FLOW_REV, flow_rev), 171 OPC(0, OPC_PREDT, predt), 172 OPC(0, OPC_PREDF, predf), 173 OPC(0, OPC_PREDE, prede), 174 OPC(0, OPC_BKT, bkt), 175 OPC(0, OPC_STKS, stks), 176 OPC(0, OPC_STKR, stkr), 177 OPC(0, OPC_XSET, xset), 178 OPC(0, OPC_XCLR, xclr), 179 OPC(0, OPC_GETONE, getone), 180 OPC(0, OPC_DBG, dbg), 181 OPC(0, OPC_SHPS, shps), 182 OPC(0, OPC_SHPE, shpe), 183 184 /* category 1: */ 185 OPC(1, OPC_MOV, ), 186 OPC(1, OPC_MOVMSK, movmsk), 187 OPC(1, OPC_SWZ, swz), 188 OPC(1, OPC_SCT, sct), 189 OPC(1, OPC_GAT, gat), 190 OPC(1, OPC_BALLOT_MACRO, ballot.macro), 191 OPC(1, OPC_ANY_MACRO, any.macro), 192 OPC(1, OPC_ALL_MACRO, all.macro), 193 OPC(1, OPC_ELECT_MACRO, elect.macro), 194 OPC(1, OPC_READ_COND_MACRO, read_cond.macro), 195 OPC(1, OPC_READ_FIRST_MACRO, read_first.macro), 196 OPC(1, OPC_SWZ_SHARED_MACRO, swz_shared.macro), 197 198 /* category 2: */ 199 OPC(2, OPC_ADD_F, add.f), 200 OPC(2, OPC_MIN_F, min.f), 201 OPC(2, OPC_MAX_F, max.f), 202 OPC(2, OPC_MUL_F, mul.f), 203 OPC(2, OPC_SIGN_F, sign.f), 204 OPC(2, OPC_CMPS_F, cmps.f), 205 OPC(2, OPC_ABSNEG_F, absneg.f), 206 OPC(2, OPC_CMPV_F, cmpv.f), 207 OPC(2, OPC_FLOOR_F, floor.f), 208 OPC(2, OPC_CEIL_F, ceil.f), 209 OPC(2, OPC_RNDNE_F, rndne.f), 210 OPC(2, OPC_RNDAZ_F, rndaz.f), 211 OPC(2, OPC_TRUNC_F, trunc.f), 212 OPC(2, OPC_ADD_U, add.u), 213 OPC(2, OPC_ADD_S, add.s), 214 OPC(2, OPC_SUB_U, sub.u), 215 OPC(2, OPC_SUB_S, sub.s), 216 OPC(2, OPC_CMPS_U, cmps.u), 217 OPC(2, OPC_CMPS_S, cmps.s), 218 OPC(2, OPC_MIN_U, min.u), 219 OPC(2, OPC_MIN_S, min.s), 220 OPC(2, OPC_MAX_U, max.u), 221 OPC(2, OPC_MAX_S, max.s), 222 OPC(2, OPC_ABSNEG_S, absneg.s), 223 OPC(2, OPC_AND_B, and.b), 224 OPC(2, OPC_OR_B, or.b), 225 OPC(2, OPC_NOT_B, not.b), 226 OPC(2, OPC_XOR_B, xor.b), 227 OPC(2, OPC_CMPV_U, cmpv.u), 228 OPC(2, OPC_CMPV_S, cmpv.s), 229 OPC(2, OPC_MUL_U24, mul.u24), 230 OPC(2, OPC_MUL_S24, mul.s24), 231 OPC(2, OPC_MULL_U, mull.u), 232 OPC(2, OPC_BFREV_B, bfrev.b), 233 OPC(2, OPC_CLZ_S, clz.s), 234 OPC(2, OPC_CLZ_B, clz.b), 235 OPC(2, OPC_SHL_B, shl.b), 236 OPC(2, OPC_SHR_B, shr.b), 237 OPC(2, OPC_ASHR_B, ashr.b), 238 OPC(2, OPC_BARY_F, bary.f), 239 OPC(2, OPC_MGEN_B, mgen.b), 240 OPC(2, OPC_GETBIT_B, getbit.b), 241 OPC(2, OPC_SETRM, setrm), 242 OPC(2, OPC_CBITS_B, cbits.b), 243 OPC(2, OPC_SHB, shb), 244 OPC(2, OPC_MSAD, msad), 245 246 /* category 3: */ 247 OPC(3, OPC_MAD_U16, mad.u16), 248 OPC(3, OPC_MADSH_U16, madsh.u16), 249 OPC(3, OPC_MAD_S16, mad.s16), 250 OPC(3, OPC_MADSH_M16, madsh.m16), 251 OPC(3, OPC_MAD_U24, mad.u24), 252 OPC(3, OPC_MAD_S24, mad.s24), 253 OPC(3, OPC_MAD_F16, mad.f16), 254 OPC(3, OPC_MAD_F32, mad.f32), 255 OPC(3, OPC_SEL_B16, sel.b16), 256 OPC(3, OPC_SEL_B32, sel.b32), 257 OPC(3, OPC_SEL_S16, sel.s16), 258 OPC(3, OPC_SEL_S32, sel.s32), 259 OPC(3, OPC_SEL_F16, sel.f16), 260 OPC(3, OPC_SEL_F32, sel.f32), 261 OPC(3, OPC_SAD_S16, sad.s16), 262 OPC(3, OPC_SAD_S32, sad.s32), 263 OPC(3, OPC_SHLG_B16, shlg.b16), 264 265 /* category 4: */ 266 OPC(4, OPC_RCP, rcp), 267 OPC(4, OPC_RSQ, rsq), 268 OPC(4, OPC_LOG2, log2), 269 OPC(4, OPC_EXP2, exp2), 270 OPC(4, OPC_SIN, sin), 271 OPC(4, OPC_COS, cos), 272 OPC(4, OPC_SQRT, sqrt), 273 OPC(4, OPC_HRSQ, hrsq), 274 OPC(4, OPC_HLOG2, hlog2), 275 OPC(4, OPC_HEXP2, hexp2), 276 277 /* category 5: */ 278 OPC(5, OPC_ISAM, isam), 279 OPC(5, OPC_ISAML, isaml), 280 OPC(5, OPC_ISAMM, isamm), 281 OPC(5, OPC_SAM, sam), 282 OPC(5, OPC_SAMB, samb), 283 OPC(5, OPC_SAML, saml), 284 OPC(5, OPC_SAMGQ, samgq), 285 OPC(5, OPC_GETLOD, getlod), 286 OPC(5, OPC_CONV, conv), 287 OPC(5, OPC_CONVM, convm), 288 OPC(5, OPC_GETSIZE, getsize), 289 OPC(5, OPC_GETBUF, getbuf), 290 OPC(5, OPC_GETPOS, getpos), 291 OPC(5, OPC_GETINFO, getinfo), 292 OPC(5, OPC_DSX, dsx), 293 OPC(5, OPC_DSY, dsy), 294 OPC(5, OPC_GATHER4R, gather4r), 295 OPC(5, OPC_GATHER4G, gather4g), 296 OPC(5, OPC_GATHER4B, gather4b), 297 OPC(5, OPC_GATHER4A, gather4a), 298 OPC(5, OPC_SAMGP0, samgp0), 299 OPC(5, OPC_SAMGP1, samgp1), 300 OPC(5, OPC_SAMGP2, samgp2), 301 OPC(5, OPC_SAMGP3, samgp3), 302 OPC(5, OPC_DSXPP_1, dsxpp.1), 303 OPC(5, OPC_DSYPP_1, dsypp.1), 304 OPC(5, OPC_RGETPOS, rgetpos), 305 OPC(5, OPC_RGETINFO, rgetinfo), 306 /* macros are needed here for ir3_print */ 307 OPC(5, OPC_DSXPP_MACRO, dsxpp.macro), 308 OPC(5, OPC_DSYPP_MACRO, dsypp.macro), 309 310 311 /* category 6: */ 312 OPC(6, OPC_LDG, ldg), 313 OPC(6, OPC_LDG_A, ldg.a), 314 OPC(6, OPC_LDL, ldl), 315 OPC(6, OPC_LDP, ldp), 316 OPC(6, OPC_STG, stg), 317 OPC(6, OPC_STG_A, stg.a), 318 OPC(6, OPC_STL, stl), 319 OPC(6, OPC_STP, stp), 320 OPC(6, OPC_LDIB, ldib), 321 OPC(6, OPC_G2L, g2l), 322 OPC(6, OPC_L2G, l2g), 323 OPC(6, OPC_PREFETCH, prefetch), 324 OPC(6, OPC_LDLW, ldlw), 325 OPC(6, OPC_STLW, stlw), 326 OPC(6, OPC_RESFMT, resfmt), 327 OPC(6, OPC_RESINFO, resinfo), 328 OPC(6, OPC_ATOMIC_ADD, atomic.add), 329 OPC(6, OPC_ATOMIC_SUB, atomic.sub), 330 OPC(6, OPC_ATOMIC_XCHG, atomic.xchg), 331 OPC(6, OPC_ATOMIC_INC, atomic.inc), 332 OPC(6, OPC_ATOMIC_DEC, atomic.dec), 333 OPC(6, OPC_ATOMIC_CMPXCHG, atomic.cmpxchg), 334 OPC(6, OPC_ATOMIC_MIN, atomic.min), 335 OPC(6, OPC_ATOMIC_MAX, atomic.max), 336 OPC(6, OPC_ATOMIC_AND, atomic.and), 337 OPC(6, OPC_ATOMIC_OR, atomic.or), 338 OPC(6, OPC_ATOMIC_XOR, atomic.xor), 339 OPC(6, OPC_LDGB, ldgb), 340 OPC(6, OPC_STGB, stgb), 341 OPC(6, OPC_STIB, stib), 342 OPC(6, OPC_LDC, ldc), 343 OPC(6, OPC_LDLV, ldlv), 344 OPC(6, OPC_PIPR, pipr), 345 OPC(6, OPC_PIPC, pipc), 346 OPC(6, OPC_EMIT2, emit), 347 OPC(6, OPC_ENDLS, endls), 348 OPC(6, OPC_GETSPID, getspid), 349 OPC(6, OPC_GETWID, getwid), 350 351 OPC(6, OPC_SPILL_MACRO, spill.macro), 352 OPC(6, OPC_RELOAD_MACRO, reload.macro), 353 354 OPC(7, OPC_BAR, bar), 355 OPC(7, OPC_FENCE, fence), 356/* clang-format on */ 357#undef OPC 358}; 359 360#define GETINFO(instr) \ 361 (&(opcs[((instr)->opc_cat << NOPC_BITS) | instr_opc(instr, ctx->gpu_id)])) 362 363const char * 364disasm_a3xx_instr_name(opc_t opc) 365{ 366 if (opc_cat(opc) == -1) 367 return "??meta??"; 368 return opcs[opc].name; 369} 370 371static void 372disasm_field_cb(void *d, const char *field_name, struct isa_decode_value *val) 373{ 374 struct disasm_ctx *ctx = d; 375 376 if (!strcmp(field_name, "NAME")) { 377 if (!strcmp("nop", val->str)) { 378 if (ctx->has_end) { 379 ctx->nop_count++; 380 if (ctx->nop_count > 3) { 381 ctx->options->stop = true; 382 } 383 } 384 ctx->stats->nops += 1 + ctx->last.repeat; 385 } else { 386 ctx->nop_count = 0; 387 } 388 389 if (!strcmp("end", val->str)) { 390 ctx->has_end = true; 391 ctx->nop_count = 0; 392 } else if (!strcmp("chsh", val->str)) { 393 ctx->options->stop = true; 394 } else if (!strcmp("bary.f", val->str)) { 395 ctx->stats->last_baryf = ctx->cur_n; 396 } 397 } else if (!strcmp(field_name, "REPEAT")) { 398 ctx->extra_cycles += val->num; 399 ctx->stats->instrs_per_cat[ctx->cur_opc_cat] += val->num; 400 ctx->last.repeat = val->num; 401 } else if (!strcmp(field_name, "NOP")) { 402 ctx->extra_cycles += val->num; 403 ctx->stats->instrs_per_cat[0] += val->num; 404 ctx->stats->nops += val->num; 405 ctx->last.nop = val->num; 406 } else if (!strcmp(field_name, "SY")) { 407 ctx->stats->sy += val->num; 408 } else if (!strcmp(field_name, "SS")) { 409 ctx->stats->ss += val->num; 410 ctx->last.ss = !!val->num; 411 } else if (!strcmp(field_name, "CONST")) { 412 ctx->reg.num = val->num; 413 ctx->reg.file = FILE_CONST; 414 } else if (!strcmp(field_name, "GPR")) { 415 /* don't count GPR regs r48.x (shared) or higher: */ 416 if (val->num < 48) { 417 ctx->reg.num = val->num; 418 ctx->reg.file = FILE_GPR; 419 } 420 } else if (!strcmp(field_name, "SRC_R") || !strcmp(field_name, "SRC1_R") || 421 !strcmp(field_name, "SRC2_R") || !strcmp(field_name, "SRC3_R")) { 422 ctx->reg.r = val->num; 423 } else if (!strcmp(field_name, "DST")) { 424 /* Dest register is always repeated 425 * 426 * Note that this doesn't really properly handle instructions 427 * that write multiple components.. the old disasm didn't handle 428 * that case either. 429 */ 430 ctx->reg.r = true; 431 } else if (strstr(field_name, "HALF")) { 432 ctx->reg.half = val->num; 433 } else if (!strcmp(field_name, "SWIZ")) { 434 unsigned num = (ctx->reg.num << 2) | val->num; 435 if (ctx->reg.r) 436 num += ctx->last.repeat; 437 438 if (ctx->reg.file == FILE_CONST) { 439 ctx->stats->constlen = MAX2(ctx->stats->constlen, num); 440 } else if (ctx->reg.file == FILE_GPR) { 441 if (ctx->reg.half) { 442 ctx->stats->halfreg = MAX2(ctx->stats->halfreg, num); 443 } else { 444 ctx->stats->fullreg = MAX2(ctx->stats->fullreg, num); 445 } 446 } 447 448 memset(&ctx->reg, 0, sizeof(ctx->reg)); 449 } 450} 451 452/** 453 * Handle stat updates dealt with at the end of instruction decoding, 454 * ie. before beginning of next instruction 455 */ 456static void 457disasm_handle_last(struct disasm_ctx *ctx) 458{ 459 if (ctx->last.ss) { 460 ctx->stats->sstall += ctx->sfu_delay; 461 ctx->sfu_delay = 0; 462 } 463 464 if (ctx->cur_opc_cat == 4) { 465 ctx->sfu_delay = 10; 466 } else { 467 int n = MIN2(ctx->sfu_delay, 1 + ctx->last.repeat + ctx->last.nop); 468 ctx->sfu_delay -= n; 469 } 470 471 memset(&ctx->last, 0, sizeof(ctx->last)); 472} 473 474static void 475disasm_instr_cb(void *d, unsigned n, void *instr) 476{ 477 struct disasm_ctx *ctx = d; 478 uint32_t *dwords = (uint32_t *)instr; 479 uint64_t val = dwords[1]; 480 val = val << 32; 481 val |= dwords[0]; 482 483 unsigned opc_cat = val >> 61; 484 485 /* There are some cases where we can get instr_cb called multiple 486 * times per instruction (like when we need an extra line for branch 487 * target labels), don't update stats in these cases: 488 */ 489 if (n != ctx->cur_n) { 490 if (n > 0) { 491 disasm_handle_last(ctx); 492 } 493 ctx->stats->instrs_per_cat[opc_cat]++; 494 ctx->cur_n = n; 495 496 /* mov vs cov stats are a bit harder to fish out of the field 497 * names, because current ir3-cat1.xml doesn't use {NAME} for 498 * this distinction. So for now just handle this case with 499 * some hand-coded parsing: 500 */ 501 if (opc_cat == 1) { 502 unsigned opc = (val >> 57) & 0x3; 503 unsigned src_type = (val >> 50) & 0x7; 504 unsigned dst_type = (val >> 46) & 0x7; 505 506 if (opc == 0) { 507 if (src_type == dst_type) { 508 ctx->stats->mov_count++; 509 } else { 510 ctx->stats->cov_count++; 511 } 512 } 513 } 514 } 515 516 ctx->cur_opc_cat = opc_cat; 517 518 if (debug & PRINT_RAW) { 519 fprintf(ctx->out, "%s:%d:%04d:%04d[%08xx_%08xx] ", levels[ctx->level], 520 opc_cat, n, ctx->extra_cycles + n, dwords[1], dwords[0]); 521 } 522} 523 524int 525disasm_a3xx_stat(uint32_t *dwords, int sizedwords, int level, FILE *out, 526 unsigned gpu_id, struct shader_stats *stats) 527{ 528 struct isa_decode_options decode_options = { 529 .gpu_id = gpu_id, 530 .show_errors = true, 531 .max_errors = 5, 532 .branch_labels = true, 533 .field_cb = disasm_field_cb, 534 .instr_cb = disasm_instr_cb, 535 }; 536 struct disasm_ctx ctx = { 537 .out = out, 538 .level = level, 539 .options = &decode_options, 540 .stats = stats, 541 .cur_n = -1, 542 }; 543 544 memset(stats, 0, sizeof(*stats)); 545 546 decode_options.cbdata = &ctx; 547 548 isa_decode(dwords, sizedwords * 4, out, &decode_options); 549 550 disasm_handle_last(&ctx); 551 552 if (debug & PRINT_STATS) 553 print_stats(&ctx); 554 555 return 0; 556} 557 558void 559disasm_a3xx_set_debug(enum debug_t d) 560{ 561 debug = d; 562} 563 564#include <setjmp.h> 565 566static bool jmp_env_valid; 567static jmp_buf jmp_env; 568 569void 570ir3_assert_handler(const char *expr, const char *file, int line, 571 const char *func) 572{ 573 mesa_loge("%s:%u: %s: Assertion `%s' failed.", file, line, func, expr); 574 if (jmp_env_valid) 575 longjmp(jmp_env, 1); 576 abort(); 577} 578 579#define TRY(x) \ 580 do { \ 581 assert(!jmp_env_valid); \ 582 if (setjmp(jmp_env) == 0) { \ 583 jmp_env_valid = true; \ 584 x; \ 585 } \ 586 jmp_env_valid = false; \ 587 } while (0) 588 589int 590disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, 591 unsigned gpu_id) 592{ 593 struct shader_stats stats; 594 return disasm_a3xx_stat(dwords, sizedwords, level, out, gpu_id, &stats); 595} 596 597int 598try_disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, 599 unsigned gpu_id) 600{ 601 struct shader_stats stats; 602 int ret = -1; 603 TRY(ret = disasm_a3xx_stat(dwords, sizedwords, level, out, gpu_id, &stats)); 604 return ret; 605} 606