mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-24 15:20:10 +01:00
freedreno/ir3: Remove legacy packed-struct encoding
Note that we can't actually remove the packed structs themselves yet, because tu still uses them in some hand-coded blit shaders. Signed-off-by: Rob Clark <robdclark@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7997>
This commit is contained in:
parent
1a8113fdee
commit
74748f16c9
2 changed files with 1 additions and 890 deletions
|
|
@ -64,869 +64,6 @@ void ir3_destroy(struct ir3 *shader)
|
|||
ralloc_free(shader);
|
||||
}
|
||||
|
||||
#define iassert(cond) do { \
|
||||
if (!(cond)) { \
|
||||
debug_assert(cond); \
|
||||
return -1; \
|
||||
} } while (0)
|
||||
|
||||
#define iassert_type(reg, full) do { \
|
||||
if ((full)) { \
|
||||
iassert(!((reg)->flags & IR3_REG_HALF)); \
|
||||
} else { \
|
||||
iassert((reg)->flags & IR3_REG_HALF); \
|
||||
} } while (0);
|
||||
|
||||
static uint32_t reg(struct ir3_register *reg, uint32_t valid_flags)
|
||||
{
|
||||
reg_t val = { .dummy32 = 0 };
|
||||
|
||||
if (reg->flags & ~valid_flags) {
|
||||
mesa_logd("INVALID FLAGS: %x vs %x",
|
||||
reg->flags, valid_flags);
|
||||
}
|
||||
|
||||
if (reg->flags & IR3_REG_IMMED) {
|
||||
val.iim_val = reg->iim_val;
|
||||
} else if (reg->flags & IR3_REG_RELATIV) {
|
||||
val.idummy10 = reg->array.offset;
|
||||
} else {
|
||||
val.comp = reg->num & 0x3;
|
||||
val.num = reg->num >> 2;
|
||||
}
|
||||
|
||||
return val.dummy32;
|
||||
}
|
||||
|
||||
static int emit_cat0(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
instr_cat0_t *cat0 = ptr;
|
||||
|
||||
if (instr->block->shader->compiler->gpu_id >= 500) {
|
||||
cat0->a5xx.immed = instr->cat0.immed;
|
||||
} else if (instr->block->shader->compiler->gpu_id >= 400) {
|
||||
cat0->a4xx.immed = instr->cat0.immed;
|
||||
} else {
|
||||
cat0->a3xx.immed = instr->cat0.immed;
|
||||
}
|
||||
cat0->repeat = instr->repeat;
|
||||
cat0->ss = !!(instr->flags & IR3_INSTR_SS);
|
||||
cat0->inv1 = instr->cat0.inv1;
|
||||
cat0->comp1 = instr->cat0.comp1;
|
||||
cat0->inv2 = instr->cat0.inv2;
|
||||
cat0->comp2 = instr->cat0.comp2;
|
||||
cat0->brtype = instr->cat0.brtype;
|
||||
cat0->idx = instr->cat0.idx;
|
||||
cat0->opc = instr->opc;
|
||||
cat0->opc_hi = instr->opc >= 16;
|
||||
cat0->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat0->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat0->opc_cat = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat1(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
struct ir3_register *dst = instr->regs[0];
|
||||
instr_cat1_t *cat1 = ptr;
|
||||
|
||||
switch (instr->opc) {
|
||||
case OPC_MOV: {
|
||||
struct ir3_register *src = instr->regs[1];
|
||||
iassert(instr->regs_count == 2);
|
||||
iassert_type(dst, type_size(instr->cat1.dst_type) == 32);
|
||||
if (!(src->flags & IR3_REG_IMMED))
|
||||
iassert_type(src, type_size(instr->cat1.src_type) == 32);
|
||||
|
||||
if (src->flags & IR3_REG_IMMED) {
|
||||
cat1->iim_val = src->iim_val;
|
||||
cat1->src_im = 1;
|
||||
} else if (src->flags & IR3_REG_RELATIV) {
|
||||
cat1->off = reg(src,
|
||||
IR3_REG_R | IR3_REG_CONST | IR3_REG_HALF | IR3_REG_RELATIV |
|
||||
IR3_REG_SHARED);
|
||||
cat1->src_rel = 1;
|
||||
cat1->src_rel_c = !!(src->flags & IR3_REG_CONST);
|
||||
} else {
|
||||
cat1->src = reg(src,
|
||||
IR3_REG_R | IR3_REG_CONST | IR3_REG_HALF | IR3_REG_SHARED);
|
||||
cat1->src_c = !!(src->flags & IR3_REG_CONST);
|
||||
}
|
||||
cat1->src_r = !!(src->flags & IR3_REG_R);
|
||||
cat1->dst_type = instr->cat1.dst_type;
|
||||
cat1->src_type = instr->cat1.src_type;
|
||||
cat1->even = !!(dst->flags & IR3_REG_EVEN);
|
||||
cat1->pos_inf = !!(dst->flags & IR3_REG_POS_INF);
|
||||
cat1->repeat = instr->repeat;
|
||||
break;
|
||||
}
|
||||
case OPC_MOVMSK: {
|
||||
iassert(instr->regs_count == 1);
|
||||
iassert(!(dst->flags & IR3_REG_HALF));
|
||||
iassert(!(dst->flags & IR3_REG_EVEN));
|
||||
iassert(!(dst->flags & IR3_REG_POS_INF));
|
||||
iassert(instr->repeat == 0);
|
||||
iassert(util_is_power_of_two_or_zero(dst->wrmask + 1));
|
||||
|
||||
unsigned components = util_last_bit(dst->wrmask);
|
||||
cat1->repeat = components - 1;
|
||||
cat1->src_type = cat1->dst_type = TYPE_U32;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
iassert(0);
|
||||
}
|
||||
|
||||
cat1->dst = reg(dst, IR3_REG_RELATIV | IR3_REG_EVEN |
|
||||
IR3_REG_R | IR3_REG_POS_INF | IR3_REG_HALF | IR3_REG_SHARED);
|
||||
cat1->ss = !!(instr->flags & IR3_INSTR_SS);
|
||||
cat1->ul = !!(instr->flags & IR3_INSTR_UL);
|
||||
cat1->dst_rel = !!(dst->flags & IR3_REG_RELATIV);
|
||||
cat1->opc = instr->opc;
|
||||
cat1->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat1->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat1->opc_cat = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat2(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
struct ir3_register *dst = instr->regs[0];
|
||||
struct ir3_register *src1 = instr->regs[1];
|
||||
struct ir3_register *src2 = (instr->regs_count > 2) ? instr->regs[2] : NULL;
|
||||
instr_cat2_t *cat2 = ptr;
|
||||
unsigned absneg = ir3_cat2_absneg(instr->opc);
|
||||
|
||||
iassert((instr->regs_count == 2) || (instr->regs_count == 3));
|
||||
|
||||
if (instr->nop) {
|
||||
iassert(!instr->repeat);
|
||||
iassert(instr->nop <= 3);
|
||||
|
||||
cat2->src1_r = instr->nop & 0x1;
|
||||
cat2->src2_r = (instr->nop >> 1) & 0x1;
|
||||
} else {
|
||||
cat2->src1_r = !!(src1->flags & IR3_REG_R);
|
||||
if (src2)
|
||||
cat2->src2_r = !!(src2->flags & IR3_REG_R);
|
||||
}
|
||||
|
||||
if (src1->flags & IR3_REG_RELATIV) {
|
||||
iassert(src1->array.offset < (1 << 10));
|
||||
cat2->rel1.src1 = reg(src1,
|
||||
IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_R |
|
||||
IR3_REG_HALF | IR3_REG_SHARED | absneg);
|
||||
cat2->rel1.src1_c = !!(src1->flags & IR3_REG_CONST);
|
||||
cat2->rel1.src1_rel = 1;
|
||||
} else if (src1->flags & IR3_REG_CONST) {
|
||||
iassert(src1->num < (1 << 12));
|
||||
cat2->c1.src1 = reg(src1,
|
||||
IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF |
|
||||
absneg);
|
||||
cat2->c1.src1_c = 1;
|
||||
} else {
|
||||
iassert(src1->num < (1 << 11));
|
||||
cat2->src1 = reg(src1,
|
||||
IR3_REG_IMMED | IR3_REG_R | IR3_REG_HALF | IR3_REG_SHARED |
|
||||
absneg);
|
||||
}
|
||||
cat2->src1_im = !!(src1->flags & IR3_REG_IMMED);
|
||||
cat2->src1_neg = !!(src1->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT));
|
||||
cat2->src1_abs = !!(src1->flags & (IR3_REG_FABS | IR3_REG_SABS));
|
||||
|
||||
if (src2) {
|
||||
iassert((src2->flags & IR3_REG_IMMED) ||
|
||||
!((src1->flags ^ src2->flags) & IR3_REG_HALF));
|
||||
|
||||
if (src2->flags & IR3_REG_RELATIV) {
|
||||
iassert(src2->array.offset < (1 << 10));
|
||||
cat2->rel2.src2 = reg(src2,
|
||||
IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_R |
|
||||
IR3_REG_HALF | IR3_REG_SHARED | absneg);
|
||||
cat2->rel2.src2_c = !!(src2->flags & IR3_REG_CONST);
|
||||
cat2->rel2.src2_rel = 1;
|
||||
} else if (src2->flags & IR3_REG_CONST) {
|
||||
iassert(src2->num < (1 << 12));
|
||||
cat2->c2.src2 = reg(src2,
|
||||
IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF |
|
||||
absneg);
|
||||
cat2->c2.src2_c = 1;
|
||||
} else {
|
||||
iassert(src2->num < (1 << 11));
|
||||
cat2->src2 = reg(src2,
|
||||
IR3_REG_IMMED | IR3_REG_R | IR3_REG_HALF | IR3_REG_SHARED |
|
||||
absneg);
|
||||
}
|
||||
|
||||
cat2->src2_im = !!(src2->flags & IR3_REG_IMMED);
|
||||
cat2->src2_neg = !!(src2->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT));
|
||||
cat2->src2_abs = !!(src2->flags & (IR3_REG_FABS | IR3_REG_SABS));
|
||||
}
|
||||
|
||||
if (!ir3_cat2_int(instr->opc)) {
|
||||
/* For floating point ALU with immediate arg, it will be a
|
||||
* FLUT index
|
||||
*/
|
||||
if (src1->flags & IR3_REG_IMMED) {
|
||||
cat2->must_be_zero1 = 1;
|
||||
if (src1->flags & IR3_REG_HALF)
|
||||
cat2->src1 |= 0x400;
|
||||
}
|
||||
|
||||
if (src2 && (src2->flags & IR3_REG_IMMED)) {
|
||||
cat2->must_be_zero2 = 1;
|
||||
if (src2->flags & IR3_REG_HALF)
|
||||
cat2->src2 |= 0x400;
|
||||
}
|
||||
}
|
||||
|
||||
cat2->dst = reg(dst, IR3_REG_R | IR3_REG_EI | IR3_REG_HALF | IR3_REG_SHARED);
|
||||
cat2->repeat = instr->repeat;
|
||||
cat2->sat = !!(instr->flags & IR3_INSTR_SAT);
|
||||
cat2->ss = !!(instr->flags & IR3_INSTR_SS);
|
||||
cat2->ul = !!(instr->flags & IR3_INSTR_UL);
|
||||
/* dst widen/narrow doesn't apply to p0.c */
|
||||
if (dst->num < regid(REG_P0, 0))
|
||||
cat2->dst_half = !!((src1->flags ^ dst->flags) & IR3_REG_HALF);
|
||||
cat2->ei = !!(dst->flags & IR3_REG_EI);
|
||||
cat2->cond = instr->cat2.condition;
|
||||
cat2->full = ! (src1->flags & IR3_REG_HALF);
|
||||
cat2->opc = instr->opc;
|
||||
cat2->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat2->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat2->opc_cat = 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat3(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
struct ir3_register *dst = instr->regs[0];
|
||||
struct ir3_register *src1 = instr->regs[1];
|
||||
struct ir3_register *src2 = instr->regs[2];
|
||||
struct ir3_register *src3 = instr->regs[3];
|
||||
unsigned absneg = ir3_cat3_absneg(instr->opc);
|
||||
instr_cat3_t *cat3 = ptr;
|
||||
uint32_t src_flags = 0;
|
||||
|
||||
switch (instr->opc) {
|
||||
case OPC_MAD_F16:
|
||||
case OPC_MAD_U16:
|
||||
case OPC_MAD_S16:
|
||||
case OPC_SEL_B16:
|
||||
case OPC_SEL_S16:
|
||||
case OPC_SEL_F16:
|
||||
case OPC_SAD_S16:
|
||||
case OPC_SAD_S32: // really??
|
||||
src_flags |= IR3_REG_HALF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iassert(instr->regs_count == 4);
|
||||
iassert(!((src1->flags ^ src_flags) & IR3_REG_HALF));
|
||||
iassert(!((src2->flags ^ src_flags) & IR3_REG_HALF));
|
||||
iassert(!((src3->flags ^ src_flags) & IR3_REG_HALF));
|
||||
|
||||
if (instr->nop) {
|
||||
iassert(!instr->repeat);
|
||||
iassert(instr->nop <= 3);
|
||||
|
||||
cat3->src1_r = instr->nop & 0x1;
|
||||
cat3->src2_r = (instr->nop >> 1) & 0x1;
|
||||
} else {
|
||||
cat3->src1_r = !!(src1->flags & IR3_REG_R);
|
||||
cat3->src2_r = !!(src2->flags & IR3_REG_R);
|
||||
}
|
||||
|
||||
if (src1->flags & IR3_REG_RELATIV) {
|
||||
iassert(src1->array.offset < (1 << 10));
|
||||
cat3->rel1.src1 = reg(src1,
|
||||
IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_R |
|
||||
IR3_REG_HALF | IR3_REG_SHARED | absneg);
|
||||
cat3->rel1.src1_c = !!(src1->flags & IR3_REG_CONST);
|
||||
cat3->rel1.src1_rel = 1;
|
||||
} else if (src1->flags & IR3_REG_CONST) {
|
||||
iassert(src1->num < (1 << 12));
|
||||
cat3->c1.src1 = reg(src1,
|
||||
IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF | absneg);
|
||||
cat3->c1.src1_c = 1;
|
||||
} else {
|
||||
iassert(src1->num < (1 << 11));
|
||||
cat3->src1 = reg(src1,
|
||||
IR3_REG_R | IR3_REG_HALF | IR3_REG_SHARED | absneg);
|
||||
}
|
||||
|
||||
cat3->src1_neg = !!(src1->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT));
|
||||
|
||||
cat3->src2 = reg(src2,
|
||||
IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF | IR3_REG_SHARED | absneg);
|
||||
cat3->src2_c = !!(src2->flags & IR3_REG_CONST);
|
||||
cat3->src2_neg = !!(src2->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT));
|
||||
|
||||
if (src3->flags & IR3_REG_RELATIV) {
|
||||
iassert(src3->array.offset < (1 << 10));
|
||||
cat3->rel2.src3 = reg(src3,
|
||||
IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_R |
|
||||
IR3_REG_HALF | IR3_REG_SHARED | absneg);
|
||||
cat3->rel2.src3_c = !!(src3->flags & IR3_REG_CONST);
|
||||
cat3->rel2.src3_rel = 1;
|
||||
} else if (src3->flags & IR3_REG_CONST) {
|
||||
iassert(src3->num < (1 << 12));
|
||||
cat3->c2.src3 = reg(src3,
|
||||
IR3_REG_CONST | IR3_REG_R | IR3_REG_HALF | absneg);
|
||||
cat3->c2.src3_c = 1;
|
||||
} else {
|
||||
iassert(src3->num < (1 << 11));
|
||||
cat3->src3 = reg(src3,
|
||||
IR3_REG_R | IR3_REG_HALF | IR3_REG_SHARED | absneg);
|
||||
}
|
||||
|
||||
cat3->src3_neg = !!(src3->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT));
|
||||
cat3->src3_r = !!(src3->flags & IR3_REG_R);
|
||||
|
||||
cat3->dst = reg(dst, IR3_REG_R | IR3_REG_HALF | IR3_REG_SHARED);
|
||||
cat3->repeat = instr->repeat;
|
||||
cat3->sat = !!(instr->flags & IR3_INSTR_SAT);
|
||||
cat3->ss = !!(instr->flags & IR3_INSTR_SS);
|
||||
cat3->ul = !!(instr->flags & IR3_INSTR_UL);
|
||||
cat3->dst_half = !!((src_flags ^ dst->flags) & IR3_REG_HALF);
|
||||
cat3->opc = instr->opc;
|
||||
cat3->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat3->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat3->opc_cat = 3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat4(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
struct ir3_register *dst = instr->regs[0];
|
||||
struct ir3_register *src = instr->regs[1];
|
||||
instr_cat4_t *cat4 = ptr;
|
||||
|
||||
iassert(instr->regs_count == 2);
|
||||
|
||||
if (src->flags & IR3_REG_RELATIV) {
|
||||
iassert(src->array.offset < (1 << 10));
|
||||
cat4->rel.src = reg(src,
|
||||
IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_FNEG |
|
||||
IR3_REG_FABS | IR3_REG_R | IR3_REG_HALF);
|
||||
cat4->rel.src_c = !!(src->flags & IR3_REG_CONST);
|
||||
cat4->rel.src_rel = 1;
|
||||
} else if (src->flags & IR3_REG_CONST) {
|
||||
iassert(src->num < (1 << 12));
|
||||
cat4->c.src = reg(src,
|
||||
IR3_REG_CONST | IR3_REG_FNEG | IR3_REG_FABS |
|
||||
IR3_REG_R | IR3_REG_HALF);
|
||||
cat4->c.src_c = 1;
|
||||
} else {
|
||||
iassert(src->num < (1 << 11));
|
||||
cat4->src = reg(src,
|
||||
IR3_REG_IMMED | IR3_REG_FNEG | IR3_REG_FABS |
|
||||
IR3_REG_R | IR3_REG_HALF);
|
||||
}
|
||||
|
||||
cat4->src_im = !!(src->flags & IR3_REG_IMMED);
|
||||
cat4->src_neg = !!(src->flags & IR3_REG_FNEG);
|
||||
cat4->src_abs = !!(src->flags & IR3_REG_FABS);
|
||||
cat4->src_r = !!(src->flags & IR3_REG_R);
|
||||
|
||||
cat4->dst = reg(dst, IR3_REG_R | IR3_REG_HALF);
|
||||
cat4->repeat = instr->repeat;
|
||||
cat4->sat = !!(instr->flags & IR3_INSTR_SAT);
|
||||
cat4->ss = !!(instr->flags & IR3_INSTR_SS);
|
||||
cat4->ul = !!(instr->flags & IR3_INSTR_UL);
|
||||
cat4->dst_half = !!((src->flags ^ dst->flags) & IR3_REG_HALF);
|
||||
cat4->full = ! (src->flags & IR3_REG_HALF);
|
||||
cat4->opc = instr->opc;
|
||||
cat4->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat4->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat4->opc_cat = 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat5(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
struct ir3_register *dst = instr->regs[0];
|
||||
/* To simplify things when there could be zero, one, or two args other
|
||||
* than tex/sampler idx, we use the first src reg in the ir to hold
|
||||
* samp_tex hvec2:
|
||||
*/
|
||||
struct ir3_register *src1;
|
||||
struct ir3_register *src2;
|
||||
instr_cat5_t *cat5 = ptr;
|
||||
|
||||
iassert((instr->regs_count == 1) ||
|
||||
(instr->regs_count == 2) ||
|
||||
(instr->regs_count == 3) ||
|
||||
(instr->regs_count == 4));
|
||||
|
||||
if (instr->flags & IR3_INSTR_S2EN) {
|
||||
src1 = instr->regs[2];
|
||||
src2 = instr->regs_count > 3 ? instr->regs[3] : NULL;
|
||||
} else {
|
||||
src1 = instr->regs_count > 1 ? instr->regs[1] : NULL;
|
||||
src2 = instr->regs_count > 2 ? instr->regs[2] : NULL;
|
||||
}
|
||||
|
||||
assume(src1 || !src2);
|
||||
|
||||
if (src1) {
|
||||
cat5->full = ! (src1->flags & IR3_REG_HALF);
|
||||
cat5->src1 = reg(src1, IR3_REG_HALF);
|
||||
}
|
||||
|
||||
if (src2) {
|
||||
iassert(!((src1->flags ^ src2->flags) & IR3_REG_HALF));
|
||||
cat5->src2 = reg(src2, IR3_REG_HALF);
|
||||
}
|
||||
|
||||
if (instr->flags & IR3_INSTR_B) {
|
||||
cat5->s2en_bindless.base_hi = instr->cat5.tex_base >> 1;
|
||||
cat5->base_lo = instr->cat5.tex_base & 1;
|
||||
}
|
||||
|
||||
if (instr->flags & IR3_INSTR_S2EN) {
|
||||
struct ir3_register *samp_tex = instr->regs[1];
|
||||
cat5->s2en_bindless.src3 = reg(samp_tex,
|
||||
(instr->flags & IR3_INSTR_B) ? 0 : IR3_REG_HALF);
|
||||
if (instr->flags & IR3_INSTR_B) {
|
||||
if (instr->flags & IR3_INSTR_A1EN) {
|
||||
cat5->s2en_bindless.desc_mode = CAT5_BINDLESS_A1_UNIFORM;
|
||||
} else {
|
||||
cat5->s2en_bindless.desc_mode = CAT5_BINDLESS_UNIFORM;
|
||||
}
|
||||
} else {
|
||||
/* TODO: This should probably be CAT5_UNIFORM, at least on a6xx,
|
||||
* as this is what the blob does and it is presumably faster, but
|
||||
* first we should confirm it is actually nonuniform and figure
|
||||
* out when the whole descriptor mode mechanism was introduced.
|
||||
*/
|
||||
cat5->s2en_bindless.desc_mode = CAT5_NONUNIFORM;
|
||||
}
|
||||
iassert(!(instr->cat5.samp | instr->cat5.tex));
|
||||
} else if (instr->flags & IR3_INSTR_B) {
|
||||
cat5->s2en_bindless.src3 = instr->cat5.samp;
|
||||
if (instr->flags & IR3_INSTR_A1EN) {
|
||||
cat5->s2en_bindless.desc_mode = CAT5_BINDLESS_A1_IMM;
|
||||
} else {
|
||||
cat5->s2en_bindless.desc_mode = CAT5_BINDLESS_IMM;
|
||||
}
|
||||
} else {
|
||||
cat5->norm.samp = instr->cat5.samp;
|
||||
cat5->norm.tex = instr->cat5.tex;
|
||||
}
|
||||
|
||||
cat5->dst = reg(dst, IR3_REG_R | IR3_REG_HALF);
|
||||
cat5->wrmask = dst->wrmask;
|
||||
cat5->type = instr->cat5.type;
|
||||
cat5->is_3d = !!(instr->flags & IR3_INSTR_3D);
|
||||
cat5->is_a = !!(instr->flags & IR3_INSTR_A);
|
||||
cat5->is_s = !!(instr->flags & IR3_INSTR_S);
|
||||
cat5->is_s2en_bindless = !!(instr->flags & (IR3_INSTR_S2EN | IR3_INSTR_B));
|
||||
cat5->is_o = !!(instr->flags & IR3_INSTR_O);
|
||||
cat5->is_p = !!(instr->flags & IR3_INSTR_P);
|
||||
cat5->opc = instr->opc;
|
||||
cat5->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat5->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat5->opc_cat = 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat6_a6xx(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
instr_cat6_a6xx_t *cat6 = ptr;
|
||||
|
||||
cat6->type = instr->cat6.type;
|
||||
cat6->opc = instr->opc;
|
||||
cat6->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat6->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat6->opc_cat = 6;
|
||||
|
||||
if (instr->opc == OPC_GETWID || instr->opc == OPC_GETSPID) {
|
||||
cat6->src2 = reg(instr->regs[0], 0);
|
||||
cat6->src1 = cat6->ssbo = 0;
|
||||
cat6->d = cat6->typed = cat6->type_size = 0;
|
||||
} else {
|
||||
struct ir3_register *ssbo = instr->regs[1];
|
||||
cat6->d = instr->cat6.d - (instr->opc == OPC_LDC ? 0 : 1);
|
||||
cat6->typed = instr->cat6.typed;
|
||||
cat6->type_size = instr->cat6.iim_val - 1;
|
||||
cat6->ssbo = reg(ssbo, IR3_REG_IMMED);
|
||||
|
||||
/* For unused sources in an opcode, initialize contents with the ir3
|
||||
* dest reg
|
||||
*/
|
||||
switch (instr->opc) {
|
||||
case OPC_RESINFO:
|
||||
cat6->src1 = reg(instr->regs[0], 0);
|
||||
cat6->src2 = reg(instr->regs[0], 0);
|
||||
break;
|
||||
case OPC_LDC:
|
||||
case OPC_LDIB:
|
||||
cat6->src1 = reg(instr->regs[2], 0);
|
||||
cat6->src2 = reg(instr->regs[0], 0);
|
||||
break;
|
||||
default:
|
||||
cat6->src1 = reg(instr->regs[2], 0);
|
||||
cat6->src2 = reg(instr->regs[3], 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (instr->flags & IR3_INSTR_B) {
|
||||
if (ssbo->flags & IR3_REG_IMMED) {
|
||||
cat6->desc_mode = CAT6_BINDLESS_IMM;
|
||||
} else if (instr->flags & IR3_INSTR_NONUNIF) {
|
||||
cat6->desc_mode = CAT6_BINDLESS_NONUNIFORM;
|
||||
} else {
|
||||
cat6->desc_mode = CAT6_BINDLESS_UNIFORM;
|
||||
}
|
||||
cat6->base = instr->cat6.base;
|
||||
} else {
|
||||
if (ssbo->flags & IR3_REG_IMMED) {
|
||||
cat6->desc_mode = CAT6_IMM;
|
||||
} else if (instr->flags & IR3_INSTR_NONUNIF) {
|
||||
cat6->desc_mode = CAT6_NONUNIFORM;
|
||||
} else {
|
||||
cat6->desc_mode = CAT6_UNIFORM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (instr->opc) {
|
||||
case OPC_ATOMIC_ADD:
|
||||
case OPC_ATOMIC_SUB:
|
||||
case OPC_ATOMIC_XCHG:
|
||||
case OPC_ATOMIC_INC:
|
||||
case OPC_ATOMIC_DEC:
|
||||
case OPC_ATOMIC_CMPXCHG:
|
||||
case OPC_ATOMIC_MIN:
|
||||
case OPC_ATOMIC_MAX:
|
||||
case OPC_ATOMIC_AND:
|
||||
case OPC_ATOMIC_OR:
|
||||
case OPC_ATOMIC_XOR:
|
||||
cat6->pad1 = 0x1;
|
||||
cat6->pad3 = 0x6;
|
||||
cat6->pad5 = 0x3;
|
||||
break;
|
||||
case OPC_STIB:
|
||||
case OPC_LDIB:
|
||||
case OPC_RESINFO:
|
||||
cat6->pad1 = 0x0;
|
||||
cat6->pad3 = 0x6;
|
||||
cat6->pad5 = 0x2;
|
||||
break;
|
||||
case OPC_LDC:
|
||||
case OPC_GETWID:
|
||||
case OPC_GETSPID:
|
||||
cat6->pad1 = 0x0;
|
||||
cat6->pad3 = 0x4;
|
||||
cat6->pad5 = 0x2;
|
||||
break;
|
||||
default:
|
||||
iassert(0);
|
||||
}
|
||||
cat6->pad2 = 0x0;
|
||||
cat6->pad4 = 0x0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat6(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
struct ir3_register *dst, *src1, *src2;
|
||||
instr_cat6_t *cat6 = ptr;
|
||||
|
||||
/* In a6xx we start using a new instruction encoding for some of
|
||||
* these instructions:
|
||||
*/
|
||||
if (instr->block->shader->compiler->gpu_id >= 600) {
|
||||
switch (instr->opc) {
|
||||
case OPC_ATOMIC_ADD:
|
||||
case OPC_ATOMIC_SUB:
|
||||
case OPC_ATOMIC_XCHG:
|
||||
case OPC_ATOMIC_INC:
|
||||
case OPC_ATOMIC_DEC:
|
||||
case OPC_ATOMIC_CMPXCHG:
|
||||
case OPC_ATOMIC_MIN:
|
||||
case OPC_ATOMIC_MAX:
|
||||
case OPC_ATOMIC_AND:
|
||||
case OPC_ATOMIC_OR:
|
||||
case OPC_ATOMIC_XOR:
|
||||
/* The shared variants of these still use the old encoding: */
|
||||
if (!(instr->flags & IR3_INSTR_G))
|
||||
break;
|
||||
/* fallthrough */
|
||||
case OPC_STIB:
|
||||
case OPC_LDIB:
|
||||
case OPC_LDC:
|
||||
case OPC_RESINFO:
|
||||
case OPC_GETSPID:
|
||||
case OPC_GETWID:
|
||||
return emit_cat6_a6xx(instr, ptr);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool type_full = type_size(instr->cat6.type) == 32;
|
||||
|
||||
cat6->type = instr->cat6.type;
|
||||
cat6->opc = instr->opc;
|
||||
cat6->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat6->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat6->g = !!(instr->flags & IR3_INSTR_G);
|
||||
cat6->opc_cat = 6;
|
||||
|
||||
switch (instr->opc) {
|
||||
case OPC_RESINFO:
|
||||
case OPC_RESFMT:
|
||||
iassert_type(instr->regs[0], type_full); /* dst */
|
||||
iassert_type(instr->regs[1], type_full); /* src1 */
|
||||
break;
|
||||
case OPC_L2G:
|
||||
case OPC_G2L:
|
||||
iassert_type(instr->regs[0], true); /* dst */
|
||||
iassert_type(instr->regs[1], true); /* src1 */
|
||||
break;
|
||||
case OPC_STG:
|
||||
case OPC_STL:
|
||||
case OPC_STP:
|
||||
case OPC_STLW:
|
||||
case OPC_STIB:
|
||||
/* no dst, so regs[0] is dummy */
|
||||
iassert_type(instr->regs[1], true); /* dst */
|
||||
iassert_type(instr->regs[2], type_full); /* src1 */
|
||||
iassert_type(instr->regs[3], true); /* src2 */
|
||||
break;
|
||||
default:
|
||||
iassert_type(instr->regs[0], type_full); /* dst */
|
||||
iassert_type(instr->regs[1], true); /* src1 */
|
||||
if (instr->regs_count > 2)
|
||||
iassert_type(instr->regs[2], true); /* src1 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* the "dst" for a store instruction is (from the perspective
|
||||
* of data flow in the shader, ie. register use/def, etc) in
|
||||
* fact a register that is read by the instruction, rather
|
||||
* than written:
|
||||
*/
|
||||
if (is_store(instr)) {
|
||||
iassert(instr->regs_count >= 3);
|
||||
|
||||
dst = instr->regs[1];
|
||||
src1 = instr->regs[2];
|
||||
src2 = (instr->regs_count >= 4) ? instr->regs[3] : NULL;
|
||||
} else {
|
||||
iassert(instr->regs_count >= 2);
|
||||
|
||||
dst = instr->regs[0];
|
||||
src1 = instr->regs[1];
|
||||
src2 = (instr->regs_count >= 3) ? instr->regs[2] : NULL;
|
||||
}
|
||||
|
||||
/* TODO we need a more comprehensive list about which instructions
|
||||
* can be encoded which way. Or possibly use IR3_INSTR_0 flag to
|
||||
* indicate to use the src_off encoding even if offset is zero
|
||||
* (but then what to do about dst_off?)
|
||||
*/
|
||||
if (is_atomic(instr->opc)) {
|
||||
instr_cat6ldgb_t *ldgb = ptr;
|
||||
|
||||
/* maybe these two bits both determine the instruction encoding? */
|
||||
cat6->src_off = false;
|
||||
|
||||
ldgb->d = instr->cat6.d - 1;
|
||||
ldgb->typed = instr->cat6.typed;
|
||||
ldgb->type_size = instr->cat6.iim_val - 1;
|
||||
|
||||
ldgb->dst = reg(dst, IR3_REG_R | IR3_REG_HALF);
|
||||
|
||||
if (ldgb->g) {
|
||||
struct ir3_register *src3 = instr->regs[3];
|
||||
struct ir3_register *src4 = instr->regs[4];
|
||||
|
||||
/* first src is src_ssbo: */
|
||||
iassert(src1->flags & IR3_REG_IMMED);
|
||||
ldgb->src_ssbo = src1->uim_val;
|
||||
ldgb->src_ssbo_im = 0x1;
|
||||
|
||||
ldgb->src1 = reg(src2, IR3_REG_IMMED);
|
||||
ldgb->src1_im = !!(src2->flags & IR3_REG_IMMED);
|
||||
ldgb->src2 = reg(src3, IR3_REG_IMMED);
|
||||
ldgb->src2_im = !!(src3->flags & IR3_REG_IMMED);
|
||||
|
||||
ldgb->src3 = reg(src4, 0);
|
||||
ldgb->pad0 = 0x1;
|
||||
} else {
|
||||
ldgb->src1 = reg(src1, IR3_REG_IMMED);
|
||||
ldgb->src1_im = !!(src1->flags & IR3_REG_IMMED);
|
||||
ldgb->src2 = reg(src2, IR3_REG_IMMED);
|
||||
ldgb->src2_im = !!(src2->flags & IR3_REG_IMMED);
|
||||
ldgb->pad0 = 0x1;
|
||||
ldgb->src_ssbo_im = 0x0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (instr->opc == OPC_LDGB) {
|
||||
struct ir3_register *src3 = instr->regs[3];
|
||||
instr_cat6ldgb_t *ldgb = ptr;
|
||||
|
||||
/* maybe these two bits both determine the instruction encoding? */
|
||||
cat6->src_off = false;
|
||||
|
||||
ldgb->d = instr->cat6.d - 1;
|
||||
ldgb->typed = instr->cat6.typed;
|
||||
ldgb->type_size = instr->cat6.iim_val - 1;
|
||||
|
||||
ldgb->dst = reg(dst, IR3_REG_R | IR3_REG_HALF);
|
||||
|
||||
/* first src is src_ssbo: */
|
||||
iassert(src1->flags & IR3_REG_IMMED);
|
||||
ldgb->src_ssbo = src1->uim_val;
|
||||
|
||||
/* then next two are src1/src2: */
|
||||
ldgb->src1 = reg(src2, IR3_REG_IMMED);
|
||||
ldgb->src1_im = !!(src2->flags & IR3_REG_IMMED);
|
||||
ldgb->src2 = reg(src3, IR3_REG_IMMED);
|
||||
ldgb->src2_im = !!(src3->flags & IR3_REG_IMMED);
|
||||
|
||||
ldgb->pad0 = 0x0;
|
||||
ldgb->src_ssbo_im = true;
|
||||
|
||||
return 0;
|
||||
} else if (instr->opc == OPC_RESINFO) {
|
||||
instr_cat6ldgb_t *ldgb = ptr;
|
||||
|
||||
ldgb->d = instr->cat6.d - 1;
|
||||
|
||||
ldgb->dst = reg(dst, IR3_REG_R | IR3_REG_HALF);
|
||||
|
||||
/* first src is src_ssbo: */
|
||||
ldgb->src_ssbo = reg(src1, IR3_REG_IMMED);
|
||||
ldgb->src_ssbo_im = !!(src1->flags & IR3_REG_IMMED);
|
||||
|
||||
return 0;
|
||||
} else if ((instr->opc == OPC_STGB) || (instr->opc == OPC_STIB)) {
|
||||
struct ir3_register *src3 = instr->regs[4];
|
||||
instr_cat6stgb_t *stgb = ptr;
|
||||
|
||||
/* maybe these two bits both determine the instruction encoding? */
|
||||
cat6->src_off = true;
|
||||
stgb->pad3 = 0x2;
|
||||
|
||||
stgb->d = instr->cat6.d - 1;
|
||||
stgb->typed = instr->cat6.typed;
|
||||
stgb->type_size = instr->cat6.iim_val - 1;
|
||||
|
||||
/* first src is dst_ssbo: */
|
||||
iassert(dst->flags & IR3_REG_IMMED);
|
||||
stgb->dst_ssbo = dst->uim_val;
|
||||
|
||||
/* then src1/src2/src3: */
|
||||
stgb->src1 = reg(src1, 0);
|
||||
stgb->src2 = reg(src2, IR3_REG_IMMED);
|
||||
stgb->src2_im = !!(src2->flags & IR3_REG_IMMED);
|
||||
stgb->src3 = reg(src3, IR3_REG_IMMED);
|
||||
stgb->src3_im = !!(src3->flags & IR3_REG_IMMED);
|
||||
|
||||
return 0;
|
||||
} else if ((instr->opc == OPC_LDG) || (instr->opc == OPC_LDL) ||
|
||||
(instr->opc == OPC_LDLW) || (instr->opc == OPC_LDP)) {
|
||||
struct ir3_register *src3 = instr->regs[3];
|
||||
instr_cat6a_t *cat6a = ptr;
|
||||
|
||||
cat6->src_off = true;
|
||||
|
||||
if (instr->opc == OPC_LDG) {
|
||||
/* For LDG src1 can not be immediate, so src1_imm is redundant and
|
||||
* instead used to signal whether (when true) 'off' is a 32 bit
|
||||
* register or an immediate offset.
|
||||
*/
|
||||
cat6a->src1 = reg(src1, 0);
|
||||
cat6a->src1_im = !(src2->flags & IR3_REG_IMMED);
|
||||
cat6a->off = reg(src2, IR3_REG_IMMED);
|
||||
} else {
|
||||
cat6a->src1 = reg(src1, IR3_REG_IMMED);
|
||||
cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED);
|
||||
cat6a->off = reg(src2, IR3_REG_IMMED);
|
||||
iassert(src2->flags & IR3_REG_IMMED);
|
||||
}
|
||||
|
||||
/* Num components */
|
||||
cat6a->src3 = reg(src3, IR3_REG_IMMED);
|
||||
cat6a->src3_im = true;
|
||||
} else {
|
||||
instr_cat6b_t *cat6b = ptr;
|
||||
|
||||
cat6->src_off = false;
|
||||
|
||||
cat6b->src1 = reg(src1, IR3_REG_IMMED | IR3_REG_HALF);
|
||||
cat6b->src1_im = !!(src1->flags & IR3_REG_IMMED);
|
||||
if (src2) {
|
||||
cat6b->src2 = reg(src2, IR3_REG_IMMED);
|
||||
cat6b->src2_im = !!(src2->flags & IR3_REG_IMMED);
|
||||
}
|
||||
}
|
||||
|
||||
if (instr->cat6.dst_offset || (instr->opc == OPC_STG) ||
|
||||
(instr->opc == OPC_STL) || (instr->opc == OPC_STLW) ||
|
||||
(instr->opc == OPC_STP)) {
|
||||
instr_cat6c_t *cat6c = ptr;
|
||||
cat6->dst_off = true;
|
||||
cat6c->dst = reg(dst, IR3_REG_R | IR3_REG_HALF);
|
||||
|
||||
if (instr->flags & IR3_INSTR_G) {
|
||||
struct ir3_register *src3 = instr->regs[4];
|
||||
cat6c->off = reg(src3, IR3_REG_R | IR3_REG_HALF);
|
||||
if (src3->flags & IR3_REG_IMMED) {
|
||||
/* Immediate offsets are in bytes... */
|
||||
cat6->g = false;
|
||||
cat6c->off *= 4;
|
||||
}
|
||||
} else {
|
||||
cat6c->off = instr->cat6.dst_offset;
|
||||
cat6c->off_high = instr->cat6.dst_offset >> 8;
|
||||
}
|
||||
} else {
|
||||
instr_cat6d_t *cat6d = ptr;
|
||||
cat6->dst_off = false;
|
||||
cat6d->dst = reg(dst, IR3_REG_R | IR3_REG_HALF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_cat7(struct ir3_instruction *instr, void *ptr)
|
||||
{
|
||||
instr_cat7_t *cat7 = ptr;
|
||||
|
||||
cat7->ss = !!(instr->flags & IR3_INSTR_SS);
|
||||
cat7->w = instr->cat7.w;
|
||||
cat7->r = instr->cat7.r;
|
||||
cat7->l = instr->cat7.l;
|
||||
cat7->g = instr->cat7.g;
|
||||
cat7->opc = instr->opc;
|
||||
cat7->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
|
||||
cat7->sync = !!(instr->flags & IR3_INSTR_SY);
|
||||
cat7->opc_cat = 7;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*emit[])(struct ir3_instruction *instr, void *ptr) = {
|
||||
emit_cat0, emit_cat1, emit_cat2, emit_cat3, emit_cat4, emit_cat5, emit_cat6,
|
||||
emit_cat7,
|
||||
};
|
||||
|
||||
static void
|
||||
collect_reg_info(struct ir3_instruction *instr, struct ir3_register *reg,
|
||||
struct ir3_info *info)
|
||||
|
|
@ -997,8 +134,7 @@ ir3_collect_info(struct ir3_shader_variant *v)
|
|||
* doesn't try to decode the following data as instructions (such as the
|
||||
* next stage's shader in turnip)
|
||||
*/
|
||||
info->size = MAX2(v->instrlen * compiler->instr_align, instr_count + 4) *
|
||||
sizeof(instr_t);
|
||||
info->size = MAX2(v->instrlen * compiler->instr_align, instr_count + 4) * 8;
|
||||
info->sizedwords = info->size / 4;
|
||||
|
||||
foreach_block (block, &shader->block_list) {
|
||||
|
|
@ -1066,30 +202,6 @@ ir3_collect_info(struct ir3_shader_variant *v)
|
|||
}
|
||||
}
|
||||
|
||||
void * ir3_assemble(struct ir3_shader_variant *v)
|
||||
{
|
||||
uint32_t *ptr, *dwords;
|
||||
const struct ir3_info *info = &v->info;
|
||||
struct ir3 *shader = v->ir;
|
||||
|
||||
ptr = dwords = rzalloc_size(v, info->size);
|
||||
|
||||
foreach_block (block, &shader->block_list) {
|
||||
foreach_instr (instr, &block->instr_list) {
|
||||
int ret = emit[opc_cat(instr->opc)](instr, dwords);
|
||||
if (ret)
|
||||
goto fail;
|
||||
dwords += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
|
||||
fail:
|
||||
ralloc_free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ir3_register * reg_create(struct ir3 *shader,
|
||||
int num, int flags)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -581,7 +581,6 @@ struct ir3 * ir3_create(struct ir3_compiler *compiler, struct ir3_shader_variant
|
|||
void ir3_destroy(struct ir3 *shader);
|
||||
|
||||
void ir3_collect_info(struct ir3_shader_variant *v);
|
||||
void * ir3_assemble(struct ir3_shader_variant *v);
|
||||
void * ir3_alloc(struct ir3 *shader, int sz);
|
||||
|
||||
struct ir3_block * ir3_block_create(struct ir3 *shader);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue