From 9af795d9b984055042ef4ed33c6d3f2021be778a Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Fri, 18 Jun 2021 12:01:18 +0200 Subject: [PATCH] ir3: Make ir3_instruction::address a normal register This fixes an annoying mismatch in the indices between foreach_ssa_src_n and ir3_delayslots(), and lets us remove a bunch of other special cases. Part-of: --- src/freedreno/ir3/ir3.c | 15 ++++++++----- src/freedreno/ir3/ir3.h | 33 +++++++++++----------------- src/freedreno/ir3/ir3_context.c | 2 -- src/freedreno/ir3/ir3_cp.c | 16 +++++++------- src/freedreno/ir3/ir3_cp_postsched.c | 2 +- src/freedreno/ir3/ir3_delay.c | 16 +++++--------- src/freedreno/ir3/ir3_postsched.c | 10 ++------- src/freedreno/ir3/ir3_print.c | 7 ------ src/freedreno/ir3/ir3_sched.c | 10 ++++----- src/freedreno/ir3/ir3_validate.c | 2 ++ 10 files changed, 44 insertions(+), 69 deletions(-) diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c index 72e58e8a727..14aa704ab75 100644 --- a/src/freedreno/ir3/ir3.c +++ b/src/freedreno/ir3/ir3.c @@ -390,9 +390,9 @@ unsigned ir3_block_get_pred_index(struct ir3_block *block, struct ir3_block *pre static struct ir3_instruction *instr_create(struct ir3_block *block, opc_t opc, int nreg) { - /* Add an extra source for array destinations */ + /* Add extra sources for array destinations and the address reg */ if (1 <= opc_cat(opc)) - nreg++; + nreg += 2; struct ir3_instruction *instr; unsigned sz = sizeof(*instr) + (nreg * sizeof(instr->regs[0])); char *ptr = ir3_alloc(block->shader, sz); @@ -494,13 +494,14 @@ void ir3_instr_set_address(struct ir3_instruction *instr, struct ir3_instruction *addr) { - if (instr->address != addr) { + if (!instr->address) { struct ir3 *ir = instr->block->shader; - debug_assert(!instr->address); debug_assert(instr->block == addr->block); - instr->address = addr; + instr->address = ir3_reg_create(instr, addr->regs[0]->num, + addr->regs[0]->flags & ~IR3_REG_DEST); + instr->address->def = addr->regs[0]; debug_assert(reg_num(addr->regs[0]) == REG_A0); unsigned comp = reg_comp(addr->regs[0]); if (comp == 0) { @@ -509,6 +510,8 @@ ir3_instr_set_address(struct ir3_instruction *instr, debug_assert(comp == 1); array_insert(ir, ir->a1_users, instr); } + } else { + debug_assert(instr->address->def->instr == addr); } } @@ -707,7 +710,7 @@ ir3_valid_flags(struct ir3_instruction *instr, unsigned n, */ if (instr->regs[n+1]->flags & IR3_REG_SSA) { struct ir3_instruction *src = ssa(instr->regs[n+1]); - if (src->address->block != instr->block) + if (src->address->def->instr->block != instr->block) return false; } } diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index f949ba32535..cb82eede37c 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -390,7 +390,7 @@ struct ir3_instruction { * * NOTE: do not write this directly, use ir3_instr_set_address() */ - struct ir3_instruction *address; + struct ir3_register *address; /* Tracking for additional dependent instructions. Used to handle * barriers, WAR hazards for arrays/SSBOs/etc. @@ -1026,10 +1026,10 @@ static inline struct ir3_instruction *ssa(struct ir3_register *reg) return NULL; } -static inline bool conflicts(struct ir3_instruction *a, - struct ir3_instruction *b) +static inline bool conflicts(struct ir3_register *a, + struct ir3_register *b) { - return (a && b) && (a != b); + return (a && b) && (a->def != b->def); } static inline bool reg_gpr(struct ir3_register *r) @@ -1352,33 +1352,26 @@ ir3_try_swap_signedness(opc_t opc, bool *can_swap) static inline unsigned __ssa_src_cnt(struct ir3_instruction *instr) { - unsigned cnt = instr->regs_count + instr->deps_count; - if (instr->address) - cnt++; - return cnt; + return instr->regs_count + instr->deps_count; +} + +static inline bool __is_false_dep(struct ir3_instruction *instr, unsigned n) +{ + if (n >= instr->regs_count) + return true; + return false; } static inline struct ir3_instruction ** __ssa_srcp_n(struct ir3_instruction *instr, unsigned n) { - if (n == (instr->regs_count + instr->deps_count)) - return &instr->address; - if (n >= instr->regs_count) + if (__is_false_dep(instr, n)) return &instr->deps[n - instr->regs_count]; if (ssa(instr->regs[n])) return &instr->regs[n]->def->instr; return NULL; } -static inline bool __is_false_dep(struct ir3_instruction *instr, unsigned n) -{ - if (n == (instr->regs_count + instr->deps_count)) - return false; - if (n >= instr->regs_count) - return true; - return false; -} - #define foreach_ssa_srcp_n(__srcp, __n, __instr) \ for (struct ir3_instruction **__srcp = (void *)~0; __srcp; __srcp = NULL) \ for (unsigned __cnt = __ssa_src_cnt(__instr), __n = 0; __n < __cnt; __n++) \ diff --git a/src/freedreno/ir3/ir3_context.c b/src/freedreno/ir3/ir3_context.c index 8fdaa239c4b..1a92497cdf3 100644 --- a/src/freedreno/ir3/ir3_context.c +++ b/src/freedreno/ir3/ir3_context.c @@ -447,7 +447,6 @@ create_addr0(struct ir3_block *block, struct ir3_instruction *src, int align) instr = ir3_MOV(block, instr, TYPE_S16); instr->regs[0]->num = regid(REG_A0, 0); - instr->regs[0]->flags &= ~IR3_REG_SSA; return instr; } @@ -458,7 +457,6 @@ create_addr1(struct ir3_block *block, unsigned const_val) struct ir3_instruction *immed = create_immed_typed(block, const_val, TYPE_U16); struct ir3_instruction *instr = ir3_MOV(block, immed, TYPE_U16); instr->regs[0]->num = regid(REG_A0, 1); - instr->regs[0]->flags &= ~IR3_REG_SSA; return instr; } diff --git a/src/freedreno/ir3/ir3_cp.c b/src/freedreno/ir3/ir3_cp.c index bed9efe082f..d5acba5c917 100644 --- a/src/freedreno/ir3/ir3_cp.c +++ b/src/freedreno/ir3/ir3_cp.c @@ -99,7 +99,7 @@ static bool is_foldable_double_cmp(struct ir3_instruction *cmp) (cmp->regs[2]->flags & IR3_REG_IMMED) && (cmp->regs[2]->iim_val == 0) && (cmp->cat2.condition == IR3_COND_NE) && - (!cond->address || (cmp->block == cond->address->block)); + (!cond->address || cond->address->def->instr->block == cmp->block); } /* propagate register flags from src to dst.. negates need special @@ -419,7 +419,7 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr, instr->regs[n+1] = src_reg; if (src_reg->flags & IR3_REG_RELATIV) - ir3_instr_set_address(instr, reg->def->instr->address); + ir3_instr_set_address(instr, reg->def->instr->address->def->instr); return true; } @@ -526,16 +526,15 @@ instr_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr) if (is_meta(instr) && (src->opc != OPC_MOV)) continue; + /* Don't CP mova and mova1 into their users */ + if (writes_addr0(src) || writes_addr1(src)) + continue; + progress |= reg_cp(ctx, instr, reg, n); ctx->progress |= progress; } } while (progress); - if (instr->address) { - instr_cp(ctx, instr->address); - ir3_instr_set_address(instr, eliminate_output_mov(ctx, instr->address)); - } - /* After folding a mov's source we may wind up with a type-converting mov * of an immediate. This happens e.g. with texture descriptors, since we * narrow the descriptor (which may be a constant) to a half-reg in ir3. @@ -574,7 +573,8 @@ instr_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr) instr->opc = cond->opc; instr->flags = cond->flags; instr->cat2 = cond->cat2; - ir3_instr_set_address(instr, cond->address); + if (cond->address) + ir3_instr_set_address(instr, cond->address->def->instr); instr->regs[1] = ir3_reg_clone(ctx->shader, cond->regs[1]); instr->regs[2] = ir3_reg_clone(ctx->shader, cond->regs[2]); instr->barrier_class |= cond->barrier_class; diff --git a/src/freedreno/ir3/ir3_cp_postsched.c b/src/freedreno/ir3/ir3_cp_postsched.c index dc0e1c588bb..b49a62a135d 100644 --- a/src/freedreno/ir3/ir3_cp_postsched.c +++ b/src/freedreno/ir3/ir3_cp_postsched.c @@ -188,7 +188,7 @@ instr_cp_postsched(struct ir3_instruction *mov) */ if (removed) { if (src->flags & IR3_REG_RELATIV) - ir3_instr_set_address(use, mov->address); + ir3_instr_set_address(use, mov->address->def->instr); util_dynarray_append(&newdeps, struct ir3_instruction *, use); diff --git a/src/freedreno/ir3/ir3_delay.c b/src/freedreno/ir3/ir3_delay.c index 7a310f236e4..3dbc0f768eb 100644 --- a/src/freedreno/ir3/ir3_delay.c +++ b/src/freedreno/ir3/ir3_delay.c @@ -194,11 +194,6 @@ ir3_delay_calc_prera(struct ir3_block *block, struct ir3_instruction *instr) delay = MAX2(delay, d); } - if (instr->address) { - unsigned d = delay_calc_srcn_prera(block, instr->address, instr, 0); - delay = MAX2(delay, d); - } - return delay; } @@ -231,7 +226,11 @@ delay_calc_srcn_postra(struct ir3_instruction *assigner, struct ir3_instruction bool mismatched_half = (src->flags & IR3_REG_HALF) != (dst->flags & IR3_REG_HALF); - if (!mergedregs && mismatched_half) + /* In the mergedregs case or when the register is a special register, + * half-registers do not alias with full registers. + */ + if ((!mergedregs || is_reg_special(src) || is_reg_special(dst)) && + mismatched_half) return 0; unsigned src_start = post_ra_reg_num(src) * reg_elem_size(src); @@ -318,11 +317,6 @@ delay_calc_postra(struct ir3_block *block, unsigned new_delay = 0; - if (consumer->address == assigner) { - unsigned addr_delay = ir3_delayslots(assigner, consumer, 0, soft); - new_delay = MAX2(new_delay, addr_delay); - } - if (dest_regs(assigner) != 0) { foreach_src_n (src, n, consumer) { if (src->flags & (IR3_REG_IMMED | IR3_REG_CONST)) diff --git a/src/freedreno/ir3/ir3_postsched.c b/src/freedreno/ir3/ir3_postsched.c index cf6bec512b5..3fbe97946ca 100644 --- a/src/freedreno/ir3/ir3_postsched.c +++ b/src/freedreno/ir3/ir3_postsched.c @@ -408,9 +408,8 @@ add_single_reg_dep(struct ir3_postsched_deps_state *state, * * If non-negative, then this adds a dependency on a source register, and * src_n is the index passed into ir3_delayslots() for calculating the delay: - * 0 means this is for an address source, non-0 corresponds to - * node->instr->regs[src_n]. If negative, then this is for a destination - * register. + * If positive, corresponds to node->instr->regs[src_n]. If negative, then + * this is for a destination register. */ static void add_reg_dep(struct ir3_postsched_deps_state *state, @@ -461,11 +460,6 @@ calculate_deps(struct ir3_postsched_deps_state *state, } } - if (node->instr->address) { - add_reg_dep(state, node, node->instr->address->regs[0], - node->instr->address->regs[0]->num, 0); - } - if (dest_regs(node->instr) == 0) return; diff --git a/src/freedreno/ir3/ir3_print.c b/src/freedreno/ir3/ir3_print.c index 2ae241ba30f..a6d0b0d9786 100644 --- a/src/freedreno/ir3/ir3_print.c +++ b/src/freedreno/ir3/ir3_print.c @@ -297,13 +297,6 @@ print_instr(struct log_stream *stream, struct ir3_instruction *instr, int lvl) } } - if (instr->address) { - mesa_log_stream_printf(stream, ", address=_"); - mesa_log_stream_printf(stream, "["); - print_instr_name(stream, instr->address, false); - mesa_log_stream_printf(stream, "]"); - } - if (instr->opc == OPC_META_SPLIT) { mesa_log_stream_printf(stream, ", off=%d", instr->split.off); } else if (instr->opc == OPC_META_TEX_PREFETCH) { diff --git a/src/freedreno/ir3/ir3_sched.c b/src/freedreno/ir3/ir3_sched.c index a5509afb4e6..5a44ebe1bf8 100644 --- a/src/freedreno/ir3/ir3_sched.c +++ b/src/freedreno/ir3/ir3_sched.c @@ -381,7 +381,7 @@ check_instr(struct ir3_sched_ctx *ctx, struct ir3_sched_notes *notes, struct ir3_instruction *indirect = ir->a0_users[i]; if (!indirect) continue; - if (indirect->address != instr) + if (indirect->address->def != instr->regs[0]) continue; ready = could_sched(indirect, instr); } @@ -398,7 +398,7 @@ check_instr(struct ir3_sched_ctx *ctx, struct ir3_sched_notes *notes, struct ir3_instruction *indirect = ir->a1_users[i]; if (!indirect) continue; - if (indirect->address != instr) + if (indirect->address->def != instr->regs[0]) continue; ready = could_sched(indirect, instr); } @@ -870,13 +870,13 @@ split_addr(struct ir3_sched_ctx *ctx, struct ir3_instruction **addr, /* remap remaining instructions using current addr * to new addr: */ - if (indirect->address == *addr) { + if (indirect->address->def == (*addr)->regs[0]) { if (!new_addr) { new_addr = split_instr(ctx, *addr); /* original addr is scheduled, but new one isn't: */ new_addr->flags &= ~IR3_INSTR_MARK; } - indirect->address = new_addr; + indirect->address->def = new_addr->regs[0]; /* don't need to remove old dag edge since old addr is * already scheduled: */ @@ -984,8 +984,6 @@ sched_node_add_dep(struct ir3_instruction *instr, struct ir3_instruction *src, i unsigned d = 0; if (i < instr->regs_count) d = ir3_delayslots(src, instr, i + 1, true); - else if (src == instr->address) - d = ir3_delayslots(src, instr, 0, true); n->delay = MAX2(n->delay, d); } diff --git a/src/freedreno/ir3/ir3_validate.c b/src/freedreno/ir3/ir3_validate.c index 7100cb392f7..06f85abf238 100644 --- a/src/freedreno/ir3/ir3_validate.c +++ b/src/freedreno/ir3/ir3_validate.c @@ -157,6 +157,8 @@ validate_instr(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr) /* must have the same size as the destination, handled in * validate_reg(). */ + } else if (reg == instr->address) { + validate_assert(ctx, reg->flags & IR3_REG_HALF); } else if ((instr->flags & IR3_INSTR_S2EN) && (n < 2)) { if (n == 0) { if (instr->flags & IR3_INSTR_B)