enum debug_t {
PRINT_RAW = 0x1, /* dump raw hexdump */
PRINT_VERBOSE = 0x2,
+ EXPAND_REPEAT = 0x4,
};
static enum debug_t debug;
/* current instruction repeat flag: */
unsigned repeat;
+ /* current instruction repeat indx/offset (for --expand): */
+ unsigned repeatidx;
+
+ unsigned instructions;
+};
+
+static const char *float_imms[] = {
+ "0.0",
+ "0.5",
+ "1.0",
+ "2.0",
+ "e",
+ "pi",
+ "1/pi",
+ "1/log2(e)",
+ "log2(e)",
+ "1/log2(10)",
+ "log2(10)",
+ "4.0",
};
-static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, bool r,
+static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full,
+ bool is_float, bool r,
bool c, bool im, bool neg, bool abs, bool addr_rel)
{
const char type = c ? 'c' : 'r';
fprintf(ctx->out, "(r)");
if (im) {
- fprintf(ctx->out, "%d", reg.iim_val);
+ if (is_float && full && reg.iim_val < ARRAY_SIZE(float_imms)) {
+ fprintf(ctx->out, "(%s)", float_imms[reg.iim_val]);
+ } else {
+ fprintf(ctx->out, "%d", reg.iim_val);
+ }
} else if (addr_rel) {
/* I would just use %+d but trying to make it diff'able with
* libllvm-a3xx...
else
fprintf(ctx->out, "%s%c<a0.x>", full ? "" : "h", type);
} else if ((reg.num == REG_A0) && !c) {
- fprintf(ctx->out, "a0.%c", component[reg.comp]);
+ /* This matches libllvm output, the second (scalar) address register
+ * seems to be called a1.x instead of a0.y.
+ */
+ fprintf(ctx->out, "a%d.x", reg.comp);
} else if ((reg.num == REG_P0) && !c) {
fprintf(ctx->out, "p0.%c", component[reg.comp]);
} else {
fprintf(ctx->out, "%s%c%d.%c", full ? "" : "h", type, reg.num, component[reg.comp]);
+ if (0 && full && !c) {
+ reg_t hr0 = reg;
+ hr0.iim_val *= 2;
+ reg_t hr1 = hr0;
+ hr1.iim_val += 1;
+ fprintf(ctx->out, " (hr%d.%c,hr%d.%c)", hr0.num, component[hr0.comp], hr1.num, component[hr1.comp]);
+ }
}
}
+static unsigned regidx(reg_t reg)
+{
+ return (4 * reg.num) + reg.comp;
+}
-static void print_reg_dst(struct disasm_ctx *ctx, reg_t reg, bool full, bool addr_rel)
+static reg_t idxreg(unsigned idx)
{
- print_reg(ctx, reg, full, false, false, false, false, false, addr_rel);
+ return (reg_t){
+ .comp = idx & 0x3,
+ .num = idx >> 2,
+ };
}
-static void print_reg_src(struct disasm_ctx *ctx, reg_t reg, bool full, bool r,
- bool c, bool im, bool neg, bool abs, bool addr_rel)
+static void print_reg_dst(struct disasm_ctx *ctx, reg_t reg, bool full, bool addr_rel)
{
- print_reg(ctx, reg, full, r, c, im, neg, abs, addr_rel);
+ reg = idxreg(regidx(reg) + ctx->repeatidx);
+ print_reg(ctx, reg, full, false, false, false, false, false, false, addr_rel);
}
/* TODO switch to using reginfo struct everywhere, since more readable
bool full;
bool r;
bool c;
+ bool f; /* src reg is interpreted as float, used for printing immediates */
bool im;
bool neg;
bool abs;
static void print_src(struct disasm_ctx *ctx, struct reginfo *info)
{
- print_reg_src(ctx, info->reg, info->full, info->r, info->c, info->im,
+ reg_t reg = info->reg;
+
+ if (info->r)
+ reg = idxreg(regidx(info->reg) + ctx->repeatidx);
+
+ print_reg(ctx, reg, info->full, info->f, info->r, info->c, info->im,
info->neg, info->abs, info->addr_rel);
}
static void print_instr_cat0(struct disasm_ctx *ctx, instr_t *instr)
{
+ static const struct {
+ const char *suffix;
+ int nsrc;
+ bool idx;
+ } brinfo[7] = {
+ [BRANCH_PLAIN] = { "r", 1, false },
+ [BRANCH_OR] = { "rao", 2, false },
+ [BRANCH_AND] = { "raa", 2, false },
+ [BRANCH_CONST] = { "rac", 0, true },
+ [BRANCH_ANY] = { "any", 1, false },
+ [BRANCH_ALL] = { "all", 1, false },
+ [BRANCH_X] = { "rax", 0, false },
+ };
instr_cat0_t *cat0 = &instr->cat0;
- switch (cat0->opc) {
+ switch (instr_opc(instr, ctx->gpu_id)) {
case OPC_KILL:
- case OPC_CONDEND:
- fprintf(ctx->out, " %sp0.%c", cat0->inv ? "!" : "",
- component[cat0->comp]);
+ case OPC_PREDT:
+ case OPC_PREDF:
+ fprintf(ctx->out, " %sp0.%c", cat0->inv0 ? "!" : "",
+ component[cat0->comp0]);
break;
- case OPC_BR:
- fprintf(ctx->out, " %sp0.%c, #%d", cat0->inv ? "!" : "",
- component[cat0->comp], cat0->a3xx.immed);
+ case OPC_B:
+ fprintf(ctx->out, "%s", brinfo[cat0->brtype].suffix);
+ if (brinfo[cat0->brtype].idx) {
+ fprintf(ctx->out, ".%u", cat0->idx);
+ }
+ if (brinfo[cat0->brtype].nsrc >= 1) {
+ fprintf(ctx->out, " %sp0.%c,", cat0->inv0 ? "!" : "",
+ component[cat0->comp0]);
+ }
+ if (brinfo[cat0->brtype].nsrc >= 2) {
+ fprintf(ctx->out, " %sp0.%c,", cat0->inv1 ? "!" : "",
+ component[cat0->comp1]);
+ }
+ fprintf(ctx->out, " #%d", cat0->a3xx.immed);
break;
case OPC_JUMP:
case OPC_CALL:
+ case OPC_BKT:
+ case OPC_GETONE:
+ case OPC_SHPS:
fprintf(ctx->out, " #%d", cat0->a3xx.immed);
break;
}
- if ((debug & PRINT_VERBOSE) && (cat0->dummy2|cat0->dummy3|cat0->dummy4))
- fprintf(ctx->out, "\t{0: %x,%x,%x}", cat0->dummy2, cat0->dummy3, cat0->dummy4);
+ if ((debug & PRINT_VERBOSE) && (cat0->dummy3|cat0->dummy4))
+ fprintf(ctx->out, "\t{0: %x,%x}", cat0->dummy3, cat0->dummy4);
}
static void print_instr_cat1(struct disasm_ctx *ctx, instr_t *instr)
* libllvm-a3xx...
*/
char type = cat1->src_rel_c ? 'c' : 'r';
+ const char *full = (type_size(cat1->src_type) == 32) ? "" : "h";
if (cat1->off < 0)
- fprintf(ctx->out, "%c<a0.x - %d>", type, -cat1->off);
+ fprintf(ctx->out, "%s%c<a0.x - %d>", full, type, -cat1->off);
else if (cat1->off > 0)
- fprintf(ctx->out, "%c<a0.x + %d>", type, cat1->off);
+ fprintf(ctx->out, "%s%c<a0.x + %d>", full, type, cat1->off);
else
- fprintf(ctx->out, "%c<a0.x>", type);
+ fprintf(ctx->out, "%s%c<a0.x>", full, type);
} else {
- print_reg_src(ctx, (reg_t)(cat1->src), type_size(cat1->src_type) == 32,
- cat1->src_r, cat1->src_c, cat1->src_im, false, false, false);
+ struct reginfo src = {
+ .reg = (reg_t)cat1->src,
+ .full = type_size(cat1->src_type) == 32,
+ .r = cat1->src_r,
+ .c = cat1->src_c,
+ .im = cat1->src_im,
+ };
+ print_src(ctx, &src);
}
if ((debug & PRINT_VERBOSE) && (cat1->must_be_0))
static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr)
{
instr_cat2_t *cat2 = &instr->cat2;
+ int opc = _OPC(2, cat2->opc);
static const char *cond[] = {
"lt",
"le",
"?6?",
};
- switch (_OPC(2, cat2->opc)) {
+ switch (opc) {
case OPC_CMPS_F:
case OPC_CMPS_U:
case OPC_CMPS_S:
print_reg_dst(ctx, (reg_t)(cat2->dst), cat2->full ^ cat2->dst_half, false);
fprintf(ctx->out, ", ");
- unsigned src1_r = cat2->repeat ? cat2->src1_r : 0;
+ struct reginfo src1 = {
+ .full = cat2->full,
+ .r = cat2->repeat ? cat2->src1_r : 0,
+ .f = is_cat2_float(opc),
+ .im = cat2->src1_im,
+ .abs = cat2->src1_abs,
+ .neg = cat2->src1_neg,
+ };
+
if (cat2->c1.src1_c) {
- print_reg_src(ctx, (reg_t)(cat2->c1.src1), cat2->full, src1_r,
- cat2->c1.src1_c, cat2->src1_im, cat2->src1_neg,
- cat2->src1_abs, false);
+ src1.reg = (reg_t)(cat2->c1.src1);
+ src1.c = true;
} else if (cat2->rel1.src1_rel) {
- print_reg_src(ctx, (reg_t)(cat2->rel1.src1), cat2->full, src1_r,
- cat2->rel1.src1_c, cat2->src1_im, cat2->src1_neg,
- cat2->src1_abs, cat2->rel1.src1_rel);
+ src1.reg = (reg_t)(cat2->rel1.src1);
+ src1.c = cat2->rel1.src1_c;
+ src1.addr_rel = true;
} else {
- print_reg_src(ctx, (reg_t)(cat2->src1), cat2->full, src1_r,
- false, cat2->src1_im, cat2->src1_neg,
- cat2->src1_abs, false);
+ src1.reg = (reg_t)(cat2->src1);
}
+ print_src(ctx, &src1);
- unsigned src2_r = cat2->repeat ? cat2->src2_r : 0;
- switch (_OPC(2, cat2->opc)) {
+ struct reginfo src2 = {
+ .r = cat2->repeat ? cat2->src2_r : 0,
+ .full = cat2->full,
+ .f = is_cat2_float(opc),
+ .abs = cat2->src2_abs,
+ .neg = cat2->src2_neg,
+ .im = cat2->src2_im,
+ };
+ switch (opc) {
case OPC_ABSNEG_F:
case OPC_ABSNEG_S:
case OPC_CLZ_B:
default:
fprintf(ctx->out, ", ");
if (cat2->c2.src2_c) {
- print_reg_src(ctx, (reg_t)(cat2->c2.src2), cat2->full, src2_r,
- cat2->c2.src2_c, cat2->src2_im, cat2->src2_neg,
- cat2->src2_abs, false);
+ src2.reg = (reg_t)(cat2->c2.src2);
+ src2.c = true;
} else if (cat2->rel2.src2_rel) {
- print_reg_src(ctx, (reg_t)(cat2->rel2.src2), cat2->full, src2_r,
- cat2->rel2.src2_c, cat2->src2_im, cat2->src2_neg,
- cat2->src2_abs, cat2->rel2.src2_rel);
+ src2.reg = (reg_t)(cat2->rel2.src2);
+ src2.c = cat2->rel2.src2_c;
+ src2.addr_rel = true;
} else {
- print_reg_src(ctx, (reg_t)(cat2->src2), cat2->full, src2_r,
- false, cat2->src2_im, cat2->src2_neg,
- cat2->src2_abs, false);
+ src2.reg = (reg_t)(cat2->src2);
}
+ print_src(ctx, &src2);
break;
}
}
fprintf(ctx->out, " ");
print_reg_dst(ctx, (reg_t)(cat3->dst), full ^ cat3->dst_half, false);
fprintf(ctx->out, ", ");
- unsigned src1_r = cat3->repeat ? cat3->src1_r : 0;
+
+ struct reginfo src1 = {
+ .r = cat3->repeat ? cat3->src1_r : 0,
+ .full = full,
+ .neg = cat3->src1_neg,
+ };
if (cat3->c1.src1_c) {
- print_reg_src(ctx, (reg_t)(cat3->c1.src1), full,
- src1_r, cat3->c1.src1_c, false, cat3->src1_neg,
- false, false);
+ src1.reg = (reg_t)(cat3->c1.src1);
+ src1.c = true;
} else if (cat3->rel1.src1_rel) {
- print_reg_src(ctx, (reg_t)(cat3->rel1.src1), full,
- src1_r, cat3->rel1.src1_c, false, cat3->src1_neg,
- false, cat3->rel1.src1_rel);
+ src1.reg = (reg_t)(cat3->rel1.src1);
+ src1.c = cat3->rel1.src1_c;
+ src1.addr_rel = true;
} else {
- print_reg_src(ctx, (reg_t)(cat3->src1), full,
- src1_r, false, false, cat3->src1_neg,
- false, false);
+ src1.reg = (reg_t)(cat3->src1);
}
+ print_src(ctx, &src1);
+
fprintf(ctx->out, ", ");
- unsigned src2_r = cat3->repeat ? cat3->src2_r : 0;
- print_reg_src(ctx, (reg_t)cat3->src2, full,
- src2_r, cat3->src2_c, false, cat3->src2_neg,
- false, false);
+ struct reginfo src2 = {
+ .reg = (reg_t)cat3->src2,
+ .full = full,
+ .r = cat3->repeat ? cat3->src2_r : 0,
+ .c = cat3->src2_c,
+ .neg = cat3->src2_neg,
+ };
+ print_src(ctx, &src2);
+
fprintf(ctx->out, ", ");
+ struct reginfo src3 = {
+ .r = cat3->src3_r,
+ .full = full,
+ .neg = cat3->src3_neg,
+ };
if (cat3->c2.src3_c) {
- print_reg_src(ctx, (reg_t)(cat3->c2.src3), full,
- cat3->src3_r, cat3->c2.src3_c, false, cat3->src3_neg,
- false, false);
+ src3.reg = (reg_t)(cat3->c2.src3);
+ src3.c = true;
} else if (cat3->rel2.src3_rel) {
- print_reg_src(ctx, (reg_t)(cat3->rel2.src3), full,
- cat3->src3_r, cat3->rel2.src3_c, false, cat3->src3_neg,
- false, cat3->rel2.src3_rel);
+ src3.reg = (reg_t)(cat3->rel2.src3);
+ src3.c = cat3->rel2.src3_c;
+ src3.addr_rel = true;
} else {
- print_reg_src(ctx, (reg_t)(cat3->src3), full,
- cat3->src3_r, false, false, cat3->src3_neg,
- false, false);
+ src3.reg = (reg_t)(cat3->src3);
}
+ print_src(ctx, &src3);
}
static void print_instr_cat4(struct disasm_ctx *ctx, instr_t *instr)
print_reg_dst(ctx, (reg_t)(cat4->dst), cat4->full ^ cat4->dst_half, false);
fprintf(ctx->out, ", ");
+ struct reginfo src = {
+ .r = cat4->src_r,
+ .im = cat4->src_im,
+ .full = cat4->full,
+ .neg = cat4->src_neg,
+ .abs = cat4->src_abs,
+ };
if (cat4->c.src_c) {
- print_reg_src(ctx, (reg_t)(cat4->c.src), cat4->full,
- cat4->src_r, cat4->c.src_c, cat4->src_im,
- cat4->src_neg, cat4->src_abs, false);
+ src.reg = (reg_t)(cat4->c.src);
+ src.c = true;
} else if (cat4->rel.src_rel) {
- print_reg_src(ctx, (reg_t)(cat4->rel.src), cat4->full,
- cat4->src_r, cat4->rel.src_c, cat4->src_im,
- cat4->src_neg, cat4->src_abs, cat4->rel.src_rel);
+ src.reg = (reg_t)(cat4->rel.src);
+ src.c = cat4->rel.src_c;
+ src.addr_rel = true;
} else {
- print_reg_src(ctx, (reg_t)(cat4->src), cat4->full,
- cat4->src_r, false, cat4->src_im,
- cat4->src_neg, cat4->src_abs, false);
+ src.reg = (reg_t)(cat4->src);
}
+ print_src(ctx, &src);
if ((debug & PRINT_VERBOSE) && (cat4->dummy1|cat4->dummy2))
fprintf(ctx->out, "\t{4: %x,%x}", cat4->dummy1, cat4->dummy2);
[opc_op(OPC_RGETPOS)] = { true, false, false, false, },
[opc_op(OPC_RGETINFO)] = { false, false, false, false, },
};
+
+ static const struct {
+ bool indirect;
+ bool bindless;
+ bool use_a1;
+ bool uniform;
+ } desc_features[8] = {
+ [CAT5_NONUNIFORM] = { .indirect = true, },
+ [CAT5_UNIFORM] = { .indirect = true, .uniform = true, },
+ [CAT5_BINDLESS_IMM] = { .bindless = true, },
+ [CAT5_BINDLESS_UNIFORM] = {
+ .bindless = true,
+ .indirect = true,
+ .uniform = true,
+ },
+ [CAT5_BINDLESS_NONUNIFORM] = {
+ .bindless = true,
+ .indirect = true,
+ },
+ [CAT5_BINDLESS_A1_IMM] = {
+ .bindless = true,
+ .use_a1 = true,
+ },
+ [CAT5_BINDLESS_A1_UNIFORM] = {
+ .bindless = true,
+ .indirect = true,
+ .uniform = true,
+ .use_a1 = true,
+ },
+ [CAT5_BINDLESS_A1_NONUNIFORM] = {
+ .bindless = true,
+ .indirect = true,
+ .use_a1 = true,
+ },
+ };
+
instr_cat5_t *cat5 = &instr->cat5;
int i;
+ bool desc_indirect =
+ cat5->is_s2en_bindless &&
+ desc_features[cat5->s2en_bindless.desc_mode].indirect;
+ bool bindless =
+ cat5->is_s2en_bindless &&
+ desc_features[cat5->s2en_bindless.desc_mode].bindless;
+ bool use_a1 =
+ cat5->is_s2en_bindless &&
+ desc_features[cat5->s2en_bindless.desc_mode].use_a1;
+ bool uniform =
+ cat5->is_s2en_bindless &&
+ desc_features[cat5->s2en_bindless.desc_mode].uniform;
+
if (cat5->is_3d) fprintf(ctx->out, ".3d");
if (cat5->is_a) fprintf(ctx->out, ".a");
if (cat5->is_o) fprintf(ctx->out, ".o");
if (cat5->is_p) fprintf(ctx->out, ".p");
if (cat5->is_s) fprintf(ctx->out, ".s");
- if (cat5->is_s2en) fprintf(ctx->out, ".s2en");
+ if (desc_indirect) fprintf(ctx->out, ".s2en");
+ if (uniform) fprintf(ctx->out, ".uniform");
+
+ if (bindless) {
+ unsigned base = (cat5->s2en_bindless.base_hi << 1) | cat5->base_lo;
+ fprintf(ctx->out, ".base%d", base);
+ }
fprintf(ctx->out, " ");
if (info[cat5->opc].src1) {
fprintf(ctx->out, ", ");
- print_reg_src(ctx, (reg_t)(cat5->src1), cat5->full, false, false, false,
- false, false, false);
+ struct reginfo src = { .reg = (reg_t)(cat5->src1), .full = cat5->full };
+ print_src(ctx, &src);
}
- if (cat5->is_s2en) {
- if (cat5->is_o || info[cat5->opc].src2) {
- fprintf(ctx->out, ", ");
- print_reg_src(ctx, (reg_t)(cat5->s2en.src2), cat5->full,
- false, false, false, false, false, false);
- }
+ if (cat5->is_o || info[cat5->opc].src2) {
fprintf(ctx->out, ", ");
- print_reg_src(ctx, (reg_t)(cat5->s2en.src3), false, false, false, false,
- false, false, false);
- } else {
- if (cat5->is_o || info[cat5->opc].src2) {
- fprintf(ctx->out, ", ");
- print_reg_src(ctx, (reg_t)(cat5->norm.src2), cat5->full,
- false, false, false, false, false, false);
+ struct reginfo src = { .reg = (reg_t)(cat5->src2), .full = cat5->full };
+ print_src(ctx, &src);
+ }
+ if (cat5->is_s2en_bindless) {
+ if (!desc_indirect) {
+ if (info[cat5->opc].samp) {
+ if (use_a1)
+ fprintf(ctx->out, ", s#%d", cat5->s2en_bindless.src3);
+ else
+ fprintf(ctx->out, ", s#%d", cat5->s2en_bindless.src3 & 0xf);
+ }
+
+ if (info[cat5->opc].tex && !use_a1) {
+ fprintf(ctx->out, ", t#%d", cat5->s2en_bindless.src3 >> 4);
+ }
}
+ } else {
if (info[cat5->opc].samp)
fprintf(ctx->out, ", s#%d", cat5->norm.samp);
if (info[cat5->opc].tex)
fprintf(ctx->out, ", t#%d", cat5->norm.tex);
}
+ if (desc_indirect) {
+ fprintf(ctx->out, ", ");
+ struct reginfo src = { .reg = (reg_t)(cat5->s2en_bindless.src3), .full = bindless };
+ print_src(ctx, &src);
+ }
+
+ if (use_a1)
+ fprintf(ctx->out, ", a1.x");
+
if (debug & PRINT_VERBOSE) {
- if (cat5->is_s2en) {
- if ((debug & PRINT_VERBOSE) && (cat5->s2en.dummy1|cat5->s2en.dummy2|cat5->dummy2))
- fprintf(ctx->out, "\t{5: %x,%x,%x}", cat5->s2en.dummy1, cat5->s2en.dummy2, cat5->dummy2);
+ if (cat5->is_s2en_bindless) {
+ if ((debug & PRINT_VERBOSE) && cat5->s2en_bindless.dummy1)
+ fprintf(ctx->out, "\t{5: %x}", cat5->s2en_bindless.dummy1);
} else {
- if ((debug & PRINT_VERBOSE) && (cat5->norm.dummy1|cat5->dummy2))
- fprintf(ctx->out, "\t{5: %x,%x}", cat5->norm.dummy1, cat5->dummy2);
+ if ((debug & PRINT_VERBOSE) && cat5->norm.dummy1)
+ fprintf(ctx->out, "\t{5: %x}", cat5->norm.dummy1);
}
}
}
instr_cat6_t *cat6 = &instr->cat6;
char sd = 0, ss = 0; /* dst/src address space */
bool nodst = false;
- struct reginfo dst, src1, src2;
+ struct reginfo dst, src1, src2, ssbo;
int src1off = 0, dstoff = 0;
memset(&dst, 0, sizeof(dst));
memset(&src1, 0, sizeof(src1));
memset(&src2, 0, sizeof(src2));
+ memset(&ssbo, 0, sizeof(ssbo));
switch (_OPC(6, cat6->opc)) {
case OPC_RESINFO:
case OPC_STP:
case OPC_STLW:
case OPC_STIB:
- dst.full = true;
+ dst.full = type_size(cat6->type) == 32;
src1.full = type_size(cat6->type) == 32;
src2.full = type_size(cat6->type) == 32;
break;
print_src(ctx, &src3); /* 64b byte offset.. */
if (debug & PRINT_VERBOSE) {
- fprintf(ctx->out, " (pad0=%x, pad3=%x, mustbe0=%x)", cat6->ldgb.pad0,
- cat6->ldgb.pad3, cat6->ldgb.mustbe0);
+ fprintf(ctx->out, " (pad0=%x, mustbe0=%x)", cat6->ldgb.pad0,
+ cat6->ldgb.mustbe0);
}
} else { /* ss == 'l' */
fprintf(ctx->out, "l[");
print_src(ctx, &src2); /* value */
if (debug & PRINT_VERBOSE) {
- fprintf(ctx->out, " (src3=%x, pad0=%x, pad3=%x, mustbe0=%x)",
+ fprintf(ctx->out, " (src3=%x, pad0=%x, src_ssbo_im=%x, mustbe0=%x)",
cat6->ldgb.src3, cat6->ldgb.pad0,
- cat6->ldgb.pad3, cat6->ldgb.mustbe0);
+ cat6->ldgb.src_ssbo_im, cat6->ldgb.mustbe0);
}
}
return;
} else if (_OPC(6, cat6->opc) == OPC_RESINFO) {
dst.reg = (reg_t)(cat6->ldgb.dst);
+ ssbo.reg = (reg_t)(cat6->ldgb.src_ssbo);
+ ssbo.im = cat6->ldgb.src_ssbo_im;
print_src(ctx, &dst);
fprintf(ctx->out, ", ");
- fprintf(ctx->out, "g[%u]", cat6->ldgb.src_ssbo);
+
+ fprintf(ctx->out, "g[");
+ print_src(ctx, &ssbo);
+ fprintf(ctx->out, "]");
return;
} else if (_OPC(6, cat6->opc) == OPC_LDGB) {
src1.im = cat6->ldgb.src1_im;
src2.reg = (reg_t)(cat6->ldgb.src2);
src2.im = cat6->ldgb.src2_im;
+ ssbo.reg = (reg_t)(cat6->ldgb.src_ssbo);
+ ssbo.im = cat6->ldgb.src_ssbo_im;
dst.reg = (reg_t)(cat6->ldgb.dst);
print_src(ctx, &dst);
fprintf(ctx->out, ", ");
- fprintf(ctx->out, "g[%u], ", cat6->ldgb.src_ssbo);
+
+ fprintf(ctx->out, "g[");
+ print_src(ctx, &ssbo);
+ fprintf(ctx->out, "], ");
+
print_src(ctx, &src1);
fprintf(ctx->out, ", ");
print_src(ctx, &src2);
if (debug & PRINT_VERBOSE)
- fprintf(ctx->out, " (pad0=%x, pad3=%x, mustbe0=%x)", cat6->ldgb.pad0, cat6->ldgb.pad3, cat6->ldgb.mustbe0);
+ fprintf(ctx->out, " (pad0=%x, ssbo_im=%x, mustbe0=%x)", cat6->ldgb.pad0, cat6->ldgb.src_ssbo_im, cat6->ldgb.mustbe0);
return;
} else if (_OPC(6, cat6->opc) == OPC_LDG && cat6->a.src1_im && cat6->a.src2_im) {
/* note: dst might actually be a src (ie. address to store to) */
print_src(ctx, &dst);
if (cat6->dst_off && cat6->g) {
- struct reginfo dstoff_reg = {};
- dstoff_reg.reg = (reg_t) cat6->c.off;
- dstoff_reg.full = true;
+ struct reginfo dstoff_reg = {
+ .reg = (reg_t) cat6->c.off,
+ .full = true
+ };
fprintf(ctx->out, "+");
print_src(ctx, &dstoff_reg);
- } else if (dstoff) {
+ } else if (dstoff)
fprintf(ctx->out, "%+d", dstoff);
- }
if (sd)
fprintf(ctx->out, "]");
fprintf(ctx->out, ", ");
static void print_instr_cat6_a6xx(struct disasm_ctx *ctx, instr_t *instr)
{
instr_cat6_a6xx_t *cat6 = &instr->cat6_a6xx;
- struct reginfo src1, src2;
- bool has_dest = _OPC(6, cat6->opc) == OPC_LDIB;
- char ss = 0;
+ struct reginfo src1, src2, ssbo;
+ uint32_t opc = _OPC(6, cat6->opc);
+ bool uses_type = opc != OPC_LDC;
- memset(&src1, 0, sizeof(src1));
- memset(&src2, 0, sizeof(src2));
+ static const struct {
+ bool indirect;
+ bool bindless;
+ const char *name;
+ } desc_features[8] = {
+ [CAT6_IMM] = {
+ .name = "imm"
+ },
+ [CAT6_UNIFORM] = {
+ .indirect = true,
+ .name = "uniform"
+ },
+ [CAT6_NONUNIFORM] = {
+ .indirect = true,
+ .name = "nonuniform"
+ },
+ [CAT6_BINDLESS_IMM] = {
+ .bindless = true,
+ .name = "imm"
+ },
+ [CAT6_BINDLESS_UNIFORM] = {
+ .bindless = true,
+ .indirect = true,
+ .name = "uniform"
+ },
+ [CAT6_BINDLESS_NONUNIFORM] = {
+ .bindless = true,
+ .indirect = true,
+ .name = "nonuniform"
+ },
+ };
- fprintf(ctx->out, ".%s", cat6->typed ? "typed" : "untyped");
- fprintf(ctx->out, ".%dd", cat6->d + 1);
- fprintf(ctx->out, ".%s", type[cat6->type]);
- fprintf(ctx->out, ".%u ", cat6->type_size + 1);
+ bool indirect_ssbo = desc_features[cat6->desc_mode].indirect;
+ bool bindless = desc_features[cat6->desc_mode].bindless;
+ bool type_full = cat6->type != TYPE_U16;
- if (has_dest) {
- src2.reg = (reg_t)(cat6->src2);
- src2.full = true; // XXX
- print_src(ctx, &src2);
- fprintf(ctx->out, ", ");
+ memset(&src1, 0, sizeof(src1));
+ memset(&src2, 0, sizeof(src2));
+ memset(&ssbo, 0, sizeof(ssbo));
+
+ if (uses_type) {
+ fprintf(ctx->out, ".%s", cat6->typed ? "typed" : "untyped");
+ fprintf(ctx->out, ".%dd", cat6->d + 1);
+ fprintf(ctx->out, ".%s", type[cat6->type]);
+ } else {
+ fprintf(ctx->out, ".offset%d", cat6->d);
}
+ fprintf(ctx->out, ".%u", cat6->type_size + 1);
- /* NOTE: blob seems to use old encoding for ldl/stl (local memory) */
- ss = 'g';
+ fprintf(ctx->out, ".%s", desc_features[cat6->desc_mode].name);
+ if (bindless)
+ fprintf(ctx->out, ".base%d", cat6->base);
+ fprintf(ctx->out, " ");
- fprintf(ctx->out, "%c[%u", ss, cat6->ssbo);
- fprintf(ctx->out, "] + ");
- src1.reg = (reg_t)(cat6->src1);
- src1.full = true; // XXX
- print_src(ctx, &src1);
+ src2.reg = (reg_t)(cat6->src2);
+ src2.full = type_full;
+ print_src(ctx, &src2);
+ fprintf(ctx->out, ", ");
- if (!has_dest) {
+ if (opc != OPC_RESINFO) {
+ src1.reg = (reg_t)(cat6->src1);
+ src1.full = true; // XXX
+ print_src(ctx, &src1);
fprintf(ctx->out, ", ");
-
- src2.reg = (reg_t)(cat6->src2);
- src2.full = true; // XXX
- print_src(ctx, &src2);
}
+ ssbo.reg = (reg_t)(cat6->ssbo);
+ ssbo.im = !indirect_ssbo;
+ ssbo.full = true;
+ print_src(ctx, &ssbo);
+
if (debug & PRINT_VERBOSE) {
- fprintf(ctx->out, " (pad1=%x, pad2=%x, pad3=%x, pad4=%x)", cat6->pad1,
- cat6->pad2, cat6->pad3, cat6->pad4);
+ fprintf(ctx->out, " (pad1=%x, pad2=%x, pad3=%x, pad4=%x, pad5=%x)",
+ cat6->pad1, cat6->pad2, cat6->pad3, cat6->pad4, cat6->pad5);
}
}
#define OPC(cat, opc, name) [(opc)] = { (cat), (opc), #name, print_instr_cat##cat }
/* category 0: */
OPC(0, OPC_NOP, nop),
- OPC(0, OPC_BR, br),
+ OPC(0, OPC_B, b),
OPC(0, OPC_JUMP, jump),
OPC(0, OPC_CALL, call),
OPC(0, OPC_RET, ret),
OPC(0, OPC_CHMASK, chmask),
OPC(0, OPC_CHSH, chsh),
OPC(0, OPC_FLOW_REV, flow_rev),
- OPC(0, OPC_CONDEND, condend),
- OPC(0, OPC_ENDPATCH, endpatch),
+ OPC(0, OPC_PREDT, predt),
+ OPC(0, OPC_PREDF, predf),
+ OPC(0, OPC_PREDE, prede),
+ OPC(0, OPC_BKT, bkt),
+ OPC(0, OPC_STKS, stks),
+ OPC(0, OPC_STKR, stkr),
+ OPC(0, OPC_XSET, xset),
+ OPC(0, OPC_XCLR, xclr),
+ OPC(0, OPC_GETONE, getone),
+ OPC(0, OPC_DBG, dbg),
+ OPC(0, OPC_SHPS, shps),
+ OPC(0, OPC_SHPE, shpe),
/* category 1: */
OPC(1, OPC_MOV, ),
OPC(4, OPC_SIN, sin),
OPC(4, OPC_COS, cos),
OPC(4, OPC_SQRT, sqrt),
+ OPC(4, OPC_HRSQ, hrsq),
+ OPC(4, OPC_HLOG2, hlog2),
+ OPC(4, OPC_HEXP2, hexp2),
/* category 5: */
OPC(5, OPC_ISAM, isam),
return opcs[instr->opc].name;
}
+static void print_single_instr(struct disasm_ctx *ctx, instr_t *instr)
+{
+ const char *name = GETINFO(instr)->name;
+ uint32_t opc = instr_opc(instr, ctx->gpu_id);
+
+ if (name) {
+ fprintf(ctx->out, "%s", name);
+ GETINFO(instr)->print(ctx, instr);
+ } else {
+ fprintf(ctx->out, "unknown(%d,%d)", instr->opc_cat, opc);
+
+ switch (instr->opc_cat) {
+ case 0: print_instr_cat0(ctx, instr); break;
+ case 1: print_instr_cat1(ctx, instr); break;
+ case 2: print_instr_cat2(ctx, instr); break;
+ case 3: print_instr_cat3(ctx, instr); break;
+ case 4: print_instr_cat4(ctx, instr); break;
+ case 5: print_instr_cat5(ctx, instr); break;
+ case 6: print_instr_cat6(ctx, instr); break;
+ case 7: print_instr_cat7(ctx, instr); break;
+ }
+ }
+}
+
static bool print_instr(struct disasm_ctx *ctx, uint32_t *dwords, int n)
{
instr_t *instr = (instr_t *)dwords;
uint32_t opc = instr_opc(instr, ctx->gpu_id);
- const char *name;
+ unsigned nop = 0;
+ unsigned cycles = ctx->instructions;
- if (debug & PRINT_VERBOSE)
- fprintf(ctx->out, "%s%04d[%08xx_%08xx] ", levels[ctx->level], n, dwords[1], dwords[0]);
+ if (debug & PRINT_VERBOSE) {
+ fprintf(ctx->out, "%s%04d:%04d[%08xx_%08xx] ", levels[ctx->level],
+ n, cycles++, dwords[1], dwords[0]);
+ }
/* NOTE: order flags are printed is a bit fugly.. but for now I
* try to match the order in llvm-a3xx disassembler for easy
*/
ctx->repeat = instr_repeat(instr);
+ ctx->instructions += 1 + ctx->repeat;
- if (instr->sync)
+ if (instr->sync) {
fprintf(ctx->out, "(sy)");
- if (instr->ss && ((instr->opc_cat <= 4) || (instr->opc_cat == 7)))
+ }
+ if (instr->ss && ((instr->opc_cat <= 4) || (instr->opc_cat == 7))) {
fprintf(ctx->out, "(ss)");
+ }
if (instr->jmp_tgt)
fprintf(ctx->out, "(jp)");
+ if ((instr->opc_cat == 0) && instr->cat0.eq)
+ fprintf(ctx->out, "(eq)");
if (instr_sat(instr))
fprintf(ctx->out, "(sat)");
- if (ctx->repeat) {
+ if (ctx->repeat)
fprintf(ctx->out, "(rpt%d)", ctx->repeat);
- } else if ((instr->opc_cat == 2) && (instr->cat2.src1_r || instr->cat2.src2_r)) {
- unsigned nop = (instr->cat2.src2_r * 2) + instr->cat2.src1_r;
- fprintf(ctx->out, "(nop%d)", nop);
- } else if ((instr->opc_cat == 3) && (instr->cat3.src1_r || instr->cat3.src2_r)) {
- unsigned nop = (instr->cat3.src2_r * 2) + instr->cat3.src1_r;
- fprintf(ctx->out, "(nop%d)", nop);
- }
+ else if ((instr->opc_cat == 2) && (instr->cat2.src1_r || instr->cat2.src2_r))
+ nop = (instr->cat2.src2_r * 2) + instr->cat2.src1_r;
+ else if ((instr->opc_cat == 3) && (instr->cat3.src1_r || instr->cat3.src2_r))
+ nop = (instr->cat3.src2_r * 2) + instr->cat3.src1_r;
+ ctx->instructions += nop;
+ if (nop)
+ fprintf(ctx->out, "(nop%d) ", nop);
+
if (instr->ul && ((2 <= instr->opc_cat) && (instr->opc_cat <= 4)))
fprintf(ctx->out, "(ul)");
- name = GETINFO(instr)->name;
+ print_single_instr(ctx, instr);
+ fprintf(ctx->out, "\n");
- if (name) {
- fprintf(ctx->out, "%s", name);
- GETINFO(instr)->print(ctx, instr);
- } else {
- fprintf(ctx->out, "unknown(%d,%d)", instr->opc_cat, opc);
+ if ((instr->opc_cat <= 4) && (debug & EXPAND_REPEAT)) {
+ int i;
+ for (i = 0; i < nop; i++) {
+ if (debug & PRINT_VERBOSE) {
+ fprintf(ctx->out, "%s%04d:%04d[ ] ",
+ levels[ctx->level], n, cycles++);
+ }
+ fprintf(ctx->out, "nop\n");
+ }
+ for (i = 0; i < ctx->repeat; i++) {
+ ctx->repeatidx = i + 1;
+ if (debug & PRINT_VERBOSE) {
+ fprintf(ctx->out, "%s%04d:%04d[ ] ",
+ levels[ctx->level], n, cycles++);
+ }
+ print_single_instr(ctx, instr);
+ fprintf(ctx->out, "\n");
+ }
+ ctx->repeatidx = 0;
}
- fprintf(ctx->out, "\n");
-
return (instr->opc_cat == 0) && (opc == OPC_END);
}
{
struct disasm_ctx ctx;
int i;
+ int nop_count = 0;
assert((sizedwords % 2) == 0);
ctx.level = level;
ctx.gpu_id = gpu_id;
- for (i = 0; i < sizedwords; i += 2)
+ for (i = 0; i < sizedwords; i += 2) {
print_instr(&ctx, &dwords[i], i/2);
+ if (dwords[i] == 0 && dwords[i + 1] == 0)
+ nop_count++;
+ else
+ nop_count = 0;
+ if (nop_count > 3)
+ break;
+ }
return 0;
}