Mesa (main): agx: Assign registers locally
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Wed Jul 7 03:41:57 UTC 2021
Module: Mesa
Branch: main
Commit: 85e18deb18a195cea78da8746fe9a2ef8e74e049
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=85e18deb18a195cea78da8746fe9a2ef8e74e049
Author: Alyssa Rosenzweig <alyssa at rosenzweig.io>
Date: Sat Jun 19 14:34:44 2021 -0400
agx: Assign registers locally
Signed-off-by: Alyssa Rosenzweig <alyssa at rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11751>
---
src/asahi/compiler/agx_compiler.h | 6 ++
src/asahi/compiler/agx_register_allocate.c | 151 +++++++++++++++++++++++------
2 files changed, 130 insertions(+), 27 deletions(-)
diff --git a/src/asahi/compiler/agx_compiler.h b/src/asahi/compiler/agx_compiler.h
index 94f75a6e985..e4f76813d8e 100644
--- a/src/asahi/compiler/agx_compiler.h
+++ b/src/asahi/compiler/agx_compiler.h
@@ -43,6 +43,9 @@ enum agx_dbg {
extern int agx_debug;
+/* r0-r127 inclusive, as pairs of 16-bits, gives 256 registers */
+#define AGX_NUM_REGS (256)
+
enum agx_index_type {
AGX_INDEX_NULL = 0,
AGX_INDEX_NORMAL = 1,
@@ -325,6 +328,9 @@ typedef struct agx_block {
BITSET_WORD *live_in;
BITSET_WORD *live_out;
+ /* Register allocation */
+ BITSET_DECLARE(regs_out, AGX_NUM_REGS);
+
/* Offset of the block in the emitted binary */
off_t offset;
diff --git a/src/asahi/compiler/agx_register_allocate.c b/src/asahi/compiler/agx_register_allocate.c
index 0977d2be2d5..0f1acdc7c57 100644
--- a/src/asahi/compiler/agx_register_allocate.c
+++ b/src/asahi/compiler/agx_register_allocate.c
@@ -37,8 +37,6 @@ agx_read_registers(agx_instr *I, unsigned s)
unsigned size = I->src[s].size == AGX_SIZE_32 ? 2 : 1;
switch (I->op) {
- case AGX_OPCODE_DEVICE_LOAD:
- return 8;
default:
return size;
}
@@ -58,43 +56,134 @@ agx_write_registers(agx_instr *I, unsigned d)
return 8;
case AGX_OPCODE_LD_VARY_FLAT:
return 6;
+ case AGX_OPCODE_P_COMBINE:
+ {
+ unsigned components = 0;
+
+ for (unsigned i = 0; i < 4; ++i) {
+ if (!agx_is_null(I->src[i]))
+ components = i + 1;
+ }
+
+ return components * size;
+ }
default:
return size;
}
}
+static unsigned
+agx_assign_regs(BITSET_WORD *used_regs, unsigned count, unsigned align)
+{
+ for (unsigned reg = 0; reg < AGX_NUM_REGS; reg += align) {
+ bool conflict = false;
+
+ for (unsigned j = 0; j < count; ++j)
+ conflict |= BITSET_TEST(used_regs, reg + j);
+
+ if (!conflict) {
+ for (unsigned j = 0; j < count; ++j)
+ BITSET_SET(used_regs, reg + j);
+
+ return reg;
+ }
+ }
+
+ unreachable("Could not find a free register");
+}
+
+/** Assign registers to SSA values in a block. */
+
+static void
+agx_ra_assign_local(agx_block *block, uint8_t *ssa_to_reg)
+{
+ BITSET_DECLARE(used_regs, AGX_NUM_REGS) = { 0 };
+
+ agx_foreach_predecessor(block, pred) {
+ for (unsigned i = 0; i < BITSET_WORDS(AGX_NUM_REGS); ++i)
+ used_regs[i] |= pred->regs_out[i];
+ }
+
+ BITSET_SET(used_regs, 0); // control flow writes r0l
+ BITSET_SET(used_regs, 5*2); // TODO: precolouring, don't overwrite vertex ID
+ BITSET_SET(used_regs, (5*2 + 1));
+
+ agx_foreach_instr_in_block(block, I) {
+ /* First, free killed sources */
+ agx_foreach_src(I, s) {
+ if (I->src[s].type == AGX_INDEX_NORMAL && I->src[s].kill) {
+ unsigned reg = ssa_to_reg[I->src[s].value];
+ unsigned count = agx_read_registers(I, s);
+
+ for (unsigned i = 0; i < count; ++i)
+ BITSET_CLEAR(used_regs, reg + i);
+ }
+ }
+
+ /* Next, assign destinations. Always legal in SSA form. */
+ agx_foreach_dest(I, d) {
+ if (I->dest[d].type == AGX_INDEX_NORMAL) {
+ unsigned count = agx_write_registers(I, d);
+ unsigned align = (I->dest[d].size == AGX_SIZE_16) ? 1 : 2;
+ unsigned reg = agx_assign_regs(used_regs, count, align);
+
+ ssa_to_reg[I->dest[d].value] = reg;
+ }
+ }
+ }
+
+ STATIC_ASSERT(sizeof(block->regs_out) == sizeof(used_regs));
+ memcpy(block->regs_out, used_regs, sizeof(used_regs));
+}
+
void
agx_ra(agx_context *ctx)
{
unsigned *alloc = calloc(ctx->alloc, sizeof(unsigned));
- unsigned usage = 6*2;
+
+ agx_compute_liveness(ctx);
+ uint8_t *ssa_to_reg = calloc(ctx->alloc, sizeof(uint8_t));
+ agx_foreach_block(ctx, block)
+ agx_ra_assign_local(block, ssa_to_reg);
+
+ /* TODO: Coalesce combines */
agx_foreach_instr_global_safe(ctx, ins) {
/* Lower away RA pseudo-instructions */
if (ins->op == AGX_OPCODE_P_COMBINE) {
/* TODO: Optimize out the moves! */
- unsigned components = 0;
-
- for (unsigned i = 0; i < 4; ++i) {
- if (!agx_is_null(ins->src[i]))
- components = i + 1;
- }
-
- unsigned size = ins->dest[0].size == AGX_SIZE_32 ? 2 : 1;
- if (size == 2 && usage & 1) usage++;
- unsigned base = usage;
assert(ins->dest[0].type == AGX_INDEX_NORMAL);
- alloc[ins->dest[0].value] = base;
- usage += (components * size);
+ enum agx_size common_size = ins->dest[0].size;
+ unsigned base = ssa_to_reg[ins->dest[0].value];
+ unsigned size = common_size == AGX_SIZE_32 ? 2 : 1;
/* Move the sources */
agx_builder b = agx_init_builder(ctx, agx_after_instr(ins));
+ /* TODO: Eliminate the intermediate copy by handling parallel copies */
for (unsigned i = 0; i < 4; ++i) {
if (agx_is_null(ins->src[i])) continue;
- assert(ins->src[0].type == AGX_INDEX_NORMAL);
- agx_mov_to(&b, agx_register(base + (i * size), ins->dest[0].size),
- agx_register(alloc[ins->src[i].value], ins->src[0].size));
+ unsigned base = ins->src[i].value;
+ if (ins->src[i].type == AGX_INDEX_NORMAL)
+ base = ssa_to_reg[base];
+ else
+ assert(ins->src[i].type == AGX_INDEX_REGISTER);
+
+ assert(ins->src[i].size == common_size);
+
+ agx_mov_to(&b, agx_register(124*2 + (i * size), common_size),
+ agx_register(base, common_size));
+ }
+
+ for (unsigned i = 0; i < 4; ++i) {
+ if (agx_is_null(ins->src[i])) continue;
+ agx_index src = ins->src[i];
+
+ if (src.type == AGX_INDEX_NORMAL)
+ src = agx_register(alloc[src.value], src.size);
+
+ agx_mov_to(&b, agx_register(base + (i * size), common_size),
+ agx_register(124*2 + (i * size), common_size));
}
/* We've lowered away, delete the old */
@@ -102,34 +191,42 @@ agx_ra(agx_context *ctx)
continue;
} else if (ins->op == AGX_OPCODE_P_EXTRACT) {
assert(ins->dest[0].type == AGX_INDEX_NORMAL);
- assert(ins->src[0].type == AGX_INDEX_NORMAL);
assert(ins->dest[0].size == ins->src[0].size);
+ unsigned base = ins->src[0].value;
+
+ if (ins->src[0].type != AGX_INDEX_REGISTER) {
+ assert(ins->src[0].type == AGX_INDEX_NORMAL);
+ base = alloc[base];
+ }
unsigned size = ins->dest[0].size == AGX_SIZE_32 ? 2 : 1;
- alloc[ins->dest[0].value] = alloc[ins->src[0].value] + (size * ins->imm);
+ unsigned left = ssa_to_reg[ins->dest[0].value];
+ unsigned right = ssa_to_reg[ins->src[0].value] + (size * ins->imm);
+
+ if (left != right) {
+ agx_builder b = agx_init_builder(ctx, agx_after_instr(ins));
+ agx_mov_to(&b, agx_register(left, ins->dest[0].size),
+ agx_register(right, ins->src[0].size));
+ }
+
agx_remove_instruction(ins);
continue;
}
agx_foreach_src(ins, s) {
if (ins->src[s].type == AGX_INDEX_NORMAL) {
- unsigned v = alloc[ins->src[s].value];
+ unsigned v = ssa_to_reg[ins->src[s].value];
ins->src[s] = agx_replace_index(ins->src[s], agx_register(v, ins->src[s].size));
}
}
agx_foreach_dest(ins, d) {
if (ins->dest[d].type == AGX_INDEX_NORMAL) {
- unsigned size = ins->dest[d].size == AGX_SIZE_32 ? 2 : 1;
- if (size == 2 && usage & 1) usage++;
- unsigned v = usage;
- usage += agx_write_registers(ins, d);
- alloc[ins->dest[d].value] = v;
+ unsigned v = ssa_to_reg[ins->dest[d].value];
ins->dest[d] = agx_replace_index(ins->dest[d], agx_register(v, ins->dest[d].size));
}
}
}
- assert(usage < 256 && "dummy RA");
free(alloc);
}
More information about the mesa-commit
mailing list