From 6f1c275c94f25b41430f6ba6fed9dec3ef450e16 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Fri, 27 Sep 2024 07:52:18 -0400 Subject: [PATCH] agx: produce regful SSA in RA for validation Signed-off-by: Alyssa Rosenzweig Part-of: --- src/asahi/compiler/agx_compiler.h | 7 +++ src/asahi/compiler/agx_register_allocate.c | 57 +++++++++++++--------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/asahi/compiler/agx_compiler.h b/src/asahi/compiler/agx_compiler.h index 66635af2a7b..d61329f7be8 100644 --- a/src/asahi/compiler/agx_compiler.h +++ b/src/asahi/compiler/agx_compiler.h @@ -180,6 +180,13 @@ agx_register_like(uint32_t imm, agx_index like) }; } +static inline agx_index +agx_as_register(agx_index x) +{ + assert(x.has_reg); + return agx_register_like(x.reg, x); +} + static inline agx_index agx_undef(enum agx_size size) { diff --git a/src/asahi/compiler/agx_register_allocate.c b/src/asahi/compiler/agx_register_allocate.c index 7efb5fdf78f..f6315112a61 100644 --- a/src/asahi/compiler/agx_register_allocate.c +++ b/src/asahi/compiler/agx_register_allocate.c @@ -681,8 +681,10 @@ agx_emit_move_before_phi(agx_context *ctx, agx_block *block, /* Look for the phi writing the destination */ agx_foreach_phi_in_block(block, phi) { - if (agx_is_equiv(phi->dest[0], copy->src) && !phi->dest[0].memory) { - phi->dest[0].value = copy->dest; + if (agx_is_equiv(agx_as_register(phi->dest[0]), copy->src) && + !phi->dest[0].memory) { + + phi->dest[0].reg = copy->dest; return; } } @@ -812,6 +814,9 @@ reserve_live_in(struct ra_ctx *rctx) agx_foreach_predecessor(rctx->block, pred) { unsigned pred_idx = agx_predecessor_index(rctx->block, *pred); + phi->src[pred_idx] = agx_get_index(i, size); + phi->src[pred_idx].memory = cls == RA_MEM; + if ((*pred)->reg_to_ssa_out[cls] == NULL) { /* If this is a loop header, we don't know where the register * will end up. So, we create a phi conservatively but don't fill @@ -819,14 +824,11 @@ reserve_live_in(struct ra_ctx *rctx) * we'll need to fill in the real register later. */ assert(rctx->block->loop_header); - phi->src[pred_idx] = agx_get_index(i, size); - phi->src[pred_idx].memory = rctx->classes[i] == RA_MEM; } else { /* Otherwise, we can build the phi now */ - unsigned reg = search_ssa_to_reg_out(rctx, *pred, cls, i); - phi->src[pred_idx] = cls == RA_MEM - ? agx_memory_register(reg, size) - : agx_register(reg, size); + phi->src[pred_idx].reg = + search_ssa_to_reg_out(rctx, *pred, cls, i); + phi->src[pred_idx].has_reg = true; } } @@ -835,9 +837,9 @@ reserve_live_in(struct ra_ctx *rctx) * particular predecessor. That means that such a register allocation * is valid here, because it was valid in the predecessor. */ - assert(phi->src[0].type == AGX_INDEX_REGISTER && "not loop source"); + assert(phi->src[0].has_reg && "not loop source"); phi->dest[0] = phi->src[0]; - base = phi->dest[0].value; + base = phi->dest[0].reg; } else { /* If we don't emit a phi, there is already a unique register */ assert(nr_preds == 1); @@ -891,8 +893,8 @@ agx_set_sources(struct ra_ctx *rctx, agx_instr *I) agx_foreach_ssa_src(I, s) { assert(BITSET_TEST(rctx->visited, I->src[s].value) && "no phis"); - unsigned v = rctx->ssa_to_reg[I->src[s].value]; - agx_replace_src(I, s, agx_register_like(v, I->src[s])); + I->src[s].reg = rctx->ssa_to_reg[I->src[s].value]; + I->src[s].has_reg = true; } } @@ -900,9 +902,8 @@ static void agx_set_dests(struct ra_ctx *rctx, agx_instr *I) { agx_foreach_ssa_dest(I, s) { - unsigned v = rctx->ssa_to_reg[I->dest[s].value]; - I->dest[s] = - agx_replace_index(I->dest[s], agx_register_like(v, I->dest[s])); + I->dest[s].reg = rctx->ssa_to_reg[I->dest[s].value]; + I->dest[s].has_reg = true; } } @@ -1106,8 +1107,8 @@ pick_regs(struct ra_ctx *rctx, agx_instr *I, unsigned d) } /* If we're in a loop, we may have already allocated the phi. Try that. */ - if (phi->dest[0].type == AGX_INDEX_REGISTER) { - unsigned base = phi->dest[0].value; + if (phi->dest[0].has_reg) { + unsigned base = phi->dest[0].reg; if (base + count <= rctx->bound[cls] && !BITSET_TEST_RANGE(rctx->used_regs[cls], base, base + count - 1)) @@ -1224,6 +1225,9 @@ agx_ra_assign_local(struct ra_ctx *rctx) * because of the SSA form. */ agx_foreach_ssa_dest(I, d) { + if (I->op == AGX_OPCODE_PHI && I->dest[d].has_reg) + continue; + assign_regs(rctx, I->dest[d], pick_regs(rctx, I, d)); } @@ -1255,13 +1259,12 @@ agx_ra_assign_local(struct ra_ctx *rctx) unsigned pred_idx = agx_predecessor_index(succ, block); agx_foreach_phi_in_block(succ, phi) { - if (phi->src[pred_idx].type == AGX_INDEX_NORMAL) { + if (phi->src[pred_idx].type == AGX_INDEX_NORMAL && + !phi->src[pred_idx].has_reg) { /* This source needs a fixup */ unsigned value = phi->src[pred_idx].value; - - agx_replace_src( - phi, pred_idx, - agx_register_like(rctx->ssa_to_reg[value], phi->src[pred_idx])); + phi->src[pred_idx].reg = rctx->ssa_to_reg[value]; + phi->src[pred_idx].has_reg = true; } } } @@ -1574,6 +1577,16 @@ agx_ra(agx_context *ctx) assert(ctx->max_reg <= max_regs); agx_foreach_instr_global_safe(ctx, ins) { + /* Lower away SSA */ + agx_foreach_ssa_dest(ins, d) { + ins->dest[d] = + agx_replace_index(ins->dest[d], agx_as_register(ins->dest[d])); + } + + agx_foreach_ssa_src(ins, s) { + agx_replace_src(ins, s, agx_as_register(ins->src[s])); + } + /* Lower away RA pseudo-instructions */ agx_builder b = agx_init_builder(ctx, agx_after_instr(ins));