kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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:
Msrc/api/cg.c | 8++------
Msrc/arch/regalloc.c | 26++++++++++++++++++++++----
Msrc/arch/regalloc.h | 5++++-
Msrc/opt/opt.c | 8++------
Mtest/opt/opt_test.c | 26++++++++++++++++++++++++++
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;