summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <[email protected]>2015-02-26 13:35:31 -0500
committerRob Clark <[email protected]>2015-03-03 10:41:00 -0500
commit20b50a071271e2caf8a4c3d4fd72f877af8a18d9 (patch)
treefb66449268ad4effc84192db29fadafcb14238cc
parent4abb789bca95e9c23b2339ea7732833203c94639 (diff)
freedreno/ir3: fix up cat6 instruction encodings
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 <[email protected]>
-rw-r--r--src/gallium/drivers/freedreno/ir3/disasm-a3xx.c157
-rw-r--r--src/gallium/drivers/freedreno/ir3/instr-a3xx.h41
-rw-r--r--src/gallium/drivers/freedreno/ir3/ir3.c62
3 files changed, 121 insertions, 139 deletions
diff --git a/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c b/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c
index 602be6508f3..bed9aca795f 100644
--- a/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c
+++ b/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c
@@ -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;
}
}
diff --git a/src/gallium/drivers/freedreno/ir3/instr-a3xx.h b/src/gallium/drivers/freedreno/ir3/instr-a3xx.h
index c67f1037ced..b7e19c8ae39 100644
--- a/src/gallium/drivers/freedreno/ir3/instr-a3xx.h
+++ b/src/gallium/drivers/freedreno/ir3/instr-a3xx.h
@@ -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;
diff --git a/src/gallium/drivers/freedreno/ir3/ir3.c b/src/gallium/drivers/freedreno/ir3/ir3.c
index 095085a0ea9..a02b06f059a 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3.c
@@ -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);