freedreno/ir3: fix up cat6 instruction encodings
authorRob Clark <robclark@freedesktop.org>
Thu, 26 Feb 2015 18:35:31 +0000 (13:35 -0500)
committerRob Clark <robclark@freedesktop.org>
Tue, 3 Mar 2015 15:41:00 +0000 (10:41 -0500)
I think there is at least one more sub-encoding, but these two should be
enough to cover the common load/store instructions.

Signed-off-by: Rob Clark <robclark@freedesktop.org>
src/gallium/drivers/freedreno/ir3/disasm-a3xx.c
src/gallium/drivers/freedreno/ir3/instr-a3xx.h
src/gallium/drivers/freedreno/ir3/ir3.c

index 602be6508f32e8550a0284cdf9baaf716847f99b..bed9aca795f572efb9c345f8fb46a78bb1cb4d13 100644 (file)
@@ -448,117 +448,114 @@ static void print_instr_cat5(instr_t *instr)
        }
 }
 
-static int32_t u2i(uint32_t val, int nbits)
-{
-       return ((val >> (nbits-1)) * ~((1 << nbits) - 1)) | val;
-}
-
 static void print_instr_cat6(instr_t *instr)
 {
        instr_cat6_t *cat6 = &instr->cat6;
+       char sd = 0, ss = 0;  /* dst/src address space */
+       bool full = type_size(cat6->type) == 32;
+       bool nodst = false;
 
        printf(".%s ", type[cat6->type]);
 
        switch (cat6->opc) {
+       case OPC_STG:
+               sd = 'g';
+               break;
+       case OPC_STP:
+               sd = 'p';
+               break;
+       case OPC_STL:
+       case OPC_STLW:
+               sd = 'l';
+               break;
+
        case OPC_LDG:
+               ss = 'g';
+               break;
        case OPC_LDP:
+               ss = 'p';
+               break;
        case OPC_LDL:
        case OPC_LDLW:
        case OPC_LDLV:
-               /* load instructions: */
-               print_reg_dst((reg_t)(cat6->a.dst), type_size(cat6->type) == 32, false);
-               printf(",");
-               switch (cat6->opc) {
-               case OPC_LDG:
-                       printf("g");
-                       break;
-               case OPC_LDP:
-                       printf("p");
-                       break;
-               case OPC_LDL:
-               case OPC_LDLW:
-               case OPC_LDLV:
-                       printf("l");
-                       break;
-               }
-               printf("[");
-               print_reg_src((reg_t)(cat6->a.src), true,
-                               false, false, false, false, false, false);
-               if (cat6->a.off)
-                       printf("%+d", cat6->a.off);
-               printf("]");
+               ss = 'l';
                break;
-       case OPC_PREFETCH:
-               /* similar to load instructions: */
-               printf("g[");
-               print_reg_src((reg_t)(cat6->a.src), true,
-                               false, false, false, false, false, false);
-               if (cat6->a.off)
-                       printf("%+d", cat6->a.off);
-               printf("]");
+
+       case OPC_L2G:
+               ss = 'l';
+               sd = 'g';
                break;
-       case OPC_STG:
-       case OPC_STP:
-       case OPC_STL:
-       case OPC_STLW:
-               /* store instructions: */
-               switch (cat6->opc) {
-               case OPC_STG:
-                       printf("g");
-                       break;
-               case OPC_STP:
-                       printf("p");
-                       break;
-               case OPC_STL:
-               case OPC_STLW:
-                       printf("l");
-                       break;
-               }
-               printf("[");
-               print_reg_dst((reg_t)(cat6->b.dst), true, false);
-               if (cat6->b.off || cat6->b.off_hi)
-                       printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
-               printf("]");
-               printf(",");
-               print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
-                               false, false, false, false, false, false);
 
+       case OPC_G2L:
+               ss = 'g';
+               sd = 'l';
                break;
+
+       case OPC_PREFETCH:
+               ss = 'g';
+               nodst = true;
+               break;
+
        case OPC_STI:
-               /* sti has same encoding as other store instructions, but
-                * slightly different syntax:
-                */
-               print_reg_dst((reg_t)(cat6->b.dst), false /* XXX is it always half? */, false);
-               if (cat6->b.off || cat6->b.off_hi)
-                       printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
-               printf(",");
-               print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
-                               false, false, false, false, false, false);
+               full = false;  // XXX or inverts??
                break;
        }
 
-       printf(", %d", cat6->iim_val);
+       if (cat6->has_off) {
+               if (!nodst) {
+                       if (sd)
+                               printf("%c[", sd);
+                       print_reg_dst((reg_t)(cat6->a.dst), full, false);
+                       if (sd)
+                               printf("]");
+                       printf(", ");
+               }
+               if (ss)
+                       printf("%c[", ss);
+               print_reg_src((reg_t)(cat6->a.src1), true,
+                               false, false, cat6->a.src1_im, false, false, false);
+               printf("%+d", cat6->a.off);
+               if (ss)
+                       printf("]");
+               printf(", ");
+               print_reg_src((reg_t)(cat6->a.src2), full,
+                               false, false, cat6->a.src2_im, false, false, false);
+       } else {
+               if (!nodst) {
+                       if (sd)
+                               printf("%c[", sd);
+                       print_reg_dst((reg_t)(cat6->b.dst), full, false);
+                       if (sd)
+                               printf("]");
+                       printf(", ");
+               }
+               if (ss)
+                       printf("%c[", ss);
+               print_reg_src((reg_t)(cat6->b.src1), true,
+                               false, false, cat6->b.src1_im, false, false, false);
+               if (ss)
+                       printf("]");
+               printf(", ");
+               print_reg_src((reg_t)(cat6->b.src2), full,
+                               false, false, cat6->b.src2_im, false, false, false);
+       }
 
        if (debug & PRINT_VERBOSE) {
                switch (cat6->opc) {
                case OPC_LDG:
                case OPC_LDP:
                        /* load instructions: */
-                       if (cat6->a.dummy1|cat6->a.dummy2|cat6->a.dummy3)
-                               printf("\t{6: %x,%x,%x}", cat6->a.dummy1, cat6->a.dummy2, cat6->a.dummy3);
-                       if ((cat6->a.must_be_one1 != 1) || (cat6->a.must_be_one2 != 1))
-                               printf("{?? %d,%d ??}", cat6->a.must_be_one1, cat6->a.must_be_one2);
+                       if (cat6->a.dummy2|cat6->a.dummy3)
+                               printf("\t{6: %x,%x}", cat6->a.dummy2, cat6->a.dummy3);
                        break;
                case OPC_STG:
                case OPC_STP:
                case OPC_STI:
                        /* store instructions: */
-                       if (cat6->b.dummy1|cat6->b.dummy2)
-                               printf("\t{6: %x,%x}", cat6->b.dummy1, cat6->b.dummy2);
-                       if ((cat6->b.must_be_one1 != 1) || (cat6->b.must_be_one2 != 1) ||
-                                       (cat6->b.must_be_zero1 != 0))
-                               printf("{?? %d,%d,%d ??}", cat6->b.must_be_one1, cat6->b.must_be_one2,
-                                               cat6->b.must_be_zero1);
+                       if (cat6->b.dummy2|cat6->b.dummy2)
+                               printf("\t{6: %x,%x}", cat6->b.dummy2, cat6->b.dummy3);
+                       if (cat6->b.ignore0)
+                               printf("\t{?? %x}", cat6->b.ignore0);
                        break;
                }
        }
index c67f1037ced41db991caa0301ecd0d2b468c8450..b7e19c8ae39e13e2d88714304eba0cbc2d04cb7d 100644 (file)
@@ -572,15 +572,15 @@ typedef struct PACKED {
        uint32_t opc_cat  : 3;
 } instr_cat5_t;
 
-/* used for load instructions: */
+/* [src1 + off], src2: */
 typedef struct PACKED {
        /* dword0: */
-       uint32_t must_be_one1 : 1;
-       int16_t  off      : 13;
-       uint32_t src      : 8;
-       uint32_t dummy1   : 1;
-       uint32_t must_be_one2 : 1;
-       int32_t  iim_val  : 8;
+       uint32_t mustbe1  : 1;
+       int32_t  off      : 13;
+       uint32_t src1     : 8;
+       uint32_t src1_im  : 1;
+       uint32_t src2_im  : 1;
+       uint32_t src2     : 8;
 
        /* dword1: */
        uint32_t dst      : 8;
@@ -593,35 +593,38 @@ typedef struct PACKED {
        uint32_t opc_cat  : 3;
 } instr_cat6a_t;
 
-/* used for store instructions: */
+/* [src1], src2: */
 typedef struct PACKED {
        /* dword0: */
-       uint32_t must_be_zero1 : 1;
-       uint32_t src      : 8;
-       uint32_t off_hi   : 5;   /* high bits of 'off'... ugly! */
-       uint32_t dummy1   : 9;
-       uint32_t must_be_one1 : 1;
-       int32_t  iim_val  : 8;
+       uint32_t mustbe0  : 1;
+       uint32_t src1     : 8;
+       uint32_t ignore0  : 13;
+       uint32_t src1_im  : 1;
+       uint32_t src2_im  : 1;
+       uint32_t src2     : 8;
 
        /* dword1: */
-       uint16_t off      : 8;
-       uint32_t must_be_one2 : 1;
        uint32_t dst      : 8;
+       uint32_t dummy2   : 9;
        uint32_t type     : 3;
-       uint32_t dummy2   : 2;
+       uint32_t dummy3   : 2;
        uint32_t opc      : 5;
        uint32_t jmp_tgt  : 1;
        uint32_t sync     : 1;
        uint32_t opc_cat  : 3;
 } instr_cat6b_t;
 
+/* I think some of the other cat6 instructions use additional
+ * sub-encodings..
+ */
+
 typedef union PACKED {
        instr_cat6a_t a;
        instr_cat6b_t b;
        struct PACKED {
                /* dword0: */
-               uint32_t pad1     : 24;
-               int32_t  iim_val  : 8;
+               uint32_t has_off  : 1;
+               uint32_t pad1     : 31;
 
                /* dword1: */
                uint32_t pad2     : 17;
index 095085a0ea9c4cac2da1fa624c1da5a503d80f81..a02b06f059a7baaf77486da7152c2fe5a198f996 100644 (file)
@@ -474,58 +474,40 @@ static int emit_cat5(struct ir3_instruction *instr, void *ptr,
 static int emit_cat6(struct ir3_instruction *instr, void *ptr,
                struct ir3_info *info)
 {
-       struct ir3_register *dst = instr->regs[0];
-       struct ir3_register *src = instr->regs[1];
+       struct ir3_register *dst  = instr->regs[0];
+       struct ir3_register *src1 = instr->regs[1];
+       struct ir3_register *src2 = (instr->regs_count >= 3) ? instr->regs[2] : NULL;
        instr_cat6_t *cat6 = ptr;
 
-       iassert(instr->regs_count == 2);
+       iassert(instr->regs_count >= 2);
 
-       switch (instr->opc) {
-       /* load instructions: */
-       case OPC_LDG:
-       case OPC_LDP:
-       case OPC_LDL:
-       case OPC_LDLW:
-       case OPC_LDLV:
-       case OPC_PREFETCH: {
+       if (instr->cat6.offset) {
                instr_cat6a_t *cat6a = ptr;
 
-               iassert(!((dst->flags ^ type_flags(instr->cat6.type)) & IR3_REG_HALF));
+               cat6->has_off = true;
 
-               cat6a->must_be_one1  = 1;
-               cat6a->must_be_one2  = 1;
-               cat6a->off = instr->cat6.offset;
-               cat6a->src = reg(src, info, instr->repeat, 0);
                cat6a->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
-               break;
-       }
-       /* store instructions: */
-       case OPC_STG:
-       case OPC_STP:
-       case OPC_STL:
-       case OPC_STLW:
-       case OPC_STI: {
+               cat6a->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+               cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED);
+               if (src2) {
+                       cat6a->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+                       cat6a->src2_im = !!(src2->flags & IR3_REG_IMMED);
+               }
+               cat6a->off = instr->cat6.offset;
+       } else {
                instr_cat6b_t *cat6b = ptr;
-               uint32_t src_flags = type_flags(instr->cat6.type);
-               uint32_t dst_flags = (instr->opc == OPC_STI) ? IR3_REG_HALF : 0;
-
-               iassert(!((src->flags ^ src_flags) & IR3_REG_HALF));
 
-               cat6b->must_be_one1  = 1;
-               cat6b->must_be_one2  = 1;
-               cat6b->src    = reg(src, info, instr->repeat, src_flags);
-               cat6b->off_hi = instr->cat6.offset >> 8;
-               cat6b->off    = instr->cat6.offset;
-               cat6b->dst    = reg(dst, info, instr->repeat, IR3_REG_R | dst_flags);
+               cat6->has_off = false;
 
-               break;
-       }
-       default:
-               // TODO
-               break;
+               cat6b->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
+               cat6b->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+               cat6b->src1_im = !!(src1->flags & IR3_REG_IMMED);
+               if (src2) {
+                       cat6b->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+                       cat6b->src2_im = !!(src2->flags & IR3_REG_IMMED);
+               }
        }
 
-       cat6->iim_val  = instr->cat6.iim_val;
        cat6->type     = instr->cat6.type;
        cat6->opc      = instr->opc;
        cat6->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);