kit

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

commit fb17391cb69f024c19807c67bda922243b50d655
parent 6d3a2b1b89cd31db1855b9a57a11abeb1602c9d1
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sat, 13 Jun 2026 10:00:59 -0700

perf(cg): -O0 memoize builtin predicate bitsets (kill api_type_pred reclassify)

api_type_pred's builtin fast path re-derived the predicate bitset on EVERY
call via cg_type_get + api_pred_bits_for_kind. Builtins (int/char/long/
double/...) are the most-frequent operand types, so this reclassify dominated
the 66.8M-Ir api_type_pred hub the prior wave's O(1) descriptor surfaced.

Precompute a builtin_pred[] bitset at builtin init (mirroring builtin_class[]),
and have the predicate query read it with one indexed load. Builtins are never
aliases, so the bitset is the exact, final value; semantics are bit-identical
to the old api_pred_bits_for_kind(cg_type_get(...)) path.

Gate: full byte-identity gate PASS; test-cg-api 211/0.

Diffstat:
Msrc/cg/type.c | 16+++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/cg/type.c b/src/cg/type.c @@ -106,6 +106,11 @@ typedef struct CgApiState { /* Packed API_TYPE_CLASS_* per builtin, precomputed at init so the hottest * operand types (i32/i64/f64/ptr/...) classify with a single indexed load. */ u8 builtin_class[KIT_CG_BUILTIN_COUNT]; + /* Packed API_PRED_* bitset per builtin, precomputed at init so the (very hot) + * cg_type_is_* predicate queries on the most-frequent operand types resolve + * with a single indexed load instead of a cg_type_get + per-kind re-classify + * on every call. Builtins are never aliases, so the bitset is exact. */ + u8 builtin_pred[KIT_CG_BUILTIN_COUNT]; u8 builtins_init; u8 pad[3]; } CgApiState; @@ -218,6 +223,7 @@ static void builtin_cg_type_init(Compiler* c, CgType* out, KitCgBuiltinType t) { static CgApiState* cg_api_get(Compiler* c); static CgApiType* api_type_from_id(Compiler* c, KitCgTypeId id); +static u8 api_pred_bits_for_kind(const CgType* ty); /* ---- codegen scalar type-property predicates ---- * Thin queries over the resolved CgType / target ABI; pure functions of @@ -309,6 +315,10 @@ static void cg_api_init_builtins(Compiler* c, CgApiState* s) { * builtin, so it is ready). */ for (u32 i = 0; i < KIT_CG_BUILTIN_COUNT; ++i) { s->builtin_class[i] = api_compute_type_class(c, builtin_id((KitCgBuiltinType)i)); + /* Builtins are never aliases, so the kind-derived predicate bitset is the + * exact, final value — classify the node once here, then every predicate + * query is one indexed load (see api_type_pred). */ + s->builtin_pred[i] = api_pred_bits_for_kind(&s->builtins[i]); } s->builtins_init = 1; } @@ -444,7 +454,11 @@ static int api_type_pred(Compiler* c, KitCgTypeId id, u8 mask) { CgApiType* e; if (id == KIT_CG_TYPE_NONE) return 0; if ((id >> CG_API_TYPE_SEG_SHIFT) == CG_API_TYPE_BUILTIN_SEG) { - /* Builtins are never aliases; classify the node directly. */ + /* Builtins are never aliases; their predicate bitset is precomputed at + * init, so this is one indexed load (no cg_type_get + re-classify). */ + u32 off = id & CG_API_TYPE_SEG_MASK; + CgApiState* s = c->cg_api ? (CgApiState*)c->cg_api : cg_api_get(c); + if (s && off < KIT_CG_BUILTIN_COUNT) return (s->builtin_pred[off] & mask) != 0; return (api_pred_bits_for_kind(cg_type_get(c, id)) & mask) != 0; } e = api_type_from_id(c, id);