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:
Rob Clark 2015-02-26 13:35:31 -05:00
parent 4abb789bca
commit 20b50a0712
3 changed files with 122 additions and 140 deletions

View 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("]");
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;
}
}

View 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;

View 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));
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);