kit

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

commit 73e128a2a4859f2f82f39f3cf956ba61bb8a2917
parent ecbd00dc995aefbe600af5bfd5494412f7a59245
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sat, 13 Jun 2026 01:45:18 -0700

perf(cg): reuse a dead-transient index instead of copying it (kit_cg_elem)

kit_cg_elem copied the dynamic index into a fresh owned local "for unambiguous
ownership" before building the [base + index<<scale + ofs] place. When the index
is already a dead transient (provably referenced by nothing else — the value
stack confirms via api_temp_dead), take it over as the index slot directly and
skip the copy. Falls back to the copy for declared/shared locals and to the
pre-multiply for non-power-of-two strides. Guarded so the reused index can't
alias the base.

sqlite3.c -c, arm64-macOS: 543,470 -> 539,549 insns; reg-reg mov 45,770 -> 44,000.
Compile is net faster with the coalescing on (2.154B vs 2.177B with it disabled),
so the incremental refcount pays for itself.

test-toy 1392/0, test-parse-ok 3920/0 (O0/O1 x D/R/J/E), test-parse-err 129/0,
test-smoke-x64/rv64 3/0; subscript edge cases (struct-field, 2D, non-pow2) verified.

Diffstat:
Msrc/cg/control.c | 23++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/src/cg/control.c b/src/cg/control.c @@ -1109,18 +1109,27 @@ static void api_cg_elem(KitCg* g, u32 elem_size, int64_t offset) { * index is copied into a fresh local for unambiguous ownership. */ { int lg2 = cg_scale_to_log2(elemsz); - CGLocal ir = api_alloc_temp_local(g, idx_ty); - Operand iro = api_op_local(ir, idx_ty); + CGLocal ir; u8 log2_scale; - /* Refresh idx_op: allocating `ir` may have materialized a delayed index. */ + /* Force the index to a local first so we can tell whether it is a dead + * transient (provably not referenced elsewhere) that we can take over as the + * index slot directly, skipping the ownership copy. */ idx_op = api_force_local_unless_imm(g, &idx, idx_ty); if (idx.op.kind == OPK_LOCAL) idx_op = idx.op; - if (lg2 >= 0) { - T->copy(T, iro, idx_op); + if (lg2 >= 0 && idx_op.kind == OPK_LOCAL && idx_op.v.local != base_local && + api_coalesce_on(g) && api_temp_dead(g, idx_op.v.local)) { + ir = idx_op.v.local; /* reuse the dead transient; no copy */ log2_scale = (u8)lg2; } else { - T->binop(T, BO_IMUL, iro, idx_op, api_op_imm((i64)elemsz, idx_ty)); - log2_scale = 0; + ir = api_alloc_temp_local(g, idx_ty); + if (lg2 >= 0) { + T->copy(T, api_op_local(ir, idx_ty), idx_op); + log2_scale = (u8)lg2; + } else { + T->binop(T, BO_IMUL, api_op_local(ir, idx_ty), idx_op, + api_op_imm((i64)elemsz, idx_ty)); + log2_scale = 0; + } } api_release(g, &base); api_release(g, &idx);