From 20b50a071271e2caf8a4c3d4fd72f877af8a18d9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 26 Feb 2015 13:35:31 -0500 Subject: [PATCH] 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 --- .../drivers/freedreno/ir3/disasm-a3xx.c | 157 +++++++++--------- .../drivers/freedreno/ir3/instr-a3xx.h | 41 ++--- src/gallium/drivers/freedreno/ir3/ir3.c | 62 +++---- 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); -- 2.30.2