ir3: teach backend about alias

Take the properties of alias.{rt,tex} and its registers into account:
- Don't count alias registers for GPR usage;
- Allow all immediates in alias regs;
- Fix properties like is_barrier and (ss) support;
- alias.rt dst is not a GPR, don't use it in legalize/postsched to track
  dependencies;

Signed-off-by: Job Noorman <jnoorman@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31222>
This commit is contained in:
Job Noorman
2025-01-22 15:33:47 +01:00
committed by Marge Bot
parent a325573aaf
commit 4c2fc07a7e
5 changed files with 51 additions and 7 deletions
+21 -3
View File
@@ -275,21 +275,39 @@ ir3_collect_info(struct ir3_shader_variant *v)
bool in_preamble = false;
bool has_eq = false;
/* Track which registers are currently aliases because they shouldn't be
* included in the GPR footprint.
*/
regmask_t aliases;
/* Full and half aliases do not overlap so treat them as !mergedregs. */
regmask_init(&aliases, false);
foreach_block (block, &shader->block_list) {
int sfu_delay = 0, mem_delay = 0;
foreach_instr (instr, &block->instr_list) {
foreach_src (reg, instr) {
collect_reg_info(instr, reg, info);
if (!is_reg_gpr(reg) || !regmask_get(&aliases, reg)) {
collect_reg_info(instr, reg, info);
}
}
foreach_dst (reg, instr) {
if (is_dest_gpr(reg)) {
if (instr->opc == OPC_ALIAS &&
instr->cat7.alias_scope == ALIAS_TEX) {
regmask_set(&aliases, instr->dsts[0]);
} else if (is_dest_gpr(reg)) {
collect_reg_info(instr, reg, info);
}
}
if (is_tex(instr)) {
/* All aliases are cleared after they are used. */
regmask_init(&aliases, false);
}
if ((instr->opc == OPC_STP || instr->opc == OPC_LDP)) {
unsigned components = instr->srcs[2]->uim_val;
@@ -1479,7 +1497,7 @@ ir3_valid_flags(struct ir3_instruction *instr, unsigned n, unsigned flags)
bool
ir3_valid_immediate(struct ir3_instruction *instr, int32_t immed)
{
if (instr->opc == OPC_MOV || is_meta(instr))
if (instr->opc == OPC_MOV || is_meta(instr) || instr->opc == OPC_ALIAS)
return true;
if (is_mem(instr)) {
+21 -2
View File
@@ -159,6 +159,17 @@ typedef enum ir3_register_flags {
/* Render target dst. Only used by alias.rt. */
IR3_REG_RT = BIT(20),
/* Register that is initialized using alias.tex (or will be once the
* alias.tex instructions are inserted). Before alias.tex is inserted, alias
* registers may contain things that are normally not allowed by the owning
* instruction (e.g., consts or immediates) because they will be replaced by
* GPRs later.
* Note that if wrmask > 1, this will be set if any of the registers is an
* alias, even though not all of them may be. We currently have no way to
* tell which ones are actual aliases.
*/
IR3_REG_ALIAS = BIT(21),
} ir3_register_flags;
struct ir3_register {
@@ -1148,7 +1159,7 @@ is_mem(struct ir3_instruction *instr)
static inline bool
is_barrier(struct ir3_instruction *instr)
{
return (opc_cat(instr->opc) == 7);
return (opc_cat(instr->opc) == 7) && instr->opc != OPC_ALIAS;
}
static inline bool
@@ -1418,8 +1429,10 @@ dest_regs(struct ir3_instruction *instr)
static inline bool
is_reg_gpr(const struct ir3_register *reg)
{
if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED | IR3_REG_PREDICATE))
if (reg->flags &
(IR3_REG_CONST | IR3_REG_IMMED | IR3_REG_PREDICATE | IR3_REG_RT)) {
return false;
}
if (reg_num(reg) == REG_A0)
return false;
if (!(reg->flags & (IR3_REG_SSA | IR3_REG_RELATIV)) &&
@@ -2091,6 +2104,12 @@ needs_ss(const struct ir3_compiler *compiler, struct ir3_instruction *producer,
return is_ss_producer(producer);
}
static inline bool
supports_ss(struct ir3_instruction *instr)
{
return opc_cat(instr->opc) < 5 || instr->opc == OPC_ALIAS;
}
/* The soft delay for approximating the cost of (ss). */
static inline unsigned
soft_ss_delay(struct ir3_instruction *instr)
+6 -1
View File
@@ -231,6 +231,9 @@ delay_update(struct ir3_legalize_state *state,
return;
foreach_dst_n (dst, n, instr) {
if (dst->flags & IR3_REG_RT)
continue;
unsigned elems = post_ra_reg_elems(dst);
unsigned num = post_ra_reg_num(dst);
unsigned dst_cycle = cycle;
@@ -523,6 +526,8 @@ legalize_block(struct ir3_legalize_ctx *ctx, struct ir3_block *block)
}
foreach_dst (reg, n) {
if (reg->flags & IR3_REG_RT)
continue;
if (needs_ss_war(state, reg, n_is_scalar_alu)) {
apply_ss(n, state, mergedregs);
last_input_needs_ss = false;
@@ -540,7 +545,7 @@ legalize_block(struct ir3_legalize_ctx *ctx, struct ir3_block *block)
* clever if we were aware of this during scheduling, but
* this should be a pretty rare case:
*/
if ((n->flags & IR3_INSTR_SS) && (opc_cat(n->opc) >= 5)) {
if ((n->flags & IR3_INSTR_SS) && !supports_ss(n)) {
struct ir3_instruction *nop;
nop = ir3_NOP(&build);
nop->flags |= IR3_INSTR_SS;
+2
View File
@@ -488,6 +488,8 @@ calculate_deps(struct ir3_postsched_deps_state *state,
foreach_dst_n (reg, i, node->instr) {
if (reg->wrmask == 0)
continue;
if (reg->flags & IR3_REG_RT)
continue;
if (reg->flags & IR3_REG_RELATIV) {
/* mark the entire array as written: */
for (unsigned j = 0; j < reg->size; j++) {
+1 -1
View File
@@ -66,7 +66,7 @@ static void
validate_src(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr,
struct ir3_register *reg)
{
if (reg->flags & IR3_REG_IMMED)
if ((reg->flags & IR3_REG_IMMED) && !(reg->flags & IR3_REG_ALIAS))
validate_assert(ctx, ir3_valid_immediate(instr, reg->iim_val));
if (!(reg->flags & IR3_REG_SSA) || !reg->def)