From 1f3b52ce503597ccb170b7caae3b3f19890dce46 Mon Sep 17 00:00:00 2001 From: "Kristian H. Kristensen" Date: Tue, 22 Oct 2019 16:03:36 -0700 Subject: [PATCH] freedreno/a6xx: Add register offset for STG/LDG These instructions take a 64 bit iova as two conescutive registers and a immediate offset. This patch adds support for the offset to be a single register, which is added to the 64 bit iova. Signed-off-by: Kristian H. Kristensen Acked-by: Eric Anholt Reviewed-by: Rob Clark --- src/freedreno/ir3/disasm-a3xx.c | 33 +++++++++++++++++++++++++++++++-- src/freedreno/ir3/instr-a3xx.h | 2 ++ src/freedreno/ir3/ir3.c | 33 ++++++++++++++++++++++++++------- src/freedreno/ir3/ir3.h | 2 ++ src/freedreno/ir3/ir3_cp.c | 3 +++ 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/freedreno/ir3/disasm-a3xx.c b/src/freedreno/ir3/disasm-a3xx.c index 093a38fa9b5..344bb7bd98c 100644 --- a/src/freedreno/ir3/disasm-a3xx.c +++ b/src/freedreno/ir3/disasm-a3xx.c @@ -721,6 +721,26 @@ static void print_instr_cat6_a3xx(struct disasm_ctx *ctx, instr_t *instr) if (debug & PRINT_VERBOSE) fprintf(ctx->out, " (pad0=%x, pad3=%x, mustbe0=%x)", cat6->ldgb.pad0, cat6->ldgb.pad3, cat6->ldgb.mustbe0); + return; + } else if (_OPC(6, cat6->opc) == OPC_LDG && cat6->a.src1_im && cat6->a.src2_im) { + struct reginfo src3; + + memset(&src3, 0, sizeof(src3)); + src1.reg = (reg_t)(cat6->a.src1); + src2.reg = (reg_t)(cat6->a.src2); + src2.im = cat6->a.src2_im; + src3.reg = (reg_t)(cat6->a.off); + src3.full = true; + dst.reg = (reg_t)(cat6->d.dst); + + print_src(ctx, &dst); + fprintf(ctx->out, ", g["); + print_src(ctx, &src1); + fprintf(ctx->out, "+"); + print_src(ctx, &src3); + fprintf(ctx->out, "], "); + print_src(ctx, &src2); + return; } if (cat6->dst_off) { @@ -748,8 +768,15 @@ static void print_instr_cat6_a3xx(struct disasm_ctx *ctx, instr_t *instr) fprintf(ctx->out, "%c[", sd); /* note: dst might actually be a src (ie. address to store to) */ print_src(ctx, &dst); - if (dstoff) + if (cat6->dst_off && cat6->g) { + struct reginfo dstoff_reg = {}; + dstoff_reg.reg = (reg_t) cat6->c.off; + dstoff_reg.full = true; + fprintf(ctx->out, "+"); + print_src(ctx, &dstoff_reg); + } else if (dstoff) { fprintf(ctx->out, "%+d", dstoff); + } if (sd) fprintf(ctx->out, "]"); fprintf(ctx->out, ", "); @@ -765,7 +792,9 @@ static void print_instr_cat6_a3xx(struct disasm_ctx *ctx, instr_t *instr) print_src(ctx, &src1); } - if (src1off) + if (cat6->src_off && cat6->g) + print_src(ctx, &src2); + else if (src1off) fprintf(ctx->out, "%+d", src1off); if (ss) fprintf(ctx->out, "]"); diff --git a/src/freedreno/ir3/instr-a3xx.h b/src/freedreno/ir3/instr-a3xx.h index 29f2bd781bc..9ad07d3173e 100644 --- a/src/freedreno/ir3/instr-a3xx.h +++ b/src/freedreno/ir3/instr-a3xx.h @@ -284,6 +284,8 @@ typedef union PACKED { uint32_t dummy12 : 12; uint32_t dummy13 : 13; uint32_t dummy8 : 8; + int32_t idummy13 : 13; + int32_t idummy8 : 8; } reg_t; /* special registers: */ diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c index b137ee1a695..fa7aa418027 100644 --- a/src/freedreno/ir3/ir3.c +++ b/src/freedreno/ir3/ir3.c @@ -801,16 +801,24 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr, cat6->src_off = true; - cat6a->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED); - cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED); + if (instr->opc == OPC_LDG) { + /* For LDG src1 can not be immediate, so src1_imm is redundant and + * instead used to signal whether (when true) 'off' is a 32 bit + * register or an immediate offset. + */ + cat6a->src1 = reg(src1, info, instr->repeat, 0); + cat6a->src1_im = !(src3->flags & IR3_REG_IMMED); + cat6a->off = reg(src3, info, instr->repeat, IR3_REG_IMMED); + } else { + cat6a->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED); + cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED); + cat6a->off = reg(src3, info, instr->repeat, IR3_REG_IMMED); + iassert(src3->flags & IR3_REG_IMMED); + } /* Num components */ cat6a->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED); cat6a->src2_im = true; - - /* Offset */ - iassert(src3->flags & IR3_REG_IMMED); - cat6a->off = reg(src3, info, instr->repeat, IR3_REG_IMMED); } else { instr_cat6b_t *cat6b = ptr; @@ -827,9 +835,20 @@ static int emit_cat6(struct ir3_instruction *instr, void *ptr, if (instr->cat6.dst_offset || (instr->opc == OPC_STG) || (instr->opc == OPC_STL) || (instr->opc == OPC_STLW)) { instr_cat6c_t *cat6c = ptr; + struct ir3_register *src3 = instr->regs[4]; cat6->dst_off = true; cat6c->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF); - cat6c->off = instr->cat6.dst_offset; + + if (instr->flags & IR3_INSTR_G) { + cat6c->off = reg(src3, info, instr->repeat, IR3_REG_R | IR3_REG_HALF); + if (src3->flags & IR3_REG_IMMED) { + /* Immediate offsets are in bytes... */ + cat6->g = false; + cat6c->off *= 4; + } + } else { + cat6c->off = instr->cat6.dst_offset; + } } else { instr_cat6d_t *cat6d = ptr; cat6->dst_off = false; diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 7eeb8b44336..7e69e8ea8ed 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -1471,6 +1471,8 @@ INSTR4F(G, ATOMIC_OR) INSTR4F(G, ATOMIC_XOR) #endif +INSTR4F(G, STG) + /* cat7 instructions: */ INSTR0(BAR) INSTR0(FENCE) diff --git a/src/freedreno/ir3/ir3_cp.c b/src/freedreno/ir3/ir3_cp.c index fa25c9ca8a1..5cc3f833144 100644 --- a/src/freedreno/ir3/ir3_cp.c +++ b/src/freedreno/ir3/ir3_cp.c @@ -238,6 +238,9 @@ static bool valid_flags(struct ir3_instruction *instr, unsigned n, if (is_atomic(instr->opc) && !(instr->flags & IR3_INSTR_G)) return false; + if (instr->opc == OPC_STG && (instr->flags & IR3_INSTR_G) && (n != 2)) + return false; + /* as with atomics, ldib on a6xx can only have immediate for * SSBO slot argument */ -- 2.30.2