diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/freedreno/ir3/disasm-a3xx.c | 94 | ||||
-rw-r--r-- | src/freedreno/ir3/instr-a3xx.h | 59 | ||||
-rw-r--r-- | src/freedreno/ir3/ir3_shader.c | 2 | ||||
-rw-r--r-- | src/gallium/drivers/freedreno/disasm.h | 2 |
4 files changed, 132 insertions, 25 deletions
diff --git a/src/freedreno/ir3/disasm-a3xx.c b/src/freedreno/ir3/disasm-a3xx.c index 4cf45ce9227..9c0432c67ab 100644 --- a/src/freedreno/ir3/disasm-a3xx.c +++ b/src/freedreno/ir3/disasm-a3xx.c @@ -77,6 +77,7 @@ static const char *type[] = { struct disasm_ctx { FILE *out; int level; + unsigned gpu_id; /* current instruction repeat flag: */ unsigned repeat; @@ -117,7 +118,7 @@ static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, bool r, } 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 & 0x3f, component[reg.comp]); + fprintf(ctx->out, "%s%c%d.%c", full ? "" : "h", type, reg.num, component[reg.comp]); } } @@ -271,20 +272,22 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr) 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; if (cat2->c1.src1_c) { - print_reg_src(ctx, (reg_t)(cat2->c1.src1), cat2->full, cat2->src1_r, + 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); } else if (cat2->rel1.src1_rel) { - print_reg_src(ctx, (reg_t)(cat2->rel1.src1), cat2->full, cat2->src1_r, + 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); } else { - print_reg_src(ctx, (reg_t)(cat2->src1), cat2->full, cat2->src1_r, + print_reg_src(ctx, (reg_t)(cat2->src1), cat2->full, src1_r, false, cat2->src1_im, cat2->src1_neg, cat2->src1_abs, false); } + unsigned src2_r = cat2->repeat ? cat2->src2_r : 0; switch (_OPC(2, cat2->opc)) { case OPC_ABSNEG_F: case OPC_ABSNEG_S: @@ -305,15 +308,15 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr) default: fprintf(ctx->out, ", "); if (cat2->c2.src2_c) { - print_reg_src(ctx, (reg_t)(cat2->c2.src2), cat2->full, cat2->src2_r, + 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); } else if (cat2->rel2.src2_rel) { - print_reg_src(ctx, (reg_t)(cat2->rel2.src2), cat2->full, cat2->src2_r, + 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); } else { - print_reg_src(ctx, (reg_t)(cat2->src2), cat2->full, cat2->src2_r, + print_reg_src(ctx, (reg_t)(cat2->src2), cat2->full, src2_r, false, cat2->src2_im, cat2->src2_neg, cat2->src2_abs, false); } @@ -329,22 +332,24 @@ static void print_instr_cat3(struct disasm_ctx *ctx, instr_t *instr) 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; if (cat3->c1.src1_c) { print_reg_src(ctx, (reg_t)(cat3->c1.src1), full, - cat3->src1_r, cat3->c1.src1_c, false, cat3->src1_neg, + src1_r, cat3->c1.src1_c, false, cat3->src1_neg, false, false); } else if (cat3->rel1.src1_rel) { print_reg_src(ctx, (reg_t)(cat3->rel1.src1), full, - cat3->src1_r, cat3->rel1.src1_c, false, cat3->src1_neg, + src1_r, cat3->rel1.src1_c, false, cat3->src1_neg, false, cat3->rel1.src1_rel); } else { print_reg_src(ctx, (reg_t)(cat3->src1), full, - cat3->src1_r, false, false, cat3->src1_neg, + src1_r, false, false, cat3->src1_neg, false, false); } fprintf(ctx->out, ", "); + unsigned src2_r = cat3->repeat ? cat3->src2_r : 0; print_reg_src(ctx, (reg_t)cat3->src2, full, - cat3->src2_r, cat3->src2_c, false, cat3->src2_neg, + src2_r, cat3->src2_c, false, cat3->src2_neg, false, false); fprintf(ctx->out, ", "); if (cat3->c2.src3_c) { @@ -487,7 +492,7 @@ static void print_instr_cat5(struct disasm_ctx *ctx, instr_t *instr) } } -static void print_instr_cat6(struct disasm_ctx *ctx, instr_t *instr) +static void print_instr_cat6_a3xx(struct disasm_ctx *ctx, instr_t *instr) { instr_cat6_t *cat6 = &instr->cat6; char sd = 0, ss = 0; /* dst/src address space */ @@ -779,6 +784,55 @@ static void print_instr_cat6(struct disasm_ctx *ctx, instr_t *instr) } } +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; + char ss = 0; + + memset(&src1, 0, sizeof(src1)); + memset(&src2, 0, sizeof(src2)); + + 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); + + /* NOTE: blob seems to use old encoding for ldl/stl (local memory) */ + ss = 'g'; + + 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); + fprintf(ctx->out, ", "); + + src2.reg = (reg_t)(cat6->src2); + src2.full = true; // XXX + print_src(ctx, &src2); + + if (debug & PRINT_VERBOSE) { + fprintf(ctx->out, " (pad1=%x, pad2=%x, pad3=%x, pad4=%x)", cat6->pad1, + cat6->pad2, cat6->pad3, cat6->pad4); + } +} + +static void print_instr_cat6(struct disasm_ctx *ctx, instr_t *instr) +{ + // TODO not sure if this is the best way to figure + // out if new vs old encoding, but it kinda seems + // to work: + if ((ctx->gpu_id >= 600) && (instr->cat6.opc == 0)) { + print_instr_cat6_a6xx(ctx, instr); + if (debug & PRINT_VERBOSE) + fprintf(ctx->out, " NEW"); + } else { + print_instr_cat6_a3xx(ctx, instr); + if (debug & PRINT_VERBOSE) + fprintf(ctx->out, " LEGACY"); + } +} static void print_instr_cat7(struct disasm_ctx *ctx, instr_t *instr) { instr_cat7_t *cat7 = &instr->cat7; @@ -967,7 +1021,7 @@ static const struct opc_info { #undef OPC }; -#define GETINFO(instr) (&(opcs[((instr)->opc_cat << NOPC_BITS) | instr_opc(instr)])) +#define GETINFO(instr) (&(opcs[((instr)->opc_cat << NOPC_BITS) | instr_opc(instr, ctx->gpu_id)])) // XXX hack.. probably should move this table somewhere common: #include "ir3.h" @@ -980,7 +1034,7 @@ const char *ir3_instr_name(struct ir3_instruction *instr) 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); + uint32_t opc = instr_opc(instr, ctx->gpu_id); const char *name; if (debug & PRINT_VERBOSE) @@ -1001,8 +1055,15 @@ static bool print_instr(struct disasm_ctx *ctx, uint32_t *dwords, int n) fprintf(ctx->out, "(jp)"); 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); + } if (instr->ul && ((2 <= instr->opc_cat) && (instr->opc_cat <= 4))) fprintf(ctx->out, "(ul)"); @@ -1020,7 +1081,7 @@ static bool print_instr(struct disasm_ctx *ctx, uint32_t *dwords, int n) return (instr->opc_cat == 0) && (opc == OPC_END); } -int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out) +int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id) { struct disasm_ctx ctx; int i; @@ -1030,6 +1091,7 @@ int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out) memset(&ctx, 0, sizeof(ctx)); ctx.out = out; ctx.level = level; + ctx.gpu_id = gpu_id; for (i = 0; i < sizedwords; i += 2) print_instr(&ctx, &dwords[i], i/2); diff --git a/src/freedreno/ir3/instr-a3xx.h b/src/freedreno/ir3/instr-a3xx.h index 7f60ee5fd4c..eff720dacd5 100644 --- a/src/freedreno/ir3/instr-a3xx.h +++ b/src/freedreno/ir3/instr-a3xx.h @@ -413,13 +413,13 @@ typedef struct PACKED { uint32_t dst : 8; uint32_t repeat : 2; uint32_t sat : 1; - uint32_t src1_r : 1; + uint32_t src1_r : 1; /* doubles as nop0 if repeat==0 */ uint32_t ss : 1; uint32_t ul : 1; /* dunno */ uint32_t dst_half : 1; /* or widen/narrow.. ie. dst hrN <-> rN */ uint32_t ei : 1; uint32_t cond : 3; - uint32_t src2_r : 1; + uint32_t src2_r : 1; /* doubles as nop1 if repeat==0 */ uint32_t full : 1; /* not half */ uint32_t opc : 6; uint32_t jmp_tgt : 1; @@ -435,7 +435,7 @@ typedef struct PACKED { uint32_t must_be_zero1: 2; uint32_t src2_c : 1; uint32_t src1_neg : 1; - uint32_t src2_r : 1; + uint32_t src2_r : 1; /* doubles as nop1 if repeat==0 */ }; struct PACKED { uint32_t src1 : 10; @@ -477,7 +477,7 @@ typedef struct PACKED { uint32_t dst : 8; uint32_t repeat : 2; uint32_t sat : 1; - uint32_t src1_r : 1; + uint32_t src1_r : 1; /* doubles as nop0 if repeat==0 */ uint32_t ss : 1; uint32_t ul : 1; uint32_t dst_half : 1; /* or widen/narrow.. ie. dst hrN <-> rN */ @@ -727,6 +727,44 @@ typedef union PACKED { }; } instr_cat6_t; +/** + * For atomic ops (which return a value): + * + * pad1=1, pad2=c, pad3=0, pad4=3 + * src1 - vecN offset/coords + * src2.x - is actually dest register + * src2.y - is 'data' except for cmpxchg where src2.y is 'compare' + * and src2.z is 'data' + * + * For stib (which does not return a value): + * pad1=0, pad2=c, pad3=0, pad4=2 + * src1 - vecN offset/coords + * src2 - value to store + * + * for ldc (load from UBO using descriptor): + * pad1=0, pad2=8, pad3=0, pad4=2 + */ +typedef struct PACKED { + /* dword0: */ + uint32_t pad1 : 9; + uint32_t d : 2; + uint32_t typed : 1; + uint32_t type_size : 2; + uint32_t opc : 5; + uint32_t pad2 : 5; + uint32_t src1 : 8; /* coordinate/offset */ + + /* dword1: */ + uint32_t src2 : 8; + uint32_t pad3 : 1; //mustbe0 ?? or zero means imm vs reg for ssbo?? + uint32_t ssbo : 8; /* ssbo/image binding point */ + uint32_t type : 3; + uint32_t pad4 : 7; + uint32_t jmp_tgt : 1; + uint32_t sync : 1; + uint32_t opc_cat : 3; +} instr_cat6_a6xx_t; + typedef struct PACKED { /* dword0: */ uint32_t pad1 : 32; @@ -753,6 +791,7 @@ typedef union PACKED { instr_cat4_t cat4; instr_cat5_t cat5; instr_cat6_t cat6; + instr_cat6_a6xx_t cat6_a6xx; instr_cat7_t cat7; struct PACKED { /* dword0: */ @@ -792,7 +831,7 @@ static inline bool instr_sat(instr_t *instr) } } -static inline uint32_t instr_opc(instr_t *instr) +static inline uint32_t instr_opc(instr_t *instr, unsigned gpu_id) { switch (instr->opc_cat) { case 0: return instr->cat0.opc; @@ -801,7 +840,13 @@ static inline uint32_t instr_opc(instr_t *instr) case 3: return instr->cat3.opc; case 4: return instr->cat4.opc; case 5: return instr->cat5.opc; - case 6: return instr->cat6.opc; + case 6: + // TODO not sure if this is the best way to figure + // out if new vs old encoding, but it kinda seems + // to work: + if ((gpu_id >= 600) && (instr->cat6.opc == 0)) + return instr->cat6_a6xx.opc; + return instr->cat6.opc; case 7: return instr->cat7.opc; default: return 0; } @@ -867,6 +912,6 @@ static inline bool is_ssbo(opc_t opc) } } -int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out); +int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id); #endif /* INSTR_A3XX_H_ */ diff --git a/src/freedreno/ir3/ir3_shader.c b/src/freedreno/ir3/ir3_shader.c index 8b18e950cca..74d92e13962 100644 --- a/src/freedreno/ir3/ir3_shader.c +++ b/src/freedreno/ir3/ir3_shader.c @@ -329,7 +329,7 @@ ir3_shader_disasm(struct ir3_shader_variant *so, uint32_t *bin, FILE *out) so->immediates[i].val[3]); } - disasm_a3xx(bin, so->info.sizedwords, 0, out); + disasm_a3xx(bin, so->info.sizedwords, 0, out, ir->compiler->gpu_id); switch (so->type) { case MESA_SHADER_VERTEX: diff --git a/src/gallium/drivers/freedreno/disasm.h b/src/gallium/drivers/freedreno/disasm.h index 9de87d8de5f..dc29b2fbd2a 100644 --- a/src/gallium/drivers/freedreno/disasm.h +++ b/src/gallium/drivers/freedreno/disasm.h @@ -37,7 +37,7 @@ enum debug_t { }; int disasm_a2xx(uint32_t *dwords, int sizedwords, int level, gl_shader_stage type); -int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out); +int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id); void disasm_set_debug(enum debug_t debug); #endif /* DISASM_H_ */ |