From 17754b70d78649f29e25dfe938de91d64dbf5ebf Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 4 Feb 2015 16:07:44 -0500 Subject: [PATCH] freedreno/ir3: drop deref nodes The meta-deref instruction doesn't really do what we need for relative destination. Instead, since each instruction can reference at most a single address value, track the dependency on the address register via instr->address. This lets us express the dependency regardless of whether it is used for dst and/or src. The foreach_ssa_src{_n} iterator macros now also iterates the address register so, at least in SSA form, the address register behaves as an additional virtual src to the instruction. Which is pretty much what we want, as far as scheduling/etc. TODO: For now, the foreach_src{_n} iterators are unchanged. We could wrap the address in an ir3_register and make the foreach_src_{_n} iterators behave the same way. But that seems unnecessary at this point, since we mainly care about the address dependency when in SSA form. Signed-off-by: Rob Clark --- .../drivers/freedreno/ir3/instr-a3xx.h | 3 -- src/gallium/drivers/freedreno/ir3/ir3.h | 35 +++++++------- .../drivers/freedreno/ir3/ir3_compiler.c | 46 ++++++------------- src/gallium/drivers/freedreno/ir3/ir3_cp.c | 3 ++ src/gallium/drivers/freedreno/ir3/ir3_dump.c | 16 ++++--- src/gallium/drivers/freedreno/ir3/ir3_ra.c | 19 ++++---- src/gallium/drivers/freedreno/ir3/ir3_sched.c | 11 +---- 7 files changed, 53 insertions(+), 80 deletions(-) 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; - - 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; + compile_assert(ctx, ctx->block->address); + if (instr->address) + compile_assert(ctx, ctx->block->address == instr->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, -- 2.30.2