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 <robclark@freedesktop.org>
This commit is contained in:
parent
4abb789bca
commit
20b50a0712
|
@ -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("]");
|
||||
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_L2G:
|
||||
ss = 'l';
|
||||
sd = 'g';
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
cat6->has_off = false;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue