diff --git a/src/gallium/drivers/freedreno/ir3/instr-a3xx.h b/src/gallium/drivers/freedreno/ir3/instr-a3xx.h index b7e19c8ae39..c685fb15666 100644 --- a/src/gallium/drivers/freedreno/ir3/instr-a3xx.h +++ b/src/gallium/drivers/freedreno/ir3/instr-a3xx.h @@ -204,9 +204,6 @@ typedef enum { /* branches/flow control */ OPC_META_FLOW = 4, OPC_META_PHI = 5, - /* relative addressing */ - OPC_META_DEREF = 6, - } opc_t; diff --git a/src/gallium/drivers/freedreno/ir3/ir3.h b/src/gallium/drivers/freedreno/ir3/ir3.h index 3d3ad07c330..30932854884 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3.h +++ b/src/gallium/drivers/freedreno/ir3/ir3.h @@ -79,18 +79,19 @@ struct ir3_register { * the component is in the low two bits of the reg #, so * rN.x becomes: (N << 2) | x */ - int num; + int num; /* immediate: */ - int iim_val; - float fim_val; + int iim_val; + float fim_val; /* relative: */ - int offset; - /* for IR3_REG_SSA, src registers contain ptr back to - * assigning instruction. - */ - struct ir3_instruction *instr; + int offset; }; + /* for IR3_REG_SSA, src registers contain ptr back to + * assigning instruction. + */ + struct ir3_instruction *instr; + union { /* used for cat5 instructions, but also for internal/IR level * tracking of what registers are read/written by an instruction. @@ -209,9 +210,6 @@ struct ir3_instruction { struct { struct ir3_block *block; } inout; - struct { - int off; /* offset relative to addr reg */ - } deref; /* XXX keep this as big as all other union members! */ uint32_t info[3]; @@ -260,6 +258,12 @@ struct ir3_instruction { struct ir3_instruction *left, *right; uint16_t left_cnt, right_cnt; } cp; + + /* an instruction can reference at most one address register amongst + * it's src/dst registers. Beyond that, you need to insert mov's. + */ + struct ir3_instruction *address; + struct ir3_instruction *next; #ifdef DEBUG uint32_t serialno; @@ -445,11 +449,6 @@ static inline bool is_meta(struct ir3_instruction *instr) return (instr->category == -1); } -static inline bool is_addr(struct ir3_instruction *instr) -{ - return is_meta(instr) && (instr->opc == OPC_META_DEREF); -} - static inline bool writes_addr(struct ir3_instruction *instr) { if (instr->regs_count > 0) { @@ -499,11 +498,15 @@ static inline bool reg_gpr(struct ir3_register *r) static inline unsigned __ssa_src_cnt(struct ir3_instruction *instr) { + if (instr->address) + return instr->regs_count + 1; return instr->regs_count; } static inline struct ir3_instruction * __ssa_src_n(struct ir3_instruction *instr, unsigned n) { + if (n == (instr->regs_count + 0)) + return instr->address; return ssa(instr->regs[n]); } diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c index 8551eeb11f7..4b73390fd33 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c @@ -624,16 +624,18 @@ ssa_src(struct ir3_compile_context *ctx, struct ir3_register *reg, * we must generate a fanin instruction to collect all possible * array elements that the instruction could address together: */ - unsigned i, j, aid = src_array_id(ctx, src); + unsigned aid = src_array_id(ctx, src); + unsigned first = ctx->array[aid].first; + unsigned last = ctx->array[aid].last; + unsigned off = src->Index - first; /* vec4 offset */ + unsigned i, j; + + reg->size = 4 * (1 + last - first); + reg->offset = regid(off, chan); if (ctx->array[aid].fanin) { instr = ctx->array[aid].fanin; } else { - unsigned first, last; - - first = ctx->array[aid].first; - last = ctx->array[aid].last; - instr = ir3_instr_create2(ctx->block, -1, OPC_META_FI, 1 + (4 * (last + 1 - first))); ir3_reg_create(instr, 0, 0); @@ -756,7 +758,6 @@ add_src_reg_wrmask(struct ir3_compile_context *ctx, { unsigned flags = 0, num = 0; struct ir3_register *reg; - struct ir3_instruction *orig = NULL; switch (src->File) { case TGSI_FILE_IMMEDIATE: @@ -815,28 +816,15 @@ add_src_reg_wrmask(struct ir3_compile_context *ctx, /* shouldn't happen, and we can't cope with it below: */ compile_assert(ctx, wrmask == 0x1); - /* wrap in a meta-deref to track both the src and address: */ - orig = instr; + compile_assert(ctx, ctx->block->address); + if (instr->address) + compile_assert(ctx, ctx->block->address == instr->address); - instr = ir3_instr_create(ctx->block, -1, OPC_META_DEREF); - ir3_reg_create(instr, 0, 0); - ir3_reg_create(instr, 0, IR3_REG_SSA)->instr = ctx->block->address; - - if (src->File != TGSI_FILE_CONSTANT) { - unsigned aid = src_array_id(ctx, src); - unsigned off = src->Index - ctx->array[aid].first; /* vec4 offset */ - instr->deref.off = regid(off, chan); - } + instr->address = ctx->block->address; } reg = ir3_reg_create(instr, regid(num, chan), flags); - - if (src->Indirect && (src->File != TGSI_FILE_CONSTANT)) { - unsigned aid = src_array_id(ctx, src); - reg->size = 4 * (1 + ctx->array[aid].last - ctx->array[aid].first); - } else { - reg->wrmask = wrmask; - } + reg->wrmask = wrmask; if (wrmask == 0x1) { /* normal case */ @@ -872,14 +860,6 @@ add_src_reg_wrmask(struct ir3_compile_context *ctx, reg->instr = collect; } - if (src->Indirect) { - unsigned size = reg->size; - - reg = ir3_reg_create(orig, 0, flags | IR3_REG_SSA); - reg->instr = instr; - reg->size = size; - } - return reg; } diff --git a/src/gallium/drivers/freedreno/ir3/ir3_cp.c b/src/gallium/drivers/freedreno/ir3/ir3_cp.c index b70aba956c9..898ed70abeb 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_cp.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_cp.c @@ -95,6 +95,9 @@ instr_cp(struct ir3_instruction *instr) foreach_src(reg, instr) if (reg->flags & IR3_REG_SSA) reg->instr = instr_cp(reg->instr); + + if (instr->address) + instr->address = instr_cp(instr->address); } return instr; diff --git a/src/gallium/drivers/freedreno/ir3/ir3_dump.c b/src/gallium/drivers/freedreno/ir3/ir3_dump.c index 42a38d7511e..a846777b879 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_dump.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_dump.c @@ -58,9 +58,6 @@ static void dump_instr_name(struct ir3_dump_ctx *ctx, case OPC_META_PHI: fprintf(ctx->f, "Φ"); break; - case OPC_META_DEREF: - fprintf(ctx->f, "(*)"); - break; default: /* shouldn't hit here.. just for debugging: */ switch (instr->opc) { @@ -171,8 +168,7 @@ static void dump_instr(struct ir3_dump_ctx *ctx, ir3_block_dump(ctx, instr->flow.else_block, "else"); if (reg->flags & IR3_REG_SSA) dump_instr(ctx, reg->instr); - } else if ((instr->opc == OPC_META_PHI) || - (instr->opc == OPC_META_DEREF)) { + } else if (instr->opc == OPC_META_PHI) { /* treat like a normal instruction: */ ir3_instr_dump(ctx, instr); } @@ -234,8 +230,7 @@ static void dump_link2(struct ir3_dump_ctx *ctx, printdef(ctx, defer, "output%lx::w -> %s", PTRID(instr->inout.block), instr->regs[0]->num, target); - } else if ((instr->opc == OPC_META_PHI) || - (instr->opc == OPC_META_DEREF)) { + } else if (instr->opc == OPC_META_PHI) { /* treat like a normal instruction: */ printdef(ctx, defer, "instr%lx: -> %s", PTRID(instr), target); } @@ -412,6 +407,13 @@ ir3_dump_instr_single(struct ir3_instruction *instr) dump_reg_name(&ctx, reg, !!i); } + if (instr->address) { + fprintf(ctx.f, ", address=_"); + fprintf(ctx.f, "["); + dump_instr_name(&ctx, instr->address); + fprintf(ctx.f, "]"); + } + if (is_meta(instr) && (instr->opc == OPC_META_FO)) printf(", off=%d", instr->fo.off); diff --git a/src/gallium/drivers/freedreno/ir3/ir3_ra.c b/src/gallium/drivers/freedreno/ir3/ir3_ra.c index 03180b13b18..0f6d40f5a7c 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_ra.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_ra.c @@ -357,6 +357,11 @@ static void instr_assign(struct ir3_ra_ctx *ctx, static void instr_assign_src(struct ir3_ra_ctx *ctx, struct ir3_instruction *instr, unsigned r, unsigned name) { + struct ir3_register *reg = instr->regs[r]; + + if (reg->flags & IR3_REG_RELATIV) + name += reg->offset; + reg_assign(instr, r, name); if (is_meta(instr)) { @@ -372,14 +377,6 @@ static void instr_assign_src(struct ir3_ra_ctx *ctx, case OPC_META_FI: instr_assign(ctx, instr, name - (r - 1)); return; - case OPC_META_DEREF: - /* first arg of meta:deref is the addr reg (do not - * propagate), 2nd is actual src (fanin) which does - * get propagated) - */ - if (r == 2) - instr_assign(ctx, instr, name + instr->deref.off); - break; default: break; } @@ -392,6 +389,9 @@ static void instr_assign(struct ir3_ra_ctx *ctx, struct ir3_instruction *n, *src; struct ir3_register *reg = instr->regs[0]; + if ((reg->flags & IR3_REG_RELATIV)) + name += reg->offset; + /* check if already assigned: */ if (!(reg->flags & IR3_REG_SSA)) { /* ... and if so, sanity check: */ @@ -484,9 +484,6 @@ static void instr_alloc_and_assign(struct ir3_ra_ctx *ctx, /* allocate register(s): */ if (name >= 0) { /* already partially assigned, just finish the job */ - } else if (is_addr(instr)) { - debug_assert(!instr->cp.right); - name = instr->regs[2]->num + instr->deref.off; } else if (reg_gpr(dst)) { int size; /* number of consecutive registers to assign: */ diff --git a/src/gallium/drivers/freedreno/ir3/ir3_sched.c b/src/gallium/drivers/freedreno/ir3/ir3_sched.c index 1288452d29d..909ecc23449 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_sched.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_sched.c @@ -292,16 +292,7 @@ static struct ir3_instruction * reverse(struct ir3_instruction *instr) static bool uses_current_addr(struct ir3_sched_ctx *ctx, struct ir3_instruction *instr) { - struct ir3_instruction *src; - foreach_ssa_src(src, instr) { - if (is_addr(src)) { - struct ir3_instruction *addr = - src->regs[1]->instr; /* the mova */ - if (ctx->addr == addr) - return true; - } - } - return false; + return instr->address && (ctx->addr == instr->address); } static bool uses_current_pred(struct ir3_sched_ctx *ctx,