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: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11469>
This commit is contained in:
parent
2522f387a3
commit
9af795d9b9
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++) \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue