commit 9362d8f146cb919674bca15538ef7f3484e18451
parent 90d63a81f19f98008ca8cd0e5ba111793138f6a7
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 14 May 2026 12:52:20 -0700
Track exact simple regalloc usage
Diffstat:
5 files changed, 56 insertions(+), 17 deletions(-)
diff --git a/src/api/cg.c b/src/api/cg.c
@@ -1246,13 +1246,9 @@ static void api_regalloc_finish(CfreeCg* g) {
if (cg_simple_regalloc_is_virtual(&g->regalloc)) return;
if (!g->target->reserve_hard_regs) return;
for (u32 c = 0; c < 3u; ++c) {
- CGSimpleRegPool* p = &g->regalloc.pools[c];
Reg used[CG_SIMPLE_REGALLOC_MAX_REGS];
- u32 nused = 0;
- for (u32 i = 0; i < p->hwm && i < p->nregs; ++i) {
- Reg r = cg_simple_regpool_reg_at(p, i);
- if (r != (Reg)REG_NONE) used[nused++] = r;
- }
+ u32 nused = cg_simple_regalloc_used_regs(&g->regalloc, (RegClass)c, used,
+ CG_SIMPLE_REGALLOC_MAX_REGS);
if (nused) g->target->reserve_hard_regs(g->target, (RegClass)c, used, nused);
}
}
diff --git a/src/arch/regalloc.c b/src/arch/regalloc.c
@@ -10,7 +10,7 @@ static u32 pool_mask(u32 nregs) {
void cg_simple_regpool_init_range(CGSimpleRegPool* p, Reg base, u32 nregs) {
if (nregs > CG_SIMPLE_REGALLOC_MAX_REGS) nregs = CG_SIMPLE_REGALLOC_MAX_REGS;
p->free = pool_mask(nregs);
- p->hwm = 0;
+ p->used = 0;
p->order = NULL;
p->base = base;
p->nregs = nregs;
@@ -20,7 +20,7 @@ void cg_simple_regpool_init_ordered(CGSimpleRegPool* p, const Reg* regs,
u32 nregs) {
if (nregs > CG_SIMPLE_REGALLOC_MAX_REGS) nregs = CG_SIMPLE_REGALLOC_MAX_REGS;
p->free = pool_mask(nregs);
- p->hwm = 0;
+ p->used = 0;
p->order = regs;
p->base = 0;
p->nregs = nregs;
@@ -35,7 +35,7 @@ Reg cg_simple_regpool_alloc(CGSimpleRegPool* p) {
if (p->free == 0) return (Reg)REG_NONE;
u32 idx = (u32)__builtin_ctz(p->free);
p->free &= ~(1u << idx);
- if (idx + 1u > p->hwm) p->hwm = idx + 1u;
+ p->used |= 1u << idx;
return cg_simple_regpool_reg_at(p, idx);
}
@@ -54,12 +54,24 @@ int cg_simple_regpool_free(CGSimpleRegPool* p, Reg r) {
void cg_simple_regpool_reserve(CGSimpleRegPool* p, Reg r) {
for (u32 i = 0; i < p->nregs; ++i) {
if (cg_simple_regpool_reg_at(p, i) == r) {
- if (i + 1u > p->hwm) p->hwm = i + 1u;
+ p->free &= ~(1u << i);
+ p->used |= 1u << i;
return;
}
}
}
+u32 cg_simple_regpool_used_regs(const CGSimpleRegPool* p, Reg* out, u32 cap) {
+ u32 n = 0;
+ u32 bits = p->used & pool_mask(p->nregs);
+ while (bits) {
+ u32 idx = (u32)__builtin_ctz(bits);
+ bits &= bits - 1u;
+ if (n < cap) out[n++] = cg_simple_regpool_reg_at(p, idx);
+ }
+ return n;
+}
+
void cg_simple_regalloc_init(CGSimpleRegAlloc* a) {
memset(a, 0, sizeof *a);
}
@@ -103,6 +115,12 @@ void cg_simple_regalloc_reserve(CGSimpleRegAlloc* a, RegClass cls, Reg r) {
cg_simple_regpool_reserve(&a->pools[cls], r);
}
+u32 cg_simple_regalloc_used_regs(const CGSimpleRegAlloc* a, RegClass cls,
+ Reg* out, u32 cap) {
+ if ((u32)cls >= 3u || a->virtual_regs) return 0;
+ return cg_simple_regpool_used_regs(&a->pools[cls], out, cap);
+}
+
int cg_simple_regalloc_is_virtual(const CGSimpleRegAlloc* a) {
return a->virtual_regs != 0;
}
diff --git a/src/arch/regalloc.h b/src/arch/regalloc.h
@@ -7,7 +7,7 @@
typedef struct CGSimpleRegPool {
u32 free; /* bit i set iff reg_at(i) is free */
- u32 hwm; /* highest index+1 ever allocated/reserved */
+ u32 used; /* bit i set iff reg_at(i) was allocated/reserved */
const Reg* order; /* optional ordered hard-reg table */
Reg base; /* used when order is NULL: reg_at(i) = base + i */
u32 nregs;
@@ -26,6 +26,7 @@ Reg cg_simple_regpool_alloc(CGSimpleRegPool* p);
int cg_simple_regpool_free(CGSimpleRegPool* p, Reg r);
void cg_simple_regpool_reserve(CGSimpleRegPool* p, Reg r);
Reg cg_simple_regpool_reg_at(const CGSimpleRegPool* p, u32 idx);
+u32 cg_simple_regpool_used_regs(const CGSimpleRegPool* p, Reg* out, u32 cap);
void cg_simple_regalloc_init(CGSimpleRegAlloc* a);
void cg_simple_regalloc_init_virtual(CGSimpleRegAlloc* a);
@@ -36,6 +37,8 @@ void cg_simple_regalloc_set_ordered(CGSimpleRegAlloc* a, RegClass cls,
Reg cg_simple_regalloc_alloc(CGSimpleRegAlloc* a, RegClass cls);
int cg_simple_regalloc_free(CGSimpleRegAlloc* a, RegClass cls, Reg r);
void cg_simple_regalloc_reserve(CGSimpleRegAlloc* a, RegClass cls, Reg r);
+u32 cg_simple_regalloc_used_regs(const CGSimpleRegAlloc* a, RegClass cls,
+ Reg* out, u32 cap);
int cg_simple_regalloc_is_virtual(const CGSimpleRegAlloc* a);
#endif
diff --git a/src/opt/opt.c b/src/opt/opt.c
@@ -1300,13 +1300,9 @@ static void replay_func_to(Compiler* c, Func* f, CGTarget* w, int identity) {
}
} else if (!r.identity_regs && w->reserve_hard_regs) {
for (u32 c = 0; c < OPT_REG_CLASSES; ++c) {
- CGSimpleRegPool* p = &r.regalloc.pools[c];
Reg used[CG_SIMPLE_REGALLOC_MAX_REGS];
- u32 nused = 0;
- for (u32 i = 0; i < p->hwm && i < p->nregs; ++i) {
- Reg hr = cg_simple_regpool_reg_at(p, i);
- if (hr != (Reg)REG_NONE) used[nused++] = hr;
- }
+ u32 nused = cg_simple_regalloc_used_regs(&r.regalloc, (RegClass)c, used,
+ CG_SIMPLE_REGALLOC_MAX_REGS);
if (nused) w->reserve_hard_regs(w, (RegClass)c, used, nused);
}
}
diff --git a/test/opt/opt_test.c b/test/opt/opt_test.c
@@ -7,6 +7,7 @@
#include "abi/abi.h"
#include "arch/arch.h"
+#include "arch/regalloc.h"
#include "core/core.h"
#include "core/heap.h"
#include "opt/ir.h"
@@ -1162,6 +1163,30 @@ static void opt_emit_no_virtual_alloc(void) {
tc_fini(&tc);
}
+static void simple_regalloc_reports_exact_used_regs(void) {
+ CGSimpleRegAlloc a;
+ static const Reg regs[] = {3, 7, 11};
+ Reg used[CG_SIMPLE_REGALLOC_MAX_REGS];
+ for (u32 i = 0; i < CG_SIMPLE_REGALLOC_MAX_REGS; ++i) used[i] = REG_NONE;
+ cg_simple_regalloc_init(&a);
+ cg_simple_regalloc_set_ordered(&a, RC_INT, regs, 3);
+
+ cg_simple_regalloc_reserve(&a, RC_INT, 11);
+ u32 nused = cg_simple_regalloc_used_regs(&a, RC_INT, used,
+ CG_SIMPLE_REGALLOC_MAX_REGS);
+ EXPECT(nused == 1, "reserve should report one exact used reg, got %u",
+ (unsigned)nused);
+ EXPECT(used[0] == 11, "reserve should report r11, got r%u",
+ (unsigned)used[0]);
+
+ EXPECT(cg_simple_regalloc_alloc(&a, RC_INT) == 3,
+ "first alloc should skip no lower unreserved reg");
+ EXPECT(cg_simple_regalloc_alloc(&a, RC_INT) == 7,
+ "second alloc should use remaining unreserved reg");
+ EXPECT(cg_simple_regalloc_alloc(&a, RC_INT) == (Reg)REG_NONE,
+ "reserved reg should not be allocated");
+}
+
int main(void) {
opt_cfg_prunes_unreachable();
opt_cfg_preserves_scope_edges();
@@ -1184,6 +1209,7 @@ int main(void) {
opt_post_rewrite_dce();
opt_dead_def_elim_test();
opt_emit_no_virtual_alloc();
+ simple_regalloc_reports_exact_used_regs();
if (g_fails) {
fprintf(stderr, "opt tests: %d failed (%d checks)\n", g_fails, g_checks);
return 1;