kit

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

commit ac1e312614a908ba4f64f796ebb3fb3a37684ec9
parent 244f103980455c31f5f0ef75d128bd5fad50bc0a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 15 Jun 2026 13:42:37 -0700

cg: fold the type identity memo into the KitCgTypeInfo prefix

Now that the public KitCgTypeInfo is CgApiType's first member, route
kit_cg_type_info's identity fill through kit_cg_type_view and collapse the
duplicated per-entry memos:

- api_unalias_type and kit_cg_type_view share one api_type_info_fill helper
  (a single alias/source-base chain walk). The alias-resolved terminal id is
  the prefix's info.storage_id, gated by info.id != 0, so the separate
  unaliased/unalias_filled cache is removed.
- kit_cg_type_info copies identity from the view (*out = *v) and computes only
  the completion/sizing flags and ABI layout per call. Byte-identical output;
  the SOURCE_BASE NOMINAL case is preserved by the shared fill helper.
- Drop the write-only CgApiTypeKind field and enum (dead since the structural
  hashset dedup: the eq/hash callbacks never read it and the array/func sets
  are disjoint by construction).

test-cg-api / test-opt / test-parse green.

Diffstat:
Msrc/cg/type.c | 139+++++++++++++++++++++++++++++++++----------------------------------------------
1 file changed, 58 insertions(+), 81 deletions(-)

diff --git a/src/cg/type.c b/src/cg/type.c @@ -3,16 +3,6 @@ #include "core/hashmap.h" #include "obj/obj.h" -typedef enum CgApiTypeKind { - CG_API_TYPE_PTR, - CG_API_TYPE_ARRAY, - CG_API_TYPE_ALIAS, - CG_API_TYPE_RECORD, - CG_API_TYPE_ENUM, - CG_API_TYPE_FUNC, - CG_API_TYPE_SOURCE_BASE, -} CgApiTypeKind; - typedef struct CgApiType { /* Public identity view (kit/cg.h). Kept as the FIRST member so a pointer to * the entry is a valid `const KitCgTypeInfo*` and kit_cg_type_view can hand @@ -34,7 +24,6 @@ typedef struct CgApiType { const KitCgFuncParam* params; KitCgFuncResult result; /* void builtin means no value */ KitCgCallConv call_conv; - u8 kind; u8 abi_variadic; /* Lazily-filled packed API_TYPE_CLASS_* memo (0 == not yet computed; the * VALID bit distinguishes a computed all-zero class from unfilled). Reuses @@ -47,17 +36,14 @@ typedef struct CgApiType { u8 abi_atomic; /* Lazily-filled flat predicate descriptor (reuses the former pad[3]). Extends * the cached_class mechanism: pred_bits is a bitset of API_PRED_* computed on - * the UNALIASED type, pred_valid distinguishes a computed all-zero set from - * unfilled, and `unaliased` caches api_unalias_type's terminal id (valid once - * unalias_filled is set). Predicates and api_unalias_type then become one - * descriptor load instead of a recursive alias walk + per-kind re-decode. */ + * the UNALIASED type, and pred_valid distinguishes a computed all-zero set + * from unfilled. The alias-resolved terminal id that api_unalias_type returns + * is the prefix's info.storage_id (filled, with the rest of the identity, when + * info.id != 0) — there is no separate unaliased/unalias_filled cache. */ u8 pred_bits; u8 pred_valid; - u8 unalias_filled; u32 abi_size; u32 abi_align; - /* Terminal id of this entry's alias chain (set when unalias_filled). */ - KitCgTypeId unaliased; /* This entry's own type id (set by type_alloc). Lets a structural hashset of * CgApiType* recover the id without maintaining a reverse index. */ KitCgTypeId self_id; @@ -573,7 +559,6 @@ static KitCgTypeId find_array_type_id(Compiler* c, KitCgTypeId elem, if (!c || !c->cg_api) return KIT_CG_TYPE_NONE; s = (CgApiState*)c->cg_api; memset(&probe, 0, sizeof probe); - probe.kind = CG_API_TYPE_ARRAY; probe.base = elem; probe.array_count = count; hit = CgArraySet_find(&s->array_index, &probe); @@ -606,8 +591,8 @@ static int cg_array_eq(CgApiType* const a, CgApiType* const b) { } /* Structural hash/eq over a function type's identity — the same fields the old - * linear scan compared. Only CG_API_TYPE_FUNC entries enter the set, so neither - * callback re-checks kind. The result/param attrs are compared (not hashed): + * linear scan compared. Only function types enter this set, so neither callback + * needs to re-check kind. The result/param attrs are compared (not hashed): * fewer hash inputs just means eq resolves the (rare) collision. */ static u32 cg_func_hash(CgApiType* const e) { u32 h = 2166136261u; @@ -636,7 +621,6 @@ static KitCgTypeId find_func_type_id(Compiler* c, KitCgFuncSig sig) { if (!c || !c->cg_api) return KIT_CG_TYPE_NONE; s = (CgApiState*)c->cg_api; memset(&probe, 0, sizeof probe); - probe.kind = CG_API_TYPE_FUNC; probe.count = sig.nparams; probe.abi_variadic = (u8)(sig.abi_variadic != 0); probe.call_conv = sig.call_conv; @@ -662,35 +646,45 @@ KitCgTypeId resolve_type(Compiler* c, KitCgTypeId id) { return cg_type_get(c, id) ? id : KIT_CG_TYPE_NONE; } +/* Fill an entry's identity prefix (the kit/cg.h KitCgTypeInfo) once. storage_id + * strips both alias and source-base spellings to the terminal storage type, so + * every ABI/codegen/predicate site that unaliases sees the underlying builtin + * with no source-base special-casing. Identity is immutable after creation, so + * this runs at most once per entry (info.id != 0 thereafter). */ +static void api_type_info_fill(Compiler* c, CgApiType* e, KitCgTypeId id) { + const CgType* ty = &e->cg; /* == cg_type_get(c, id) for a user id */ + KitCgTypeId sid = id; + e->info.id = id; + e->info.kind = e->cg.kind; + if (e->cg.kind == KIT_CG_TYPE_RECORD || e->cg.kind == KIT_CG_TYPE_ENUM || + e->cg.kind == KIT_CG_TYPE_ALIAS || e->cg.kind == KIT_CG_TYPE_SOURCE_BASE) + e->info.flags = KIT_CG_TYPEF_NOMINAL; + while (ty && (ty->kind == KIT_CG_TYPE_ALIAS || + ty->kind == KIT_CG_TYPE_SOURCE_BASE)) { + sid = ty->kind == KIT_CG_TYPE_ALIAS ? ty->alias.base : ty->source_base.base; + ty = cg_type_get(c, sid); + } + e->info.storage_id = ty ? sid : KIT_CG_TYPE_NONE; +} + +/* The CgApiType for a user id with its identity prefix filled, or NULL. */ +static CgApiType* api_type_entry_filled(Compiler* c, KitCgTypeId id) { + CgApiType* e = api_type_from_id(c, id); + if (!e) return NULL; + if (e->info.id == 0) api_type_info_fill(c, e, id); + return e; +} + KitCgTypeId api_unalias_type(Compiler* c, KitCgTypeId id) { - CgApiType* e; const CgType* ty; - KitCgTypeId start = id; - /* Builtins are never aliases — no entry, no chain to walk or cache. */ + CgApiType* e; + /* Builtins are never aliases — no entry, no chain to walk. */ if (id == KIT_CG_TYPE_NONE || id <= KIT_CG_BUILTIN_COUNT) { ty = cg_type_get(c, id); return ty ? id : KIT_CG_TYPE_NONE; } - e = api_type_from_id(c, id); - if (e && e->unalias_filled) return e->unaliased; - ty = cg_type_get(c, id); - /* Both aliases and source-base spellings are transparent to storage: strip - * them to the terminal storage type so every ABI/codegen/predicate site that - * unaliases sees the underlying builtin with no source-base special-casing. */ - while (ty && (ty->kind == KIT_CG_TYPE_ALIAS || - ty->kind == KIT_CG_TYPE_SOURCE_BASE)) { - id = ty->kind == KIT_CG_TYPE_ALIAS ? ty->alias.base : ty->source_base.base; - ty = cg_type_get(c, id); - } - id = ty ? id : KIT_CG_TYPE_NONE; - /* Cache on the entry for the start id. (start == the original id; e was - * fetched for it above. Only fill for a real entry.) */ - if (e) { - e->unaliased = id; - e->unalias_filled = 1; - } - (void)start; - return id; + e = api_type_entry_filled(c, id); + return e ? e->info.storage_id : KIT_CG_TYPE_NONE; } static KitCgFuncParam* copy_cg_params(Compiler* c, const KitCgFuncParam* src, @@ -1037,7 +1031,6 @@ KitCgTypeId kit_cg_type_ptr(KitCompiler* c, KitCgTypeId pointee, if (!e) return KIT_CG_TYPE_NONE; e->base = pointee; e->address_space = address_space; - e->kind = CG_API_TYPE_PTR; if (!cg_type_set_ptr(c, e, pointee, address_space)) { return KIT_CG_TYPE_NONE; } @@ -1057,7 +1050,6 @@ KitCgTypeId kit_cg_type_array(KitCompiler* c, KitCgTypeId elem, if (!e) return KIT_CG_TYPE_NONE; e->base = elem; e->array_count = count; - e->kind = CG_API_TYPE_ARRAY; if (!cg_type_set_array(c, e, elem, count)) { return KIT_CG_TYPE_NONE; } @@ -1073,7 +1065,6 @@ KitCgTypeId kit_cg_type_alias(KitCompiler* c, KitSym name, KitCgTypeId base) { if (!e) return KIT_CG_TYPE_NONE; e->base = base; e->name = name; - e->kind = CG_API_TYPE_ALIAS; return cg_type_set_alias(c, e, name, base) ? id : KIT_CG_TYPE_NONE; } @@ -1090,7 +1081,6 @@ KitCgTypeId kit_cg_type_source_base(KitCompiler* c, KitSym name, if (!e) return KIT_CG_TYPE_NONE; e->base = storage; e->name = name; - e->kind = CG_API_TYPE_SOURCE_BASE; return cg_type_set_source_base(c, e, name, storage, (u8)encoding) ? id : KIT_CG_TYPE_NONE; @@ -1105,7 +1095,6 @@ KitCgTypeId kit_cg_type_record_decl(KitCompiler* c, KitSym tag, int is_union) { e->name = tag; e->count = 0; e->fields = NULL; - e->kind = CG_API_TYPE_RECORD; memset(&e->cg, 0, sizeof(e->cg)); e->cg.kind = KIT_CG_TYPE_RECORD; e->cg.record.tag = tag; @@ -1167,7 +1156,6 @@ KitCgTypeId kit_cg_type_enum(KitCompiler* c, KitSym tag, KitCgTypeId base, e->name = tag; e->count = nvalues; e->values = copied; - e->kind = CG_API_TYPE_ENUM; if (!cg_type_set_enum(c, e, tag, base, copied, nvalues)) { return KIT_CG_TYPE_NONE; } @@ -1202,7 +1190,6 @@ KitCgTypeId kit_cg_type_func(KitCompiler* c, KitCgFuncSig sig) { e->result = sig.result; e->call_conv = sig.call_conv; e->abi_variadic = sig.abi_variadic != 0; - e->kind = CG_API_TYPE_FUNC; if (!cg_type_set_func(c, e, sig, copied)) { return KIT_CG_TYPE_NONE; } @@ -1232,17 +1219,8 @@ const KitCgTypeInfo* kit_cg_type_view(KitCompiler* kc, KitCgTypeId id) { s = c->cg_api ? (CgApiState*)c->cg_api : cg_api_get(c); if (!s) return NULL; if (id <= KIT_CG_BUILTIN_COUNT) return &s->builtin_info[id - 1u]; - e = api_type_from_id(c, id); - if (!e) return NULL; - if (e->info.id == 0) { - e->info.id = id; - e->info.storage_id = api_unalias_type(c, id); - e->info.kind = e->cg.kind; - if (e->cg.kind == KIT_CG_TYPE_RECORD || e->cg.kind == KIT_CG_TYPE_ENUM || - e->cg.kind == KIT_CG_TYPE_ALIAS) - e->info.flags = KIT_CG_TYPEF_NOMINAL; - } - return &e->info; + e = api_type_entry_filled(c, id); + return e ? &e->info : NULL; } int kit_cg_type_is_complete(KitCompiler* c, KitCgTypeId id) { @@ -1291,30 +1269,29 @@ static uint16_t cg_type_scalar_width(Compiler* c, const CgType* ty) { KitStatus kit_cg_type_info(KitCompiler* kc, KitCgTypeId id, KitCgTypeInfo* out) { Compiler* c = (Compiler*)kc; - const CgType* exact; + const KitCgTypeInfo* v; const CgType* storage; - KitCgTypeId storage_id; ABITypeInfo ti; if (!out) return KIT_INVALID; - memset(out, 0, sizeof(*out)); - exact = cg_type_get(c, id); - if (!exact) return KIT_INVALID; - storage_id = api_unalias_type(c, id); - storage = cg_type_get(c, storage_id); - if (!storage) return KIT_INVALID; - - out->id = id; - out->storage_id = storage_id; - out->kind = exact->kind; - if (id <= KIT_CG_BUILTIN_COUNT) out->flags |= KIT_CG_TYPEF_BUILTIN; - if (exact->kind == KIT_CG_TYPE_RECORD || exact->kind == KIT_CG_TYPE_ENUM || - exact->kind == KIT_CG_TYPE_ALIAS || - exact->kind == KIT_CG_TYPE_SOURCE_BASE) - out->flags |= KIT_CG_TYPEF_NOMINAL; + v = kit_cg_type_view(kc, id); + if (!v) { + memset(out, 0, sizeof(*out)); + return KIT_INVALID; + } + storage = cg_type_get(c, v->storage_id); + if (!storage) { + memset(out, 0, sizeof(*out)); + return KIT_INVALID; + } + + /* Identity (id/storage_id/kind and the BUILTIN/NOMINAL flags) comes straight + * from the view's interned prefix; only the completion/sizing flags and the + * ABI layout are computed per call (they are not maintained on the view). */ + *out = *v; if (cg_type_complete_id(c, id)) out->flags |= KIT_CG_TYPEF_COMPLETE; if (cg_type_sized_id(c, id)) out->flags |= KIT_CG_TYPEF_SIZED; - ti = abi_cg_type_info(c->abi, storage_id); + ti = abi_cg_type_info(c->abi, v->storage_id); if (ti.align || storage->kind == KIT_CG_TYPE_VOID) { out->layout.size = ti.size; out->layout.align = ti.align;