freedreno/a6xx: Add register offset for STG/LDG
authorKristian H. Kristensen <hoegsberg@google.com>
Tue, 22 Oct 2019 23:03:36 +0000 (16:03 -0700)
committerKristian H. Kristensen <hoegsberg@google.com>
Fri, 8 Nov 2019 00:36:39 +0000 (16:36 -0800)
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 <hoegsberg@google.com>
Acked-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Rob Clark <robdclark@gmail.com>
src/freedreno/ir3/disasm-a3xx.c
src/freedreno/ir3/instr-a3xx.h
src/freedreno/ir3/ir3.c
src/freedreno/ir3/ir3.h
src/freedreno/ir3/ir3_cp.c

index 093a38fa9b5a0277e2b75a408ed29ee49aea54c8..344bb7bd98cd8c8204bfbb451a319c7940593957 100644 (file)
@@ -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, "]");
index 29f2bd781bc35dc8c3462579b63b0c581b26caf9..9ad07d3173e2481cf4cbf8e59d21b176c56d9e5f 100644 (file)
@@ -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: */
index b137ee1a695a2a7cf90e3ba6f2a207cda8f55f9b..fa7aa4180275f49beaa0fc76e7bbdfa3783e4685 100644 (file)
@@ -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;
index 7eeb8b4433645421c46f7dbd03500b81be89c4d6..7e69e8ea8edab4ac74850a7d7e18cb705a23861a 100644 (file)
@@ -1471,6 +1471,8 @@ INSTR4F(G, ATOMIC_OR)
 INSTR4F(G, ATOMIC_XOR)
 #endif
 
+INSTR4F(G, STG)
+
 /* cat7 instructions: */
 INSTR0(BAR)
 INSTR0(FENCE)
index fa25c9ca8a1248e3fd4e4ef8f64ed5bc8a1ada3a..5cc3f8331443ec2411b28428a7d28434f33ebd69 100644 (file)
@@ -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
                         */