mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-22 20:00:10 +01:00
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
10 changed files with 44 additions and 69 deletions
|
|
@ -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,
|
static struct ir3_instruction *instr_create(struct ir3_block *block,
|
||||||
opc_t opc, int nreg)
|
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))
|
if (1 <= opc_cat(opc))
|
||||||
nreg++;
|
nreg += 2;
|
||||||
struct ir3_instruction *instr;
|
struct ir3_instruction *instr;
|
||||||
unsigned sz = sizeof(*instr) + (nreg * sizeof(instr->regs[0]));
|
unsigned sz = sizeof(*instr) + (nreg * sizeof(instr->regs[0]));
|
||||||
char *ptr = ir3_alloc(block->shader, sz);
|
char *ptr = ir3_alloc(block->shader, sz);
|
||||||
|
|
@ -494,13 +494,14 @@ void
|
||||||
ir3_instr_set_address(struct ir3_instruction *instr,
|
ir3_instr_set_address(struct ir3_instruction *instr,
|
||||||
struct ir3_instruction *addr)
|
struct ir3_instruction *addr)
|
||||||
{
|
{
|
||||||
if (instr->address != addr) {
|
if (!instr->address) {
|
||||||
struct ir3 *ir = instr->block->shader;
|
struct ir3 *ir = instr->block->shader;
|
||||||
|
|
||||||
debug_assert(!instr->address);
|
|
||||||
debug_assert(instr->block == addr->block);
|
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);
|
debug_assert(reg_num(addr->regs[0]) == REG_A0);
|
||||||
unsigned comp = reg_comp(addr->regs[0]);
|
unsigned comp = reg_comp(addr->regs[0]);
|
||||||
if (comp == 0) {
|
if (comp == 0) {
|
||||||
|
|
@ -509,6 +510,8 @@ ir3_instr_set_address(struct ir3_instruction *instr,
|
||||||
debug_assert(comp == 1);
|
debug_assert(comp == 1);
|
||||||
array_insert(ir, ir->a1_users, instr);
|
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) {
|
if (instr->regs[n+1]->flags & IR3_REG_SSA) {
|
||||||
struct ir3_instruction *src = ssa(instr->regs[n+1]);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,7 @@ struct ir3_instruction {
|
||||||
*
|
*
|
||||||
* NOTE: do not write this directly, use ir3_instr_set_address()
|
* 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
|
/* Tracking for additional dependent instructions. Used to handle
|
||||||
* barriers, WAR hazards for arrays/SSBOs/etc.
|
* barriers, WAR hazards for arrays/SSBOs/etc.
|
||||||
|
|
@ -1026,10 +1026,10 @@ static inline struct ir3_instruction *ssa(struct ir3_register *reg)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool conflicts(struct ir3_instruction *a,
|
static inline bool conflicts(struct ir3_register *a,
|
||||||
struct ir3_instruction *b)
|
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)
|
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)
|
static inline unsigned __ssa_src_cnt(struct ir3_instruction *instr)
|
||||||
{
|
{
|
||||||
unsigned cnt = instr->regs_count + instr->deps_count;
|
return instr->regs_count + instr->deps_count;
|
||||||
if (instr->address)
|
}
|
||||||
cnt++;
|
|
||||||
return cnt;
|
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 **
|
static inline struct ir3_instruction **
|
||||||
__ssa_srcp_n(struct ir3_instruction *instr, unsigned n)
|
__ssa_srcp_n(struct ir3_instruction *instr, unsigned n)
|
||||||
{
|
{
|
||||||
if (n == (instr->regs_count + instr->deps_count))
|
if (__is_false_dep(instr, n))
|
||||||
return &instr->address;
|
|
||||||
if (n >= instr->regs_count)
|
|
||||||
return &instr->deps[n - instr->regs_count];
|
return &instr->deps[n - instr->regs_count];
|
||||||
if (ssa(instr->regs[n]))
|
if (ssa(instr->regs[n]))
|
||||||
return &instr->regs[n]->def->instr;
|
return &instr->regs[n]->def->instr;
|
||||||
return NULL;
|
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) \
|
#define foreach_ssa_srcp_n(__srcp, __n, __instr) \
|
||||||
for (struct ir3_instruction **__srcp = (void *)~0; __srcp; __srcp = NULL) \
|
for (struct ir3_instruction **__srcp = (void *)~0; __srcp; __srcp = NULL) \
|
||||||
for (unsigned __cnt = __ssa_src_cnt(__instr), __n = 0; __n < __cnt; __n++) \
|
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 = ir3_MOV(block, instr, TYPE_S16);
|
||||||
instr->regs[0]->num = regid(REG_A0, 0);
|
instr->regs[0]->num = regid(REG_A0, 0);
|
||||||
instr->regs[0]->flags &= ~IR3_REG_SSA;
|
|
||||||
|
|
||||||
return instr;
|
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 *immed = create_immed_typed(block, const_val, TYPE_U16);
|
||||||
struct ir3_instruction *instr = ir3_MOV(block, immed, TYPE_U16);
|
struct ir3_instruction *instr = ir3_MOV(block, immed, TYPE_U16);
|
||||||
instr->regs[0]->num = regid(REG_A0, 1);
|
instr->regs[0]->num = regid(REG_A0, 1);
|
||||||
instr->regs[0]->flags &= ~IR3_REG_SSA;
|
|
||||||
return instr;
|
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]->flags & IR3_REG_IMMED) &&
|
||||||
(cmp->regs[2]->iim_val == 0) &&
|
(cmp->regs[2]->iim_val == 0) &&
|
||||||
(cmp->cat2.condition == IR3_COND_NE) &&
|
(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
|
/* 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;
|
instr->regs[n+1] = src_reg;
|
||||||
|
|
||||||
if (src_reg->flags & IR3_REG_RELATIV)
|
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;
|
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))
|
if (is_meta(instr) && (src->opc != OPC_MOV))
|
||||||
continue;
|
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);
|
progress |= reg_cp(ctx, instr, reg, n);
|
||||||
ctx->progress |= progress;
|
ctx->progress |= progress;
|
||||||
}
|
}
|
||||||
} while (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
|
/* 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
|
* 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.
|
* 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->opc = cond->opc;
|
||||||
instr->flags = cond->flags;
|
instr->flags = cond->flags;
|
||||||
instr->cat2 = cond->cat2;
|
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[1] = ir3_reg_clone(ctx->shader, cond->regs[1]);
|
||||||
instr->regs[2] = ir3_reg_clone(ctx->shader, cond->regs[2]);
|
instr->regs[2] = ir3_reg_clone(ctx->shader, cond->regs[2]);
|
||||||
instr->barrier_class |= cond->barrier_class;
|
instr->barrier_class |= cond->barrier_class;
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ instr_cp_postsched(struct ir3_instruction *mov)
|
||||||
*/
|
*/
|
||||||
if (removed) {
|
if (removed) {
|
||||||
if (src->flags & IR3_REG_RELATIV)
|
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);
|
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);
|
delay = MAX2(delay, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instr->address) {
|
|
||||||
unsigned d = delay_calc_srcn_prera(block, instr->address, instr, 0);
|
|
||||||
delay = MAX2(delay, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
return delay;
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,7 +226,11 @@ delay_calc_srcn_postra(struct ir3_instruction *assigner, struct ir3_instruction
|
||||||
bool mismatched_half =
|
bool mismatched_half =
|
||||||
(src->flags & IR3_REG_HALF) != (dst->flags & IR3_REG_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;
|
return 0;
|
||||||
|
|
||||||
unsigned src_start = post_ra_reg_num(src) * reg_elem_size(src);
|
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;
|
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) {
|
if (dest_regs(assigner) != 0) {
|
||||||
foreach_src_n (src, n, consumer) {
|
foreach_src_n (src, n, consumer) {
|
||||||
if (src->flags & (IR3_REG_IMMED | IR3_REG_CONST))
|
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
|
* 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:
|
* 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
|
* If positive, corresponds to node->instr->regs[src_n]. If negative, then
|
||||||
* node->instr->regs[src_n]. If negative, then this is for a destination
|
* this is for a destination register.
|
||||||
* register.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
add_reg_dep(struct ir3_postsched_deps_state *state,
|
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)
|
if (dest_regs(node->instr) == 0)
|
||||||
return;
|
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) {
|
if (instr->opc == OPC_META_SPLIT) {
|
||||||
mesa_log_stream_printf(stream, ", off=%d", instr->split.off);
|
mesa_log_stream_printf(stream, ", off=%d", instr->split.off);
|
||||||
} else if (instr->opc == OPC_META_TEX_PREFETCH) {
|
} 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];
|
struct ir3_instruction *indirect = ir->a0_users[i];
|
||||||
if (!indirect)
|
if (!indirect)
|
||||||
continue;
|
continue;
|
||||||
if (indirect->address != instr)
|
if (indirect->address->def != instr->regs[0])
|
||||||
continue;
|
continue;
|
||||||
ready = could_sched(indirect, instr);
|
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];
|
struct ir3_instruction *indirect = ir->a1_users[i];
|
||||||
if (!indirect)
|
if (!indirect)
|
||||||
continue;
|
continue;
|
||||||
if (indirect->address != instr)
|
if (indirect->address->def != instr->regs[0])
|
||||||
continue;
|
continue;
|
||||||
ready = could_sched(indirect, instr);
|
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
|
/* remap remaining instructions using current addr
|
||||||
* to new addr:
|
* to new addr:
|
||||||
*/
|
*/
|
||||||
if (indirect->address == *addr) {
|
if (indirect->address->def == (*addr)->regs[0]) {
|
||||||
if (!new_addr) {
|
if (!new_addr) {
|
||||||
new_addr = split_instr(ctx, *addr);
|
new_addr = split_instr(ctx, *addr);
|
||||||
/* original addr is scheduled, but new one isn't: */
|
/* original addr is scheduled, but new one isn't: */
|
||||||
new_addr->flags &= ~IR3_INSTR_MARK;
|
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
|
/* don't need to remove old dag edge since old addr is
|
||||||
* already scheduled:
|
* already scheduled:
|
||||||
*/
|
*/
|
||||||
|
|
@ -984,8 +984,6 @@ sched_node_add_dep(struct ir3_instruction *instr, struct ir3_instruction *src, i
|
||||||
unsigned d = 0;
|
unsigned d = 0;
|
||||||
if (i < instr->regs_count)
|
if (i < instr->regs_count)
|
||||||
d = ir3_delayslots(src, instr, i + 1, true);
|
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);
|
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
|
/* must have the same size as the destination, handled in
|
||||||
* validate_reg().
|
* validate_reg().
|
||||||
*/
|
*/
|
||||||
|
} else if (reg == instr->address) {
|
||||||
|
validate_assert(ctx, reg->flags & IR3_REG_HALF);
|
||||||
} else if ((instr->flags & IR3_INSTR_S2EN) && (n < 2)) {
|
} else if ((instr->flags & IR3_INSTR_S2EN) && (n < 2)) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
if (instr->flags & IR3_INSTR_B)
|
if (instr->flags & IR3_INSTR_B)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue