ir3: Support assembling & disassembling getspid/getwid

These aren't useful yet in the driver, but were useful for
reverse-engineering how private memory works.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7386>
This commit is contained in:
Connor Abbott 2020-10-23 14:07:04 +02:00
parent 2cee8642ca
commit e7471ce776
5 changed files with 86 additions and 53 deletions

View file

@ -1185,6 +1185,7 @@ 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, ssbo;
uint32_t opc = _OPC(6, cat6->opc);
bool is_id = opc == OPC_GETSPID || opc == OPC_GETWID;
bool uses_type = opc != OPC_LDC;
static const struct {
@ -1229,35 +1230,44 @@ static void print_instr_cat6_a6xx(struct disasm_ctx *ctx, instr_t *instr)
memset(&ssbo, 0, sizeof(ssbo));
if (uses_type) {
fprintf(ctx->out, ".%s", cat6->typed ? "typed" : "untyped");
fprintf(ctx->out, ".%dd", cat6->d + 1);
if (!is_id) {
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);
fprintf(ctx->out, ".%s", desc_features[cat6->desc_mode].name);
if (bindless)
fprintf(ctx->out, ".base%d", cat6->base);
if (!is_id) {
fprintf(ctx->out, ".%u", cat6->type_size + 1);
fprintf(ctx->out, ".%s", desc_features[cat6->desc_mode].name);
if (bindless)
fprintf(ctx->out, ".base%d", cat6->base);
}
fprintf(ctx->out, " ");
src2.reg = (reg_t)(cat6->src2);
src2.full = type_full;
print_src(ctx, &src2);
fprintf(ctx->out, ", ");
if (opc != OPC_RESINFO) {
src1.reg = (reg_t)(cat6->src1);
src1.full = true; // XXX
print_src(ctx, &src1);
if (!is_id) {
fprintf(ctx->out, ", ");
}
ssbo.reg = (reg_t)(cat6->ssbo);
ssbo.im = !indirect_ssbo;
ssbo.full = true;
print_src(ctx, &ssbo);
if (opc != OPC_RESINFO) {
src1.reg = (reg_t)(cat6->src1);
src1.full = true; // XXX
print_src(ctx, &src1);
fprintf(ctx->out, ", ");
}
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, pad5=%x)",

View file

@ -537,53 +537,57 @@ static int emit_cat5(struct ir3_instruction *instr, void *ptr,
static int emit_cat6_a6xx(struct ir3_instruction *instr, void *ptr,
struct ir3_info *info)
{
struct ir3_register *ssbo;
instr_cat6_a6xx_t *cat6 = ptr;
ssbo = instr->regs[1];
cat6->type = instr->cat6.type;
cat6->d = instr->cat6.d - (instr->opc == OPC_LDC ? 0 : 1);
cat6->typed = instr->cat6.typed;
cat6->type_size = instr->cat6.iim_val - 1;
cat6->opc = instr->opc;
cat6->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
cat6->sync = !!(instr->flags & IR3_INSTR_SY);
cat6->opc_cat = 6;
cat6->ssbo = reg(ssbo, info, instr->repeat, IR3_REG_IMMED);
/* For unused sources in an opcode, initialize contents with the ir3 dest
* reg
*/
switch (instr->opc) {
case OPC_RESINFO:
cat6->src1 = reg(instr->regs[0], info, instr->repeat, 0);
if (instr->opc == OPC_GETWID || instr->opc == OPC_GETSPID) {
cat6->src2 = reg(instr->regs[0], info, instr->repeat, 0);
break;
case OPC_LDC:
case OPC_LDIB:
cat6->src1 = reg(instr->regs[2], info, instr->repeat, 0);
cat6->src2 = reg(instr->regs[0], info, instr->repeat, 0);
break;
default:
cat6->src1 = reg(instr->regs[2], info, instr->repeat, 0);
cat6->src2 = reg(instr->regs[3], info, instr->repeat, 0);
break;
}
if (instr->flags & IR3_INSTR_B) {
if (ssbo->flags & IR3_REG_IMMED) {
cat6->desc_mode = CAT6_BINDLESS_IMM;
} else {
cat6->desc_mode = CAT6_BINDLESS_UNIFORM;
}
cat6->base = instr->cat6.base;
cat6->src1 = cat6->ssbo = 0;
cat6->d = cat6->typed = cat6->type_size = 0;
} else {
if (ssbo->flags & IR3_REG_IMMED)
cat6->desc_mode = CAT6_IMM;
else
cat6->desc_mode = CAT6_UNIFORM;
struct ir3_register *ssbo = instr->regs[1];
cat6->d = instr->cat6.d - (instr->opc == OPC_LDC ? 0 : 1);
cat6->typed = instr->cat6.typed;
cat6->type_size = instr->cat6.iim_val - 1;
cat6->ssbo = reg(ssbo, info, instr->repeat, IR3_REG_IMMED);
/* For unused sources in an opcode, initialize contents with the ir3
* dest reg
*/
switch (instr->opc) {
case OPC_RESINFO:
cat6->src1 = reg(instr->regs[0], info, instr->repeat, 0);
cat6->src2 = reg(instr->regs[0], info, instr->repeat, 0);
break;
case OPC_LDC:
case OPC_LDIB:
cat6->src1 = reg(instr->regs[2], info, instr->repeat, 0);
cat6->src2 = reg(instr->regs[0], info, instr->repeat, 0);
break;
default:
cat6->src1 = reg(instr->regs[2], info, instr->repeat, 0);
cat6->src2 = reg(instr->regs[3], info, instr->repeat, 0);
break;
}
if (instr->flags & IR3_INSTR_B) {
if (ssbo->flags & IR3_REG_IMMED) {
cat6->desc_mode = CAT6_BINDLESS_IMM;
} else {
cat6->desc_mode = CAT6_BINDLESS_UNIFORM;
}
cat6->base = instr->cat6.base;
} else {
if (ssbo->flags & IR3_REG_IMMED)
cat6->desc_mode = CAT6_IMM;
else
cat6->desc_mode = CAT6_UNIFORM;
}
}
switch (instr->opc) {
@ -614,6 +618,8 @@ static int emit_cat6_a6xx(struct ir3_instruction *instr, void *ptr,
cat6->pad5 = 0x2;
break;
case OPC_LDC:
case OPC_GETWID:
case OPC_GETSPID:
cat6->pad1 = 0x0;
cat6->pad3 = 0x4;
cat6->pad5 = 0x2;
@ -658,6 +664,8 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr,
case OPC_LDIB:
case OPC_LDC:
case OPC_RESINFO:
case OPC_GETSPID:
case OPC_GETWID:
return emit_cat6_a6xx(instr, ptr, info);
default:
break;

View file

@ -264,6 +264,8 @@ static int parse_reg(const char *str)
"stib" return TOKEN(T_OP_STIB);
"ldc" return TOKEN(T_OP_LDC);
"ldlv" return TOKEN(T_OP_LDLV);
"getspid" return TOKEN(T_OP_GETSPID);
"getwid" return TOKEN(T_OP_GETWID);
"f16" return TOKEN(T_TYPE_F16);
"f32" return TOKEN(T_TYPE_F32);

View file

@ -439,6 +439,8 @@ static void print_token(FILE *file, int type, YYSTYPE value)
%token <tok> T_OP_STIB
%token <tok> T_OP_LDC
%token <tok> T_OP_LDLV
%token <tok> T_OP_GETSPID
%token <tok> T_OP_GETWID
/* type qualifiers: */
%token <tok> T_TYPE_F16
@ -811,6 +813,12 @@ cat6_atomic: T_OP_ATOMIC_ADD { new_instr(OPC_ATOMIC_ADD); } cat6_at
| T_OP_ATOMIC_OR { new_instr(OPC_ATOMIC_OR); } cat6_atomic_l_g cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' cat6_immed
| T_OP_ATOMIC_XOR { new_instr(OPC_ATOMIC_XOR); } cat6_atomic_l_g cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' cat6_immed
cat6_id_opc:
T_OP_GETSPID { new_instr(OPC_GETSPID); }
| T_OP_GETWID { new_instr(OPC_GETWID); }
cat6_id: cat6_id_opc cat6_type dst_reg
cat6_todo: T_OP_G2L { new_instr(OPC_G2L); }
| T_OP_L2G { new_instr(OPC_L2G); }
| T_OP_RESFMT { new_instr(OPC_RESFMT); }
@ -824,6 +832,7 @@ cat6_instr: cat6_load
| cat6_storeib
| cat6_prefetch
| cat6_atomic
| cat6_id
| cat6_todo
reg: T_REGISTER { $$ = new_reg($1, 0); }

View file

@ -192,6 +192,10 @@ static const struct test {
INSTR_6XX(a0c81f07_0100000b, "sam.s2en (f32)(xyzw)r1.w, r1.y, hr2.x"), /* sam.s2en.mode0 (f32)(xyzw)r1.w, r1.y, hr2.x */
/* dEQP-GLES31.functional.shaders.opaque_type_indexing.sampler.dynamically_uniform.fragment.sampler2d */
INSTR_6XX(a0c81f07_8100000b, "sam.s2en.uniform (f32)(xyzw)r1.w, r1.y, hr2.x"), /* sam.s2en.mode4 (f32)(xyzw)r1.w, r1.y, hr2.x */
/* Custom test since we've never seen the blob emit these. */
INSTR_6XX(c0260004_00490000, "getspid.u32 r1.x"),
INSTR_6XX(c0260005_00494000, "getwid.u32 r1.y"),
};
static void