kit

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

type.c (52900B)


      1 #include "arch/arch.h"
      2 #include "cg/internal.h"
      3 #include "core/hashmap.h"
      4 #include "obj/obj.h"
      5 
      6 typedef struct CgApiType {
      7   /* Public identity view (kit/cg.h). Kept as the FIRST member so a pointer to
      8    * the entry is a valid `const KitCgTypeInfo*` and kit_cg_type_view can hand
      9    * it back without a copy. Identity (id/storage_id/kind/flags) is filled once,
     10    * lazily, by kit_cg_type_view; layout and the COMPLETE/SIZED flags are not
     11    * maintained here (see the view's contract) — kit_cg_type_info computes
     12    * those. info.id == 0 marks the entry as not yet filled (a valid id is
     13    * never 0, and segvec slots are zero-initialized). */
     14   KitCgTypeInfo info;
     15   CgType cg;
     16   /* Lazily-filled packed API_TYPE_CLASS_* memo (0 == not yet computed; the
     17    * VALID bit distinguishes a computed all-zero class from unfilled). */
     18   u8 cached_class;
     19   /* Lazily-filled abi_cg_type_info memo (see api_type_layout_ref/put): `abi`
     20    * holds the cached size/align/scalar profile, valid iff abi_cached. */
     21   u8 abi_cached;
     22   /* Lazily-filled flat predicate descriptor. Extends the cached_class
     23    * mechanism: pred_bits is a bitset of API_PRED_* computed on the exact
     24    * operational type, and pred_valid distinguishes a computed all-zero set from
     25    * unfilled. */
     26   u8 pred_bits;
     27   u8 pred_valid;
     28   ABITypeInfo abi;
     29   /* This entry's own type id (set by type_alloc). Lets a structural hashset of
     30    * CgApiType* recover the id without maintaining a reverse index. */
     31   KitCgTypeId self_id;
     32 } CgApiType;
     33 
     34 /* The flat per-id predicate bitset (API_PRED_*) and api_type_pred_bits live in
     35  * cg/type.h so multi-predicate-on-same-id call sites can decode an id once. */
     36 
     37 /* High bit of CgApiType.cached_class: set once the class has been computed, so
     38  * a genuine {WK_NARROW, non-aggregate} (packed 0) is told apart from unfilled.
     39  */
     40 #define API_TYPE_CLASS_CACHED 0x80u
     41 
     42 enum { CG_API_TYPES_SEG_SHIFT = 6 };
     43 
     44 SEGVEC_DEFINE(CgApiTypes, CgApiType, CG_API_TYPES_SEG_SHIFT);
     45 
     46 /* Structural dedup of derived ptr/array types, O(1) instead of a linear scan of
     47  * the whole type table on every derivation (which made each derived-type use
     48  * O(#types) — the dominant frontend hotspot on type-heavy input like sqlite).
     49  * Pointer keys fit in a u64: ptr = (pointee<<32)|addr_sp. Arrays use the
     50  * structural hashset below so their full uint64_t count participates in
     51  * identity. */
     52 static inline u64 cg_ptr_key(KitCgTypeId pointee, u32 address_space) {
     53   return ((u64)pointee << 32) | (u64)address_space;
     54 }
     55 KIT_HASHMAP_DEFINE(CgPtrMap, u64, KitCgTypeId, hash_u64);
     56 
     57 /* Array and function types have structural keys that a scalar hashmap cannot
     58  * express (array counts are full uint64_t; function keys include attrs), so
     59  * dedup them through structural hashsets of the stored CgApiType* (SEGVEC
     60  * entries have stable addresses). The callbacks are defined further down. */
     61 static u32 cg_array_hash(CgApiType* const e);
     62 static int cg_array_eq(CgApiType* const a, CgApiType* const b);
     63 static u32 cg_func_hash(CgApiType* const e);
     64 static int cg_func_eq(CgApiType* const a, CgApiType* const b);
     65 KIT_HASHSET_DEFINE(CgArraySet, CgApiType*, cg_array_hash, cg_array_eq);
     66 KIT_HASHSET_DEFINE(CgFuncSet, CgApiType*, cg_func_hash, cg_func_eq);
     67 
     68 typedef struct CgApiState {
     69   Heap* heap;
     70   CgApiTypes types;
     71   /* Structural dedup indexes for derived ptr/array/func types (see above). */
     72   CgPtrMap ptr_index;
     73   CgArraySet array_index;
     74   CgFuncSet func_index;
     75   CgType builtins[KIT_CG_BUILTIN_COUNT];
     76   /* Per-builtin identity view returned by kit_cg_type_view: builtins are stored
     77    * as bare CgType (no CgApiType entry to point at), so their stable
     78    * KitCgTypeInfo backing lives here, precomputed at init. */
     79   KitCgTypeInfo builtin_info[KIT_CG_BUILTIN_COUNT];
     80   /* Packed API_TYPE_CLASS_* per builtin, precomputed at init so the hottest
     81    * operand types (i32/i64/f64/ptr/...) classify with a single indexed load. */
     82   u8 builtin_class[KIT_CG_BUILTIN_COUNT];
     83   /* Packed API_PRED_* bitset per builtin, precomputed at init so the (very hot)
     84    * cg_type_is_* predicate queries on the most-frequent operand types resolve
     85    * with a single indexed load instead of a cg_type_get + per-kind re-classify
     86    * on every call. Builtins are never aliases, so the bitset is exact. */
     87   u8 builtin_pred[KIT_CG_BUILTIN_COUNT];
     88   /* Per-builtin ABI layout, precomputed at init so abi_cg_type_info can hit the
     89    * same memo path for builtin scalars as it does for user types. */
     90   ABITypeInfo builtin_layout[KIT_CG_BUILTIN_COUNT];
     91   u8 builtins_init;
     92   u8 pad[3];
     93 } CgApiState;
     94 
     95 KitCgTypeId builtin_id(KitCgBuiltinType t) {
     96   if ((u32)t >= KIT_CG_BUILTIN_COUNT) return KIT_CG_TYPE_NONE;
     97   return (KitCgTypeId)((u32)t + 1u);
     98 }
     99 
    100 static int decode_user_id(KitCgTypeId id, u32* index_out) {
    101   if (!index_out) return 0;
    102   if (id <= KIT_CG_BUILTIN_COUNT) return 0;
    103   *index_out = id - (KitCgTypeId)KIT_CG_BUILTIN_COUNT - 1u;
    104   return 1;
    105 }
    106 
    107 static KitCgTypeId user_id_from_index(u32 index) {
    108   if (index > UINT32_MAX - (u32)KIT_CG_BUILTIN_COUNT - 1u)
    109     return KIT_CG_TYPE_NONE;
    110   return (KitCgTypeId)((u32)KIT_CG_BUILTIN_COUNT + 1u + index);
    111 }
    112 
    113 static u64 cg_align_to(u64 n, u32 align) {
    114   u64 a = align ? (u64)align : 1u;
    115   return ((n + a - 1u) / a) * a;
    116 }
    117 
    118 static void builtin_cg_type_init(Compiler* c, CgType* out, KitCgBuiltinType t) {
    119   memset(out, 0, sizeof(*out));
    120   switch (t) {
    121     case KIT_CG_BUILTIN_VOID:
    122       out->kind = KIT_CG_TYPE_VOID;
    123       out->align = 1;
    124       break;
    125     case KIT_CG_BUILTIN_BOOL:
    126       out->kind = KIT_CG_TYPE_BOOL;
    127       out->size = 1;
    128       out->align = 1;
    129       out->integer.width = 8;
    130       break;
    131     case KIT_CG_BUILTIN_I8:
    132       out->kind = KIT_CG_TYPE_INT;
    133       out->size = 1;
    134       out->align = 1;
    135       out->integer.width = 8;
    136       break;
    137     case KIT_CG_BUILTIN_I16:
    138       out->kind = KIT_CG_TYPE_INT;
    139       out->size = 2;
    140       out->align = 2;
    141       out->integer.width = 16;
    142       break;
    143     case KIT_CG_BUILTIN_I32:
    144       out->kind = KIT_CG_TYPE_INT;
    145       out->size = 4;
    146       out->align = 4;
    147       out->integer.width = 32;
    148       break;
    149     case KIT_CG_BUILTIN_I64:
    150       out->kind = KIT_CG_TYPE_INT;
    151       out->size = 8;
    152       out->align = 8;
    153       out->integer.width = 64;
    154       break;
    155     case KIT_CG_BUILTIN_I128:
    156       out->kind = KIT_CG_TYPE_INT;
    157       out->size = 16;
    158       out->align = 16;
    159       out->integer.width = 128;
    160       break;
    161     case KIT_CG_BUILTIN_F32:
    162       out->kind = KIT_CG_TYPE_FLOAT;
    163       out->size = 4;
    164       out->align = 4;
    165       out->fp.width = 32;
    166       break;
    167     case KIT_CG_BUILTIN_F64:
    168       out->kind = KIT_CG_TYPE_FLOAT;
    169       out->size = 8;
    170       out->align = 8;
    171       out->fp.width = 64;
    172       break;
    173     case KIT_CG_BUILTIN_F128:
    174       out->kind = KIT_CG_TYPE_FLOAT;
    175       out->size = 16;
    176       out->align = 16;
    177       out->fp.width = 128;
    178       break;
    179     case KIT_CG_BUILTIN_VARARG_STATE: {
    180       ABITypeInfo info = abi_va_list_info(c->abi);
    181       out->kind = KIT_CG_TYPE_VARARG_STATE;
    182       out->size = info.size;
    183       out->align = info.align ? info.align : 1;
    184       break;
    185     }
    186     case KIT_CG_BUILTIN_COUNT:
    187       break;
    188   }
    189 }
    190 
    191 static CgApiState* cg_api_get(Compiler* c);
    192 static CgApiType* api_type_from_id(Compiler* c, KitCgTypeId id);
    193 static u8 api_pred_bits_for_kind(const CgType* ty);
    194 
    195 static ABITypeInfo api_builtin_layout_info(Compiler* c, const CgType* t) {
    196   ABITypeInfo r = {0, 0, ABI_SC_VOID, 0, 0, 0};
    197   if (!t) return r;
    198   switch (t->kind) {
    199     case KIT_CG_TYPE_PTR:
    200       r.size = c->target.ptr_size ? c->target.ptr_size : 8;
    201       r.align = c->target.ptr_align ? c->target.ptr_align : 8;
    202       r.scalar_kind = ABI_SC_PTR;
    203       return r;
    204     case KIT_CG_TYPE_VOID:
    205       r.align = 1;
    206       r.scalar_kind = ABI_SC_VOID;
    207       return r;
    208     case KIT_CG_TYPE_BOOL:
    209       r.size = t->size;
    210       r.align = t->align;
    211       r.scalar_kind = ABI_SC_BOOL;
    212       return r;
    213     case KIT_CG_TYPE_INT:
    214       r.size = t->size;
    215       r.align = t->align;
    216       r.scalar_kind = ABI_SC_INT;
    217       return r;
    218     case KIT_CG_TYPE_FLOAT:
    219       r.size = t->size;
    220       r.align = t->align;
    221       r.scalar_kind = ABI_SC_FLOAT;
    222       return r;
    223     case KIT_CG_TYPE_VARARG_STATE:
    224       r.size = t->size;
    225       r.align = t->align;
    226       return r;
    227     default:
    228       return r;
    229   }
    230 }
    231 
    232 /* ---- codegen scalar type-property predicates ----
    233  * Thin queries over the resolved CgType / target ABI; pure functions of
    234  * (type, target). The wide-class predicates below feed api_wide_kind_for, which
    235  * feeds the memoized api_type_class. */
    236 
    237 int api_type_is_float(Compiler* c, KitCgTypeId ty) {
    238   const CgType* cg;
    239   cg = cg_type_get(c, ty);
    240   return cg && cg->kind == KIT_CG_TYPE_FLOAT;
    241 }
    242 
    243 int api_is_f128_type(Compiler* c, KitCgTypeId ty) {
    244   const CgType* cg;
    245   cg = cg_type_get(c, ty);
    246   return cg && cg->kind == KIT_CG_TYPE_FLOAT && cg->fp.width == 128;
    247 }
    248 
    249 int api_is_i128_type(Compiler* c, KitCgTypeId ty) {
    250   const CgType* cg;
    251   cg = cg_type_get(c, ty);
    252   return cg && cg->kind == KIT_CG_TYPE_INT && cg->integer.width == 128;
    253 }
    254 
    255 int api_is_wide16_scalar_type(Compiler* c, KitCgTypeId ty) {
    256   return api_is_f128_type(c, ty) || api_is_i128_type(c, ty);
    257 }
    258 
    259 /* 8-byte scalar split into two 4-byte lanes by the selected ABI. This covers
    260  * 32-bit native ABIs whose generic CG path cannot keep the value in a single
    261  * scalar register/value. Such values are forced memory-resident so operations
    262  * can be legalized as lane sequences or runtime calls. */
    263 int api_is_wide8_scalar_type(Compiler* c, KitCgTypeId ty) {
    264   ABITypeInfo ti;
    265   if (!c || !c->abi || !ty) return 0;
    266   if (abi_cg_scalar_split_lane_size(c->abi, ty) != 4u) return 0;
    267   ti = abi_cg_type_info(c->abi, ty);
    268   return ti.size == 8u &&
    269          (ti.scalar_kind == ABI_SC_INT || ti.scalar_kind == ABI_SC_FLOAT);
    270 }
    271 
    272 /* Classify a scalar into its mutually-exclusive wide / soft-float dispatch
    273  * class. Reproduces the predicates exactly: WK_I128/WK_F128 are the 128-bit
    274  * scalars; WK_WIDE8 is an int-width-bearing split-lane scalar (excluding i128,
    275  * handled above; a split-lane *float* bears int width 0 and falls through to a
    276  * soft class); WK_SOFT_DOUBLE/WK_SOFT_SINGLE are f64/f32 with no hardware FP of
    277  * that width. Only api_compute_type_class calls this. */
    278 static u8 api_wide_kind_for(Compiler* c, KitCgTypeId ty) {
    279   u8 fa;
    280   if (!c || !ty) return WK_NARROW;
    281   if (api_is_i128_type(c, ty)) return WK_I128;
    282   if (api_is_f128_type(c, ty)) return WK_F128;
    283   if (kit_cg_type_int_width((KitCompiler*)c, ty) != 0 &&
    284       api_is_wide8_scalar_type(c, ty)) {
    285     return WK_WIDE8;
    286   }
    287   fa = c->target.float_abi;
    288   if ((fa == KIT_FLOAT_ABI_SOFT || fa == KIT_FLOAT_ABI_SINGLE) &&
    289       kit_cg_type_float_width((KitCompiler*)c, ty) == 64) {
    290     return WK_SOFT_DOUBLE;
    291   }
    292   if (fa == KIT_FLOAT_ABI_SOFT &&
    293       kit_cg_type_float_width((KitCompiler*)c, ty) == 32) {
    294     return WK_SOFT_SINGLE;
    295   }
    296   return WK_NARROW;
    297 }
    298 
    299 /* Compute the packed API_TYPE_CLASS_* byte for `ty` from scratch: the wide /
    300  * soft-float dispatch class plus the aggregate-place bit. Both are pure
    301  * functions of (type, target), so callers memoize the result (per builtin at
    302  * init, per user type lazily) rather than re-run this on every value push. */
    303 static u8 api_compute_type_class(Compiler* c, KitCgTypeId ty) {
    304   u8 cls = api_wide_kind_for(c, ty) & API_TYPE_CLASS_WIDE_MASK;
    305   if (cg_type_is_aggregate(c, ty)) cls |= API_TYPE_CLASS_AGGREGATE;
    306   return cls;
    307 }
    308 
    309 static void cg_api_init_builtins(Compiler* c, CgApiState* s) {
    310   if (s->builtins_init) return;
    311   for (u32 i = 0; i < KIT_CG_BUILTIN_COUNT; ++i) {
    312     builtin_cg_type_init(c, &s->builtins[i], (KitCgBuiltinType)i);
    313   }
    314   for (u32 i = 0; i < KIT_CG_BUILTIN_COUNT; ++i) {
    315     s->builtin_layout[i] = api_builtin_layout_info(c, &s->builtins[i]);
    316   }
    317   /* Publish the filled table so abi_cg_type_info can index it inline (one load,
    318    * no cross-TU call) for the common builtin case. NULLed in cg_api_fini. */
    319   c->cg_builtin_layout = s->builtin_layout;
    320   /* Precompute each builtin's class now that the builtin table and the ABI are
    321    * both live (builtin_cg_type_init already consults c->abi for the va_list
    322    * builtin, so it is ready). */
    323   for (u32 i = 0; i < KIT_CG_BUILTIN_COUNT; ++i) {
    324     s->builtin_class[i] =
    325         api_compute_type_class(c, builtin_id((KitCgBuiltinType)i));
    326     /* Builtins are never aliases, so the kind-derived predicate bitset is the
    327      * exact, final value — classify the node once here, then every predicate
    328      * query is one indexed load (see api_type_pred). */
    329     s->builtin_pred[i] = api_pred_bits_for_kind(&s->builtins[i]);
    330     /* Stable identity view for kit_cg_type_view. storage_id == id;
    331      * layout/complete/sized are left to kit_cg_type_info. */
    332     s->builtin_info[i].id = builtin_id((KitCgBuiltinType)i);
    333     s->builtin_info[i].storage_id = s->builtin_info[i].id;
    334     s->builtin_info[i].kind = s->builtins[i].kind;
    335     s->builtin_info[i].flags = KIT_CG_TYPEF_BUILTIN;
    336   }
    337   s->builtins_init = 1;
    338 }
    339 
    340 u8 api_type_class(Compiler* c, KitCgTypeId ty) {
    341   CgApiState* s;
    342   CgApiType* e;
    343   if (ty == KIT_CG_TYPE_NONE) return 0;
    344   s = c->cg_api ? (CgApiState*)c->cg_api : cg_api_get(c);
    345   if (!s) return api_compute_type_class(c, ty);
    346   if (ty <= KIT_CG_BUILTIN_COUNT) {
    347     u32 off = ty - 1u;
    348     if (off < KIT_CG_BUILTIN_COUNT) return s->builtin_class[off];
    349     return api_compute_type_class(c, ty);
    350   }
    351   e = api_type_from_id(c, ty);
    352   if (!e) return api_compute_type_class(c, ty);
    353   if (!(e->cached_class & API_TYPE_CLASS_CACHED))
    354     e->cached_class = API_TYPE_CLASS_CACHED | api_compute_type_class(c, ty);
    355   return (u8)(e->cached_class & ~API_TYPE_CLASS_CACHED);
    356 }
    357 
    358 const ABITypeInfo* api_type_layout_ref(Compiler* c, KitCgTypeId ty) {
    359   CgApiState* s;
    360   CgApiType* e;
    361   if (!c || ty == KIT_CG_TYPE_NONE) return NULL;
    362   if (ty <= KIT_CG_BUILTIN_COUNT) {
    363     s = c->cg_api ? (CgApiState*)c->cg_api : cg_api_get(c);
    364     return s ? &s->builtin_layout[ty - 1u] : NULL;
    365   }
    366   e = api_type_from_id(c, ty);
    367   return (e && e->abi_cached) ? &e->abi : NULL;
    368 }
    369 
    370 void api_type_layout_put(Compiler* c, KitCgTypeId ty, ABITypeInfo info) {
    371   CgApiType* e;
    372   if (!c || ty == KIT_CG_TYPE_NONE) return;
    373   if (ty <= KIT_CG_BUILTIN_COUNT) return;
    374   if (!info.align && info.scalar_kind == ABI_SC_VOID) return;
    375   e = api_type_from_id(c, ty);
    376   if (!e) return;
    377   e->abi = info;
    378   e->abi_cached = 1;
    379 }
    380 
    381 static CgApiState* cg_api_get(Compiler* c) {
    382   Heap* h;
    383   CgApiState* s;
    384   if (!c) return NULL;
    385   if (c->cg_api) return (CgApiState*)c->cg_api;
    386   h = (Heap*)c->ctx->heap;
    387   s = (CgApiState*)h->alloc(h, sizeof(*s), _Alignof(CgApiState));
    388   if (!s) return NULL;
    389   memset(s, 0, sizeof(*s));
    390   s->heap = h;
    391   CgApiTypes_init(&s->types, h);
    392   CgPtrMap_init(&s->ptr_index, h);
    393   CgArraySet_init(&s->array_index, h);
    394   CgFuncSet_init(&s->func_index, h);
    395   c->cg_api = s;
    396   c->cg_api_free = cg_api_fini;
    397   cg_api_init_builtins(c, s);
    398   return s;
    399 }
    400 
    401 const CgType* cg_type_get(Compiler* c, KitCgTypeId id) {
    402   u32 off;
    403   CgApiState* s;
    404   CgApiType* e;
    405   if (!c || id == KIT_CG_TYPE_NONE) return NULL;
    406   if (id <= KIT_CG_BUILTIN_COUNT) {
    407     off = id - 1u;
    408     /* Fast path: the per-compiler state (with its builtin table) is created
    409      * on first use and then stays put, so inline the already-initialized case
    410      * -- the hot per-op type query becomes a load + index instead of a call
    411      * into cg_api_get. cg_api_get still handles lazy first-time creation. */
    412     s = c->cg_api ? (CgApiState*)c->cg_api : cg_api_get(c);
    413     if (!s) return NULL;
    414     return &s->builtins[off];
    415   }
    416   e = api_type_from_id(c, id);
    417   return e ? &e->cg : NULL;
    418 }
    419 
    420 uint64_t cg_type_size(Compiler* c, KitCgTypeId id) {
    421   return c && c->abi ? abi_cg_sizeof(c->abi, id) : 0;
    422 }
    423 
    424 uint32_t cg_type_align(Compiler* c, KitCgTypeId id) {
    425   return c && c->abi ? abi_cg_alignof(c->abi, id) : 0;
    426 }
    427 
    428 /* Predicate bitset of a single (already-unaliased) CgType node. The kind->bit
    429  * mapping reproduces the legacy cg_type_is_* predicates exactly. */
    430 static u8 api_pred_bits_for_kind(const CgType* ty) {
    431   if (!ty) return 0;
    432   switch (ty->kind) {
    433     case KIT_CG_TYPE_INT:
    434     case KIT_CG_TYPE_BOOL:
    435     case KIT_CG_TYPE_ENUM:
    436       return API_PRED_INT;
    437     case KIT_CG_TYPE_FLOAT:
    438       return API_PRED_FLOAT;
    439     case KIT_CG_TYPE_PTR:
    440       return API_PRED_PTR;
    441     case KIT_CG_TYPE_VOID:
    442       return API_PRED_VOID;
    443     case KIT_CG_TYPE_RECORD:
    444       return API_PRED_RECORD | API_PRED_AGGREGATE;
    445     default:
    446       return 0;
    447   }
    448 }
    449 
    450 /* Full API_PRED_* bitset for `id` via exactly one decode: builtin fast path (no
    451  * aliasing, no entry) or a descriptor load off the user-type entry, filled
    452  * lazily on first miss. Multi-predicate-on-the-same-id call sites read this
    453  * once and then test the masks locally instead of decoding `id` per predicate.
    454  */
    455 u8 api_type_pred_bits(Compiler* c, KitCgTypeId id) {
    456   CgApiType* e;
    457   if (id == KIT_CG_TYPE_NONE) return 0;
    458   if (id <= KIT_CG_BUILTIN_COUNT) {
    459     /* Builtin predicate bitsets are precomputed at init, so this is one indexed
    460      * load (no cg_type_get + re-classify). */
    461     u32 off = id - 1u;
    462     CgApiState* s = c->cg_api ? (CgApiState*)c->cg_api : cg_api_get(c);
    463     if (s && off < KIT_CG_BUILTIN_COUNT) return s->builtin_pred[off];
    464     return api_pred_bits_for_kind(cg_type_get(c, id));
    465   }
    466   e = api_type_from_id(c, id);
    467   if (!e) return 0;
    468   if (!e->pred_valid) {
    469     e->pred_bits = api_pred_bits_for_kind(cg_type_get(c, id));
    470     e->pred_valid = 1;
    471   }
    472   return e->pred_bits;
    473 }
    474 
    475 /* One predicate query for `id`: returns (bits & mask) != 0 off the
    476  * single-decode bitset. Mirrors api_type_class's CACHED-bit memo. */
    477 static int api_type_pred(Compiler* c, KitCgTypeId id, u8 mask) {
    478   return (api_type_pred_bits(c, id) & mask) != 0;
    479 }
    480 
    481 int cg_type_is_int(Compiler* c, KitCgTypeId id) {
    482   return api_type_pred(c, id, API_PRED_INT);
    483 }
    484 
    485 int cg_type_is_float(Compiler* c, KitCgTypeId id) {
    486   return api_type_pred(c, id, API_PRED_FLOAT);
    487 }
    488 
    489 int cg_type_is_ptr(Compiler* c, KitCgTypeId id) {
    490   return api_type_pred(c, id, API_PRED_PTR);
    491 }
    492 
    493 int cg_type_is_record(Compiler* c, KitCgTypeId id) {
    494   return api_type_pred(c, id, API_PRED_RECORD);
    495 }
    496 
    497 int cg_type_is_void(Compiler* c, KitCgTypeId id) {
    498   return api_type_pred(c, id, API_PRED_VOID);
    499 }
    500 
    501 int cg_type_is_aggregate(Compiler* c, KitCgTypeId id) {
    502   return api_type_pred(c, id, API_PRED_AGGREGATE);
    503 }
    504 
    505 KitCgTypeId cg_type_ptr_to(Compiler* c, KitCgTypeId pointee) {
    506   return kit_cg_type_ptr(c, pointee, 0);
    507 }
    508 
    509 KitCgTypeId cg_type_pointee(Compiler* c, KitCgTypeId id) {
    510   const CgType* ty = cg_type_get(c, id);
    511   return ty && ty->kind == KIT_CG_TYPE_PTR ? ty->ptr.pointee : KIT_CG_TYPE_NONE;
    512 }
    513 
    514 KitCgTypeId cg_type_func_ret_id(Compiler* c, KitCgTypeId id) {
    515   const CgType* ty = cg_type_get(c, id);
    516   if (!ty || ty->kind != KIT_CG_TYPE_FUNC) return KIT_CG_TYPE_NONE;
    517   return ty->func.result.type;
    518 }
    519 
    520 KitCgTypeId cg_func_ret_type(const CgType* fnty) {
    521   return fnty->func.result.type;
    522 }
    523 
    524 KitCgTypeId cg_type_func_result_id(Compiler* c, KitCgTypeId id) {
    525   const CgType* ty = cg_type_get(c, id);
    526   if (!ty || ty->kind != KIT_CG_TYPE_FUNC) return KIT_CG_TYPE_NONE;
    527   return ty->func.result.type;
    528 }
    529 
    530 KitCgTypeId cg_type_func_param_id(Compiler* c, KitCgTypeId id, u32 index) {
    531   const CgType* ty = cg_type_get(c, id);
    532   if (!ty || ty->kind != KIT_CG_TYPE_FUNC || index >= ty->func.nparams)
    533     return KIT_CG_TYPE_NONE;
    534   return ty->func.params[index].type;
    535 }
    536 
    537 static CgApiType* type_alloc(Compiler* c, KitCgTypeId* id_out) {
    538   CgApiState* s = cg_api_get(c);
    539   CgApiType* e;
    540   u32 index;
    541   if (!s) return NULL;
    542   e = CgApiTypes_push(&s->types, &index);
    543   if (!e) return NULL;
    544   *id_out = user_id_from_index(index);
    545   if (*id_out == KIT_CG_TYPE_NONE) return NULL;
    546   e->self_id = *id_out;
    547   return e;
    548 }
    549 
    550 static KitCgTypeId find_ptr_type_id(Compiler* c, KitCgTypeId pointee,
    551                                     u32 address_space) {
    552   CgApiState* s;
    553   const KitCgTypeId* hit;
    554   if (!c || !c->cg_api) return KIT_CG_TYPE_NONE;
    555   s = (CgApiState*)c->cg_api;
    556   hit = CgPtrMap_get(&s->ptr_index, cg_ptr_key(pointee, address_space));
    557   return hit ? *hit : KIT_CG_TYPE_NONE;
    558 }
    559 
    560 static KitCgTypeId find_array_type_id(Compiler* c, KitCgTypeId elem,
    561                                       u64 count) {
    562   CgApiState* s;
    563   CgApiType probe;
    564   CgApiType* hit;
    565   if (!c || !c->cg_api) return KIT_CG_TYPE_NONE;
    566   s = (CgApiState*)c->cg_api;
    567   memset(&probe, 0, sizeof probe);
    568   probe.cg.kind = KIT_CG_TYPE_ARRAY;
    569   probe.cg.array.elem = elem;
    570   probe.cg.array.count = count;
    571   hit = CgArraySet_find(&s->array_index, &probe);
    572   return hit ? hit->self_id : KIT_CG_TYPE_NONE;
    573 }
    574 
    575 static int cg_params_eq(const KitCgFuncParam* a, const KitCgFuncParam* b,
    576                         u32 n) {
    577   for (u32 i = 0; i < n; ++i)
    578     if (a[i].type != b[i].type ||
    579         memcmp(&a[i].attrs, &b[i].attrs, sizeof(a[i].attrs)) != 0) {
    580       return 0;
    581     }
    582   return 1;
    583 }
    584 
    585 static int cg_result_eq(const KitCgFuncResult* a, const KitCgFuncResult* b) {
    586   return a->type == b->type &&
    587          memcmp(&a->attrs, &b->attrs, sizeof(a->attrs)) == 0;
    588 }
    589 
    590 static u32 cg_array_hash(CgApiType* const e) {
    591   u32 h = hash_u32((u32)e->cg.array.elem);
    592   h ^= hash_u64(e->cg.array.count) + 0x9e3779b9u + (h << 6) + (h >> 2);
    593   return h;
    594 }
    595 
    596 static int cg_array_eq(CgApiType* const a, CgApiType* const b) {
    597   return a->cg.array.elem == b->cg.array.elem &&
    598          a->cg.array.count == b->cg.array.count;
    599 }
    600 
    601 /* Structural hash/eq over a function type's identity — the same fields the old
    602  * linear scan compared. Only function types enter this set, so neither callback
    603  * needs to re-check kind. The result/param attrs are compared (not hashed):
    604  * fewer hash inputs just means eq resolves the (rare) collision. */
    605 static u32 cg_func_hash(CgApiType* const e) {
    606   u32 h = 2166136261u;
    607   h = (h ^ (u32)e->cg.func.nparams) * 16777619u;
    608   h = (h ^ (u32)e->cg.func.abi_variadic) * 16777619u;
    609   h = (h ^ (u32)e->cg.func.call_conv) * 16777619u;
    610   h = (h ^ (u32)e->cg.func.result.type) * 16777619u;
    611   for (u32 i = 0; i < e->cg.func.nparams; ++i)
    612     h = (h ^ (u32)e->cg.func.params[i].type) * 16777619u;
    613   return h;
    614 }
    615 
    616 static int cg_func_eq(CgApiType* const a, CgApiType* const b) {
    617   if (a->cg.func.nparams != b->cg.func.nparams) return 0;
    618   if (a->cg.func.abi_variadic != b->cg.func.abi_variadic) return 0;
    619   if (a->cg.func.call_conv != b->cg.func.call_conv) return 0;
    620   if (!cg_result_eq(&a->cg.func.result, &b->cg.func.result)) return 0;
    621   if (a->cg.func.nparams &&
    622       !cg_params_eq(a->cg.func.params, b->cg.func.params, a->cg.func.nparams)) {
    623     return 0;
    624   }
    625   return 1;
    626 }
    627 
    628 static KitCgTypeId find_func_type_id(Compiler* c, KitCgFuncSig sig) {
    629   CgApiState* s;
    630   CgApiType probe;
    631   CgApiType* hit;
    632   if (!c || !c->cg_api) return KIT_CG_TYPE_NONE;
    633   s = (CgApiState*)c->cg_api;
    634   memset(&probe, 0, sizeof probe);
    635   probe.cg.kind = KIT_CG_TYPE_FUNC;
    636   probe.cg.func.nparams = sig.nparams;
    637   probe.cg.func.abi_variadic = sig.abi_variadic != 0;
    638   probe.cg.func.call_conv = sig.call_conv;
    639   probe.cg.func.result = sig.result;
    640   probe.cg.func.params = sig.params;
    641   hit = CgFuncSet_find(&s->func_index, &probe);
    642   return hit ? hit->self_id : KIT_CG_TYPE_NONE;
    643 }
    644 
    645 static CgApiType* api_type_from_id(Compiler* c, KitCgTypeId id) {
    646   u32 index;
    647   CgApiState* s;
    648   CgApiType* e;
    649   if (!c || id == KIT_CG_TYPE_NONE) return NULL;
    650   if (!decode_user_id(id, &index)) return NULL;
    651   s = (CgApiState*)c->cg_api;
    652   if (!s) return NULL;
    653   e = CgApiTypes_at(&s->types, index);
    654   return e;
    655 }
    656 
    657 KitCgTypeId resolve_type(Compiler* c, KitCgTypeId id) {
    658   if (!c || id == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    659   if (id <= KIT_CG_BUILTIN_COUNT) return id;
    660   return api_type_from_id(c, id) ? id : KIT_CG_TYPE_NONE;
    661 }
    662 
    663 /* Fill an entry's identity prefix (the kit/cg.h KitCgTypeInfo) once. Identity
    664  * is immutable after creation, so this runs at most once per entry
    665  * (info.id != 0 thereafter). */
    666 static void api_type_info_fill(Compiler* c, CgApiType* e, KitCgTypeId id) {
    667   (void)c;
    668   e->info.id = id;
    669   e->info.kind = e->cg.kind;
    670   if (e->cg.kind == KIT_CG_TYPE_RECORD || e->cg.kind == KIT_CG_TYPE_ENUM)
    671     e->info.flags = KIT_CG_TYPEF_NOMINAL;
    672   e->info.storage_id = id;
    673 }
    674 
    675 /* The CgApiType for a user id with its identity prefix filled, or NULL. */
    676 static CgApiType* api_type_entry_filled(Compiler* c, KitCgTypeId id) {
    677   CgApiType* e = api_type_from_id(c, id);
    678   if (!e) return NULL;
    679   if (e->info.id == 0) api_type_info_fill(c, e, id);
    680   return e;
    681 }
    682 
    683 static KitCgFuncParam* copy_cg_params(Compiler* c, const KitCgFuncParam* src,
    684                                       u32 n) {
    685   KitCgFuncParam* dst;
    686   if (!n) return NULL;
    687   if (!src) return NULL;
    688   dst = arena_array(&c->global->arena, KitCgFuncParam, n);
    689   if (!dst) return NULL;
    690   memcpy(dst, src, sizeof(*dst) * n);
    691   return dst;
    692 }
    693 
    694 static CgTypeField* copy_cg_fields(Compiler* c, const KitCgFieldDesc* src,
    695                                    u32 n) {
    696   CgTypeField* dst;
    697   if (!n) return NULL;
    698   if (!src) return NULL;
    699   dst = arena_array(&c->global->arena, CgTypeField, n);
    700   if (!dst) return NULL;
    701   memset(dst, 0, sizeof(*dst) * n);
    702   for (u32 i = 0; i < n; ++i) {
    703     dst[i].name = src[i].name;
    704     dst[i].type = src[i].type;
    705     dst[i].align_override = src[i].align_override;
    706     dst[i].max_align = src[i].max_align;
    707     dst[i].flags = src[i].flags;
    708     dst[i].bit_width = src[i].bit_width;
    709     dst[i].bit_signed = src[i].bit_signed != 0;
    710   }
    711   return dst;
    712 }
    713 
    714 static int cg_type_record_complete(const CgType* ty) {
    715   return ty && ty->kind == KIT_CG_TYPE_RECORD &&
    716          (ty->record.flags & CG_TYPE_RECORD_COMPLETE) != 0;
    717 }
    718 
    719 static int cg_type_complete_id(Compiler* c, KitCgTypeId id) {
    720   const CgType* ty = cg_type_get(c, id);
    721   if (!ty) return 0;
    722   switch (ty->kind) {
    723     case KIT_CG_TYPE_ARRAY:
    724       return cg_type_complete_id(c, ty->array.elem);
    725     case KIT_CG_TYPE_RECORD:
    726       return cg_type_record_complete(ty);
    727     default:
    728       return 1;
    729   }
    730 }
    731 
    732 static int cg_type_sized_id(Compiler* c, KitCgTypeId id) {
    733   ABITypeInfo ti;
    734   const CgType* ty;
    735   ty = cg_type_get(c, id);
    736   if (!ty) return 0;
    737   switch (ty->kind) {
    738     case KIT_CG_TYPE_VOID:
    739       return 0;
    740     case KIT_CG_TYPE_FUNC:
    741       return 0;
    742     case KIT_CG_TYPE_RECORD:
    743       if (!cg_type_record_complete(ty)) return 0;
    744       break;
    745     case KIT_CG_TYPE_ARRAY:
    746       if (!cg_type_sized_id(c, ty->array.elem)) return 0;
    747       break;
    748     default:
    749       break;
    750   }
    751   ti = abi_cg_type_info(c->abi, id);
    752   return ti.align != 0;
    753 }
    754 
    755 static int cg_type_valid_by_value(Compiler* c, KitCgTypeId id) {
    756   const CgType* ty = cg_type_get(c, id);
    757   if (!ty) return 0;
    758   if (ty->kind == KIT_CG_TYPE_VOID || ty->kind == KIT_CG_TYPE_FUNC) return 0;
    759   return cg_type_sized_id(c, id);
    760 }
    761 
    762 static int cg_type_contains_by_value(Compiler* c, KitCgTypeId id,
    763                                      KitCgTypeId needle) {
    764   const CgType* ty;
    765   if (!id) return 0;
    766   if (id == needle) return 1;
    767   ty = cg_type_get(c, id);
    768   if (!ty) return 0;
    769   switch (ty->kind) {
    770     case KIT_CG_TYPE_ARRAY:
    771       return cg_type_contains_by_value(c, ty->array.elem, needle);
    772     case KIT_CG_TYPE_RECORD:
    773       if (!cg_type_record_complete(ty)) return 0;
    774       for (u32 i = 0; i < ty->record.nfields; ++i) {
    775         if (cg_type_contains_by_value(c, ty->record.fields[i].type, needle))
    776           return 1;
    777       }
    778       return 0;
    779     default:
    780       return 0;
    781   }
    782 }
    783 
    784 static int cg_type_layout_record(Compiler* c, CgType* cg) {
    785   u32 max_align = 1;
    786   u64 size = 0;
    787   if (!c || !cg || cg->kind != KIT_CG_TYPE_RECORD) return 0;
    788   if (cg->record.nfields && !cg->record.fields) return 0;
    789   if (cg->record.is_union) {
    790     for (u32 i = 0; i < cg->record.nfields; ++i) {
    791       CgTypeField* f = &cg->record.fields[i];
    792       u64 fsize = cg_type_size(c, f->type);
    793       u32 falign = cg_type_align(c, f->type);
    794       if (!falign) return 0;
    795       if (f->max_align && falign > f->max_align) falign = f->max_align;
    796       if (f->align_override == 1u) {
    797         falign = 1;
    798       } else if (f->align_override > falign) {
    799         falign = f->align_override;
    800       }
    801       if (falign > max_align) max_align = falign;
    802       if ((f->flags & KIT_CG_FIELD_BITFIELD) != 0) {
    803         f->offset = 0;
    804         f->bit_offset = 0;
    805         f->bit_storage_size = (u32)fsize;
    806         if (f->bit_width == 0) continue;
    807       }
    808       if (fsize > size) size = fsize;
    809       f->offset = 0;
    810     }
    811   } else {
    812     u64 off = 0;
    813     int active_bitfield_unit = 0;
    814     u64 unit_off = 0;
    815     u32 unit_bits = 0;
    816     u32 unit_size = 0;
    817     u32 next_bit = 0;
    818     for (u32 i = 0; i < cg->record.nfields; ++i) {
    819       CgTypeField* f = &cg->record.fields[i];
    820       u64 fsize = cg_type_size(c, f->type);
    821       u32 falign = cg_type_align(c, f->type);
    822       if (!falign) return 0;
    823       if (f->max_align && falign > f->max_align) falign = f->max_align;
    824       if (f->align_override == 1u) {
    825         falign = 1;
    826       } else if (f->align_override > falign) {
    827         falign = f->align_override;
    828       }
    829       if (falign > max_align) max_align = falign;
    830       if ((f->flags & KIT_CG_FIELD_BITFIELD) != 0) {
    831         if (fsize > UINT32_MAX / 8u) return 0;
    832         if (f->bit_width == 0) {
    833           if (active_bitfield_unit) off = unit_off + unit_size;
    834           off = cg_align_to(off, falign);
    835           f->offset = off;
    836           f->bit_offset = 0;
    837           f->bit_storage_size = (u32)fsize;
    838           active_bitfield_unit = 0;
    839           next_bit = 0;
    840           continue;
    841         }
    842         if (f->bit_width > fsize * 8u) return 0;
    843         if (!active_bitfield_unit || unit_size != (u32)fsize ||
    844             next_bit + f->bit_width > unit_bits) {
    845           if (active_bitfield_unit) off = unit_off + unit_size;
    846           off = cg_align_to(off, falign);
    847           unit_off = off;
    848           unit_size = (u32)fsize;
    849           unit_bits = unit_size * 8u;
    850           next_bit = 0;
    851           active_bitfield_unit = 1;
    852         }
    853         f->offset = unit_off;
    854         f->bit_offset = (u16)next_bit;
    855         f->bit_storage_size = unit_size;
    856         next_bit += f->bit_width;
    857         off = unit_off + unit_size;
    858         continue;
    859       }
    860       active_bitfield_unit = 0;
    861       off = cg_align_to(off, falign);
    862       f->offset = off;
    863       off += fsize;
    864     }
    865     size = off;
    866   }
    867   if (cg->record.align_override > max_align) {
    868     max_align = cg->record.align_override;
    869   }
    870   cg->align = max_align;
    871   cg->size = cg_align_to(size, max_align);
    872   return 1;
    873 }
    874 
    875 static int cg_type_set_ptr(Compiler* c, CgApiType* e, KitCgTypeId pointee,
    876                            u32 address_space) {
    877   u32 ptr_size;
    878   u32 ptr_align;
    879   if (!cg_type_get(c, pointee)) return 0;
    880   memset(&e->cg, 0, sizeof(e->cg));
    881   ptr_size = c->target.ptr_size ? c->target.ptr_size : 8;
    882   ptr_align = c->target.ptr_align ? c->target.ptr_align : ptr_size;
    883   e->cg.kind = KIT_CG_TYPE_PTR;
    884   e->cg.size = ptr_size;
    885   e->cg.align = ptr_align;
    886   e->cg.ptr.pointee = pointee;
    887   e->cg.ptr.address_space = address_space;
    888   return 1;
    889 }
    890 
    891 static int cg_type_set_array(Compiler* c, CgApiType* e, KitCgTypeId elem,
    892                              u64 count) {
    893   ABITypeInfo ety;
    894   if (!cg_type_sized_id(c, elem)) return 0;
    895   ety = abi_cg_type_info(c->abi, elem);
    896   if (ety.size && count > UINT32_MAX / ety.size) return 0;
    897   memset(&e->cg, 0, sizeof(e->cg));
    898   e->cg.kind = KIT_CG_TYPE_ARRAY;
    899   e->cg.size = (u64)ety.size * count;
    900   e->cg.align = ety.align;
    901   e->cg.array.elem = elem;
    902   e->cg.array.count = count;
    903   return 1;
    904 }
    905 
    906 static int cg_type_set_record(Compiler* c, CgApiType* e, KitSym tag,
    907                               const KitCgFieldDesc* fields, u32 nfields,
    908                               int is_union, u32 align_override, u32 flags) {
    909   CgTypeField* copied = copy_cg_fields(c, fields, nfields);
    910   if (nfields && !copied) return 0;
    911   memset(&e->cg, 0, sizeof(e->cg));
    912   e->cg.kind = KIT_CG_TYPE_RECORD;
    913   e->cg.record.tag = tag;
    914   e->cg.record.fields = copied;
    915   e->cg.record.nfields = nfields;
    916   e->cg.record.is_union = is_union != 0;
    917   e->cg.record.align_override = align_override;
    918   e->cg.record.flags = flags;
    919   return cg_type_layout_record(c, &e->cg);
    920 }
    921 
    922 static int cg_type_set_enum(Compiler* c, CgApiType* e, KitSym tag,
    923                             KitCgTypeId base, KitCgEnumValue* values,
    924                             u32 nvalues) {
    925   const CgType* sty;
    926   ABITypeInfo ti;
    927   if (base == KIT_CG_TYPE_NONE) base = builtin_id(KIT_CG_BUILTIN_I32);
    928   sty = cg_type_get(c, base);
    929   if (!sty ||
    930       !(sty->kind == KIT_CG_TYPE_INT || sty->kind == KIT_CG_TYPE_BOOL)) {
    931     return 0;
    932   }
    933   ti = abi_cg_type_info(c->abi, base);
    934   memset(&e->cg, 0, sizeof(e->cg));
    935   e->cg.kind = KIT_CG_TYPE_ENUM;
    936   e->cg.size = ti.size;
    937   e->cg.align = ti.align;
    938   e->cg.enum_.tag = tag;
    939   e->cg.enum_.base = base;
    940   e->cg.enum_.values = values;
    941   e->cg.enum_.nvalues = nvalues;
    942   return 1;
    943 }
    944 
    945 static int cg_type_set_func(Compiler* c, CgApiType* e, KitCgFuncSig sig,
    946                             KitCgFuncParam* params) {
    947   KitCgTypeId void_ty = builtin_id(KIT_CG_BUILTIN_VOID);
    948   if (!sig.result.type || !cg_type_get(c, sig.result.type)) return 0;
    949   if (sig.result.type != void_ty && !cg_type_valid_by_value(c, sig.result.type))
    950     return 0;
    951   for (u32 i = 0; i < sig.nparams; ++i) {
    952     if (!cg_type_valid_by_value(c, sig.params[i].type)) return 0;
    953   }
    954   memset(&e->cg, 0, sizeof(e->cg));
    955   e->cg.kind = KIT_CG_TYPE_FUNC;
    956   e->cg.size = 1;
    957   e->cg.align = 1;
    958   e->cg.func.result = sig.result;
    959   e->cg.func.params = params;
    960   e->cg.func.nparams = sig.nparams;
    961   e->cg.func.call_conv = sig.call_conv;
    962   e->cg.func.abi_variadic = sig.abi_variadic != 0;
    963   return 1;
    964 }
    965 
    966 KitCgTypeId kit_cg_type_builtin(KitCompiler* c, KitCgBuiltinType which) {
    967   (void)c;
    968   if ((u32)which >= KIT_CG_BUILTIN_COUNT) return KIT_CG_TYPE_NONE;
    969   return builtin_id(which);
    970 }
    971 
    972 KitCgTypeId kit_cg_type_ptr(KitCompiler* c, KitCgTypeId pointee,
    973                             uint32_t address_space) {
    974   KitCgTypeId id;
    975   CgApiType* e;
    976   if (!cg_type_get(c, pointee)) return KIT_CG_TYPE_NONE;
    977   id = find_ptr_type_id(c, pointee, address_space);
    978   if (id != KIT_CG_TYPE_NONE) return id;
    979   e = type_alloc(c, &id);
    980   if (!e) return KIT_CG_TYPE_NONE;
    981   if (!cg_type_set_ptr(c, e, pointee, address_space)) {
    982     return KIT_CG_TYPE_NONE;
    983   }
    984   CgPtrMap_set(&((CgApiState*)c->cg_api)->ptr_index,
    985                cg_ptr_key(pointee, address_space), id);
    986   return id;
    987 }
    988 
    989 KitCgTypeId kit_cg_type_array(KitCompiler* c, KitCgTypeId elem,
    990                               uint64_t count) {
    991   KitCgTypeId id;
    992   CgApiType* e;
    993   if (!cg_type_sized_id(c, elem)) return KIT_CG_TYPE_NONE;
    994   id = find_array_type_id(c, elem, count);
    995   if (id != KIT_CG_TYPE_NONE) return id;
    996   e = type_alloc(c, &id);
    997   if (!e) return KIT_CG_TYPE_NONE;
    998   if (!cg_type_set_array(c, e, elem, count)) {
    999     return KIT_CG_TYPE_NONE;
   1000   }
   1001   CgArraySet_add(&((CgApiState*)c->cg_api)->array_index, e);
   1002   return id;
   1003 }
   1004 
   1005 KitCgTypeId kit_cg_type_record_decl(KitCompiler* c, KitSym tag, int is_union) {
   1006   KitCgTypeId id;
   1007   CgApiType* e;
   1008   if (!c) return KIT_CG_TYPE_NONE;
   1009   e = type_alloc(c, &id);
   1010   if (!e) return KIT_CG_TYPE_NONE;
   1011   memset(&e->cg, 0, sizeof(e->cg));
   1012   e->cg.kind = KIT_CG_TYPE_RECORD;
   1013   e->cg.record.tag = tag;
   1014   e->cg.record.is_union = is_union != 0;
   1015   return id;
   1016 }
   1017 
   1018 KitStatus kit_cg_type_record_complete(KitCompiler* c, KitCgTypeId record,
   1019                                       const KitCgRecordDesc* desc) {
   1020   CgApiType* e;
   1021   KitSym tag;
   1022   if (!c || !desc || (desc->nfields && !desc->fields) ||
   1023       desc->nfields > UINT16_MAX) {
   1024     return KIT_INVALID;
   1025   }
   1026   e = api_type_from_id(c, record);
   1027   if (!e || e->cg.kind != KIT_CG_TYPE_RECORD) return KIT_INVALID;
   1028   if (e->cg.record.flags & CG_TYPE_RECORD_COMPLETE) return KIT_INVALID;
   1029   if (e->cg.record.is_union != (desc->is_union != 0)) return KIT_INVALID;
   1030 
   1031   for (u32 i = 0; i < desc->nfields; ++i) {
   1032     KitCgTypeId fty = desc->fields[i].type;
   1033     if (!cg_type_valid_by_value(c, fty)) return KIT_INVALID;
   1034     if (cg_type_contains_by_value(c, fty, record)) return KIT_INVALID;
   1035   }
   1036 
   1037   tag = desc->tag ? desc->tag : e->cg.record.tag;
   1038   if (!cg_type_set_record(c, e, tag, desc->fields, desc->nfields,
   1039                           desc->is_union, desc->align_override,
   1040                           CG_TYPE_RECORD_COMPLETE)) {
   1041     return KIT_INVALID;
   1042   }
   1043   return KIT_OK;
   1044 }
   1045 
   1046 KitCgTypeId kit_cg_type_enum(KitCompiler* c, KitSym tag, KitCgTypeId base,
   1047                              const KitCgEnumValue* values, uint32_t nvalues) {
   1048   KitCgEnumValue* copied = NULL;
   1049   KitCgTypeId id;
   1050   CgApiType* e;
   1051   if (!c || (nvalues && !values)) return KIT_CG_TYPE_NONE;
   1052   if (base == KIT_CG_TYPE_NONE) base = builtin_id(KIT_CG_BUILTIN_I32);
   1053   if (!cg_type_is_int(c, base)) return KIT_CG_TYPE_NONE;
   1054   if (nvalues) {
   1055     copied = arena_array(&c->global->arena, KitCgEnumValue, nvalues);
   1056     if (!copied) return KIT_CG_TYPE_NONE;
   1057     memcpy(copied, values, sizeof(*copied) * nvalues);
   1058   }
   1059   e = type_alloc(c, &id);
   1060   if (!e) return KIT_CG_TYPE_NONE;
   1061   if (!cg_type_set_enum(c, e, tag, base, copied, nvalues)) {
   1062     return KIT_CG_TYPE_NONE;
   1063   }
   1064   return id;
   1065 }
   1066 
   1067 KitCgTypeId kit_cg_type_func(KitCompiler* c, KitCgFuncSig sig) {
   1068   KitCgFuncParam* copied = NULL;
   1069   KitCgTypeId id;
   1070   CgApiType* e;
   1071   if (!c || (sig.nparams && !sig.params) || sig.nparams > UINT16_MAX) {
   1072     return KIT_CG_TYPE_NONE;
   1073   }
   1074   if (!sig.result.type || !cg_type_get(c, sig.result.type))
   1075     return KIT_CG_TYPE_NONE;
   1076   if (sig.result.type != builtin_id(KIT_CG_BUILTIN_VOID) &&
   1077       !cg_type_valid_by_value(c, sig.result.type))
   1078     return KIT_CG_TYPE_NONE;
   1079   for (u32 i = 0; i < sig.nparams; ++i) {
   1080     if (!cg_type_valid_by_value(c, sig.params[i].type)) return KIT_CG_TYPE_NONE;
   1081   }
   1082   id = find_func_type_id(c, sig);
   1083   if (id != KIT_CG_TYPE_NONE) return id;
   1084   if (sig.nparams) {
   1085     copied = copy_cg_params(c, sig.params, sig.nparams);
   1086     if (!copied) return KIT_CG_TYPE_NONE;
   1087   }
   1088   e = type_alloc(c, &id);
   1089   if (!e) return KIT_CG_TYPE_NONE;
   1090   if (!cg_type_set_func(c, e, sig, copied)) {
   1091     return KIT_CG_TYPE_NONE;
   1092   }
   1093   CgFuncSet_add(&((CgApiState*)c->cg_api)->func_index, e);
   1094   return id;
   1095 }
   1096 
   1097 uint64_t kit_cg_type_size(KitCompiler* c, KitCgTypeId id) {
   1098   return cg_type_size(c, id);
   1099 }
   1100 
   1101 uint32_t kit_cg_type_align(KitCompiler* c, KitCgTypeId id) {
   1102   return cg_type_align(c, id);
   1103 }
   1104 
   1105 /* Identity view backing the inline kit_cg_type_{kind,resolve_alias,is_void} and
   1106  * kit_cg_func_result_has_value queries in kit/cg.h. Builtins read the
   1107  * precomputed table; user entries fill their identity prefix once (immutable
   1108  * thereafter: kind and storage identity are stable, NOMINAL is fixed at
   1109  * creation), then hand back the entry's first member. Layout and the
   1110  * COMPLETE/SIZED flags are deliberately left to kit_cg_type_info. */
   1111 const KitCgTypeInfo* kit_cg_type_view(KitCompiler* kc, KitCgTypeId id) {
   1112   Compiler* c = (Compiler*)kc;
   1113   CgApiState* s;
   1114   CgApiType* e;
   1115   if (!c || id == KIT_CG_TYPE_NONE) return NULL;
   1116   s = c->cg_api ? (CgApiState*)c->cg_api : cg_api_get(c);
   1117   if (!s) return NULL;
   1118   if (id <= KIT_CG_BUILTIN_COUNT) return &s->builtin_info[id - 1u];
   1119   e = api_type_entry_filled(c, id);
   1120   return e ? &e->info : NULL;
   1121 }
   1122 
   1123 int kit_cg_type_is_complete(KitCompiler* c, KitCgTypeId id) {
   1124   return cg_type_complete_id(c, id);
   1125 }
   1126 
   1127 int kit_cg_type_is_sized(KitCompiler* c, KitCgTypeId id) {
   1128   return cg_type_sized_id(c, id);
   1129 }
   1130 
   1131 static KitCgStorageKind cg_storage_kind_from_abi(const CgType* ty,
   1132                                                  ABITypeInfo ti) {
   1133   switch ((ABIScalarKind)ti.scalar_kind) {
   1134     case ABI_SC_VOID:
   1135       if (ty &&
   1136           (ty->kind == KIT_CG_TYPE_ARRAY || ty->kind == KIT_CG_TYPE_RECORD))
   1137         return KIT_CG_STORAGE_AGGREGATE;
   1138       return KIT_CG_STORAGE_VOID;
   1139     case ABI_SC_BOOL:
   1140       return KIT_CG_STORAGE_BOOL;
   1141     case ABI_SC_INT:
   1142       return KIT_CG_STORAGE_INT;
   1143     case ABI_SC_FLOAT:
   1144       return KIT_CG_STORAGE_FLOAT;
   1145     case ABI_SC_PTR:
   1146       return KIT_CG_STORAGE_PTR;
   1147   }
   1148   return KIT_CG_STORAGE_VOID;
   1149 }
   1150 
   1151 static uint16_t cg_type_scalar_width(Compiler* c, const CgType* ty) {
   1152   if (!ty) return 0;
   1153   switch (ty->kind) {
   1154     case KIT_CG_TYPE_BOOL:
   1155     case KIT_CG_TYPE_INT:
   1156       return (uint16_t)ty->integer.width;
   1157     case KIT_CG_TYPE_FLOAT:
   1158       return (uint16_t)ty->fp.width;
   1159     case KIT_CG_TYPE_ENUM:
   1160       return (uint16_t)kit_cg_type_int_width((KitCompiler*)c, ty->enum_.base);
   1161     default:
   1162       return 0;
   1163   }
   1164 }
   1165 
   1166 KitStatus kit_cg_type_info(KitCompiler* kc, KitCgTypeId id,
   1167                            KitCgTypeInfo* out) {
   1168   Compiler* c = (Compiler*)kc;
   1169   const KitCgTypeInfo* v;
   1170   const CgType* storage;
   1171   ABITypeInfo ti;
   1172   if (!out) return KIT_INVALID;
   1173   v = kit_cg_type_view(kc, id);
   1174   if (!v) {
   1175     memset(out, 0, sizeof(*out));
   1176     return KIT_INVALID;
   1177   }
   1178   storage = cg_type_get(c, v->storage_id);
   1179   if (!storage) {
   1180     memset(out, 0, sizeof(*out));
   1181     return KIT_INVALID;
   1182   }
   1183 
   1184   /* Identity (id/storage_id/kind and the BUILTIN/NOMINAL flags) comes straight
   1185    * from the view's interned prefix; only the completion/sizing flags and the
   1186    * ABI layout are computed per call (they are not maintained on the view). */
   1187   *out = *v;
   1188   if (cg_type_complete_id(c, id)) out->flags |= KIT_CG_TYPEF_COMPLETE;
   1189   if (cg_type_sized_id(c, id)) out->flags |= KIT_CG_TYPEF_SIZED;
   1190 
   1191   ti = abi_cg_type_info(c->abi, v->storage_id);
   1192   if (ti.align || storage->kind == KIT_CG_TYPE_VOID) {
   1193     out->layout.size = ti.size;
   1194     out->layout.align = ti.align;
   1195     out->layout.scalar_width = cg_type_scalar_width(c, storage);
   1196     out->layout.storage_kind = (uint8_t)cg_storage_kind_from_abi(storage, ti);
   1197     out->layout.valid = 1;
   1198   }
   1199   return KIT_OK;
   1200 }
   1201 
   1202 static int cg_type_same_storage_rec(Compiler* c, KitCgTypeId a, KitCgTypeId b) {
   1203   const CgType* ta;
   1204   const CgType* tb;
   1205   if (!a || !b) return 0;
   1206   if (a == b) return 1;
   1207   ta = cg_type_get(c, a);
   1208   tb = cg_type_get(c, b);
   1209   if (!ta || !tb) return 0;
   1210   if (ta->kind == KIT_CG_TYPE_ENUM)
   1211     return cg_type_same_storage_rec(c, ta->enum_.base, b);
   1212   if (tb->kind == KIT_CG_TYPE_ENUM)
   1213     return cg_type_same_storage_rec(c, a, tb->enum_.base);
   1214   if (ta->kind != tb->kind) return 0;
   1215   switch (ta->kind) {
   1216     case KIT_CG_TYPE_VOID:
   1217     case KIT_CG_TYPE_BOOL:
   1218     case KIT_CG_TYPE_INT:
   1219     case KIT_CG_TYPE_FLOAT: {
   1220       ABITypeInfo ai = abi_cg_type_info(c->abi, a);
   1221       ABITypeInfo bi = abi_cg_type_info(c->abi, b);
   1222       return ai.scalar_kind == bi.scalar_kind && ai.size == bi.size &&
   1223              ai.align == bi.align;
   1224     }
   1225     case KIT_CG_TYPE_PTR:
   1226       return ta->ptr.address_space == tb->ptr.address_space &&
   1227              cg_type_same_storage_rec(c, ta->ptr.pointee, tb->ptr.pointee);
   1228     case KIT_CG_TYPE_ARRAY:
   1229       return ta->array.count == tb->array.count &&
   1230              cg_type_same_storage_rec(c, ta->array.elem, tb->array.elem);
   1231     case KIT_CG_TYPE_FUNC:
   1232       if (ta->func.nparams != tb->func.nparams ||
   1233           ta->func.call_conv != tb->func.call_conv ||
   1234           ta->func.abi_variadic != tb->func.abi_variadic ||
   1235           memcmp(&ta->func.result.attrs, &tb->func.result.attrs,
   1236                  sizeof(ta->func.result.attrs)) != 0)
   1237         return 0;
   1238       if (!cg_type_same_storage_rec(c, ta->func.result.type,
   1239                                     tb->func.result.type))
   1240         return 0;
   1241       for (u32 i = 0; i < ta->func.nparams; ++i) {
   1242         if (memcmp(&ta->func.params[i].attrs, &tb->func.params[i].attrs,
   1243                    sizeof(ta->func.params[i].attrs)) != 0)
   1244           return 0;
   1245         if (!cg_type_same_storage_rec(c, ta->func.params[i].type,
   1246                                       tb->func.params[i].type))
   1247           return 0;
   1248       }
   1249       return 1;
   1250     case KIT_CG_TYPE_RECORD:
   1251       return 0;
   1252     case KIT_CG_TYPE_ENUM:
   1253       return 0;
   1254     case KIT_CG_TYPE_VARARG_STATE: {
   1255       ABITypeInfo ai = abi_cg_type_info(c->abi, a);
   1256       ABITypeInfo bi = abi_cg_type_info(c->abi, b);
   1257       return ai.size == bi.size && ai.align == bi.align;
   1258     }
   1259   }
   1260   return 0;
   1261 }
   1262 
   1263 int kit_cg_type_same_storage(KitCompiler* c, KitCgTypeId a, KitCgTypeId b) {
   1264   return cg_type_same_storage_rec((Compiler*)c, a, b);
   1265 }
   1266 
   1267 uint32_t kit_cg_type_int_width(KitCompiler* c, KitCgTypeId id) {
   1268   const CgType* ty = cg_type_get(c, id);
   1269   if (!ty) return 0;
   1270   if (ty->kind == KIT_CG_TYPE_INT || ty->kind == KIT_CG_TYPE_BOOL) {
   1271     return ty->integer.width;
   1272   }
   1273   if (ty->kind == KIT_CG_TYPE_ENUM) {
   1274     return kit_cg_type_int_width(c, ty->enum_.base);
   1275   }
   1276   return 0;
   1277 }
   1278 
   1279 uint32_t kit_cg_type_float_width(KitCompiler* c, KitCgTypeId id) {
   1280   const CgType* ty = cg_type_get(c, id);
   1281   if (!ty) return 0;
   1282   if (ty->kind == KIT_CG_TYPE_FLOAT) return ty->fp.width;
   1283   return 0;
   1284 }
   1285 
   1286 KitCgTypeId kit_cg_type_ptr_pointee(KitCompiler* c, KitCgTypeId id) {
   1287   const CgType* ty = cg_type_get(c, id);
   1288   return (ty && ty->kind == KIT_CG_TYPE_PTR) ? ty->ptr.pointee
   1289                                              : KIT_CG_TYPE_NONE;
   1290 }
   1291 
   1292 KitCgTypeId kit_cg_type_array_elem(KitCompiler* c, KitCgTypeId id) {
   1293   const CgType* ty = cg_type_get(c, id);
   1294   return (ty && ty->kind == KIT_CG_TYPE_ARRAY) ? ty->array.elem
   1295                                                : KIT_CG_TYPE_NONE;
   1296 }
   1297 
   1298 uint32_t kit_cg_type_ptr_address_space(KitCompiler* c, KitCgTypeId id) {
   1299   const CgType* ty = cg_type_get(c, id);
   1300   return (ty && ty->kind == KIT_CG_TYPE_PTR) ? ty->ptr.address_space : 0u;
   1301 }
   1302 
   1303 uint64_t kit_cg_type_array_count(KitCompiler* c, KitCgTypeId id) {
   1304   const CgType* ty = cg_type_get(c, id);
   1305   return (ty && ty->kind == KIT_CG_TYPE_ARRAY) ? ty->array.count : 0u;
   1306 }
   1307 
   1308 KitCgFuncResult kit_cg_type_func_result(KitCompiler* c, KitCgTypeId id) {
   1309   const CgType* ty = cg_type_get(c, id);
   1310   KitCgFuncResult empty;
   1311   memset(&empty, 0, sizeof(empty));
   1312   if (!ty || ty->kind != KIT_CG_TYPE_FUNC) return empty;
   1313   return ty->func.result;
   1314 }
   1315 
   1316 uint32_t kit_cg_type_func_nparams(KitCompiler* c, KitCgTypeId id) {
   1317   const CgType* ty = cg_type_get(c, id);
   1318   return (ty && ty->kind == KIT_CG_TYPE_FUNC) ? ty->func.nparams : 0;
   1319 }
   1320 
   1321 KitCgFuncParam kit_cg_type_func_param(KitCompiler* c, KitCgTypeId id,
   1322                                       uint32_t index) {
   1323   const CgType* ty = cg_type_get(c, id);
   1324   KitCgFuncParam empty;
   1325   memset(&empty, 0, sizeof(empty));
   1326   if (!ty || ty->kind != KIT_CG_TYPE_FUNC || index >= ty->func.nparams) {
   1327     return empty;
   1328   }
   1329   return ty->func.params[index];
   1330 }
   1331 
   1332 KitCgCallConv kit_cg_type_func_call_conv(KitCompiler* c, KitCgTypeId id) {
   1333   const CgType* ty = cg_type_get(c, id);
   1334   return (ty && ty->kind == KIT_CG_TYPE_FUNC) ? ty->func.call_conv
   1335                                               : KIT_CG_CC_TARGET_C;
   1336 }
   1337 
   1338 int kit_cg_type_func_is_variadic(KitCompiler* c, KitCgTypeId id) {
   1339   const CgType* ty = cg_type_get(c, id);
   1340   return ty && ty->kind == KIT_CG_TYPE_FUNC && ty->func.abi_variadic;
   1341 }
   1342 
   1343 KitSym kit_cg_type_record_tag(KitCompiler* c, KitCgTypeId id) {
   1344   const CgType* ty = cg_type_get(c, id);
   1345   return (ty && ty->kind == KIT_CG_TYPE_RECORD) ? ty->record.tag : 0;
   1346 }
   1347 
   1348 int kit_cg_type_record_is_union(KitCompiler* c, KitCgTypeId id) {
   1349   const CgType* ty = cg_type_get(c, id);
   1350   return ty && ty->kind == KIT_CG_TYPE_RECORD && ty->record.is_union;
   1351 }
   1352 
   1353 uint32_t kit_cg_type_record_nfields(KitCompiler* c, KitCgTypeId id) {
   1354   const CgType* ty = cg_type_get(c, id);
   1355   return (ty && ty->kind == KIT_CG_TYPE_RECORD && cg_type_record_complete(ty))
   1356              ? ty->record.nfields
   1357              : 0;
   1358 }
   1359 
   1360 const KitCgRecordLayout* kit_cg_type_record_layout(KitCompiler* c,
   1361                                                    KitCgTypeId id) {
   1362   CgApiType* e;
   1363   CgType* ty;
   1364   KitCgRecordLayout* view;
   1365   KitCgFieldLayout* fields;
   1366   u32 n;
   1367   e = api_type_from_id(c, id);
   1368   if (!e || e->cg.kind != KIT_CG_TYPE_RECORD) return NULL;
   1369   ty = &e->cg;
   1370   if (!cg_type_record_complete(ty)) return NULL;
   1371   /* Force/confirm sizing through the same path size/align queries use; an
   1372    * unsized record (e.g. a field that never sized) has no borrowable layout. */
   1373   if (!cg_type_sized_id(c, id)) return NULL;
   1374   if (ty->record.layout_view) return ty->record.layout_view;
   1375 
   1376   n = ty->record.nfields;
   1377   view = arena_new(&c->global->arena, KitCgRecordLayout);
   1378   if (!view) return NULL;
   1379   fields = n ? arena_array(&c->global->arena, KitCgFieldLayout, n) : NULL;
   1380   if (n && !fields) return NULL;
   1381   for (u32 i = 0; i < n; ++i) {
   1382     const CgTypeField* f = &ty->record.fields[i];
   1383     fields[i].name = f->name;
   1384     fields[i].type = f->type;
   1385     fields[i].offset = f->offset;
   1386     fields[i].flags = f->flags;
   1387     fields[i].bit_storage_size = f->bit_storage_size;
   1388     fields[i].bit_offset = f->bit_offset;
   1389     fields[i].bit_width = f->bit_width;
   1390     fields[i].bit_signed = f->bit_signed;
   1391   }
   1392   view->size = ty->size;
   1393   view->align = ty->align;
   1394   view->nfields = n;
   1395   view->fields = fields;
   1396   ty->record.layout_view = view;
   1397   return view;
   1398 }
   1399 
   1400 KitSym kit_cg_type_enum_tag(KitCompiler* c, KitCgTypeId id) {
   1401   const CgType* ty = cg_type_get(c, id);
   1402   return (ty && ty->kind == KIT_CG_TYPE_ENUM) ? ty->enum_.tag : 0;
   1403 }
   1404 
   1405 KitCgTypeId kit_cg_type_enum_base(KitCompiler* c, KitCgTypeId id) {
   1406   const CgType* ty = cg_type_get(c, id);
   1407   return (ty && ty->kind == KIT_CG_TYPE_ENUM) ? ty->enum_.base
   1408                                               : KIT_CG_TYPE_NONE;
   1409 }
   1410 
   1411 uint32_t kit_cg_type_enum_nvalues(KitCompiler* c, KitCgTypeId id) {
   1412   const CgType* ty = cg_type_get(c, id);
   1413   return (ty && ty->kind == KIT_CG_TYPE_ENUM) ? ty->enum_.nvalues : 0;
   1414 }
   1415 
   1416 KitStatus kit_cg_type_enum_value(KitCompiler* c, KitCgTypeId id, uint32_t index,
   1417                                  KitCgEnumValue* out) {
   1418   const CgType* ty = cg_type_get(c, id);
   1419   if (!ty || ty->kind != KIT_CG_TYPE_ENUM || index >= ty->enum_.nvalues)
   1420     return KIT_NOT_FOUND;
   1421   if (out) *out = ty->enum_.values[index];
   1422   return KIT_OK;
   1423 }
   1424 
   1425 int kit_cg_target_supports_call_conv(KitCompiler* c, KitCgCallConv cc) {
   1426   const ArchImpl* a;
   1427   if (!c) return 0;
   1428   /* TARGET_C is always available, including for arches with no codegen backend
   1429    * (x86_32/arm_32, where arch_for_compiler is NULL). */
   1430   if (cc == KIT_CG_CC_TARGET_C) return 1;
   1431   a = arch_for_compiler(c);
   1432   if (!a || !a->supports_call_conv) return 0;
   1433   return a->supports_call_conv(c, cc);
   1434 }
   1435 
   1436 int kit_cg_target_supports_symbol_feature(KitCompiler* c,
   1437                                           KitCgSymbolFeature feat) {
   1438   if (!c) return 0;
   1439   switch (feat) {
   1440     case KIT_CG_SYMFEAT_WEAK:
   1441     case KIT_CG_SYMFEAT_PROTECTED_VISIBILITY:
   1442     case KIT_CG_SYMFEAT_COMDAT:
   1443     case KIT_CG_SYMFEAT_COMMON:
   1444       return 1;
   1445     case KIT_CG_SYMFEAT_TLS_LOCAL_EXEC:
   1446       /* Local-exec is the only TLS model kit emits.  Whether it is actually
   1447        * available still depends on the object format being able to represent a
   1448        * TLS access at all (ELF/Mach-O yes; COFF/Wasm no). */
   1449       return obj_format_supports_symbol_feature(c, (int)feat);
   1450     case KIT_CG_SYMFEAT_TLS_INITIAL_EXEC:
   1451     case KIT_CG_SYMFEAT_TLS_LOCAL_DYNAMIC:
   1452     case KIT_CG_SYMFEAT_TLS_GENERAL_DYNAMIC:
   1453       /* kit has no initial-exec / local-dynamic / general-dynamic codegen and
   1454        * no dynamic-TLS runtime (__tls_get_addr), so it never emits these even
   1455        * where the object format could represent them.  Report the truth so a
   1456        * caller can't request a dynamic model and silently get local-exec; the
   1457        * linker enforces the same contract (see link_require_local_tls). */
   1458       return 0;
   1459     case KIT_CG_SYMFEAT_DLLIMPORT:
   1460     case KIT_CG_SYMFEAT_DLLEXPORT:
   1461     case KIT_CG_SYMFEAT_MERGE_SECTIONS:
   1462     case KIT_CG_SYMFEAT_CONSTRUCTOR_PRIORITY:
   1463       return 0;
   1464   }
   1465   return 0;
   1466 }
   1467 
   1468 KitCgVaListKind kit_cg_target_va_list_kind(const KitCompiler* c) {
   1469   ABIVaListInfo va;
   1470   if (!c) return KIT_CG_VALIST_OPAQUE;
   1471   va = abi_va_list_layout(c->abi);
   1472   switch ((ABIVaListKind)va.kind) {
   1473     case ABI_VA_LIST_OPAQUE:
   1474       return KIT_CG_VALIST_OPAQUE;
   1475     case ABI_VA_LIST_POINTER:
   1476       return KIT_CG_VALIST_POINTER;
   1477     case ABI_VA_LIST_AAPCS64:
   1478       return KIT_CG_VALIST_AAPCS64;
   1479     case ABI_VA_LIST_SYSV_X64:
   1480       return KIT_CG_VALIST_SYSV_X64;
   1481   }
   1482   return KIT_CG_VALIST_OPAQUE;
   1483 }
   1484 
   1485 const char* kit_cg_target_c_label_prefix(const KitCompiler* c) {
   1486   return obj_format_c_label_prefix(c);
   1487 }
   1488 
   1489 int kit_cg_target_supports_intrinsic(KitCompiler* c, KitCgIntrinsic intrin) {
   1490   const ArchImpl* a;
   1491   if (!c) return 0;
   1492   a = arch_for_compiler(c);
   1493   if (!a || !a->supports_intrinsic) return 0;
   1494   return a->supports_intrinsic(c, intrin);
   1495 }
   1496 
   1497 uint64_t kit_cg_target_backend_features(KitCompiler* c) {
   1498   const ArchImpl* a;
   1499   if (!c) return 0;
   1500   a = arch_for_compiler(c);
   1501   /* Arches with no registered codegen backend (x86_32) fall back to the
   1502    * conservative strict-alignment baseline. */
   1503   if (!a) return KIT_CG_BACKEND_STRICT_ALIGNMENT;
   1504   return a->backend_features;
   1505 }
   1506 
   1507 void cg_api_fini(Compiler* c) {
   1508   CgApiState* s;
   1509   if (!c || !c->cg_api) return;
   1510   s = (CgApiState*)c->cg_api;
   1511   CgApiTypes_fini(&s->types);
   1512   CgPtrMap_fini(&s->ptr_index);
   1513   CgArraySet_fini(&s->array_index);
   1514   CgFuncSet_fini(&s->func_index);
   1515   s->heap->free(s->heap, s, sizeof(*s));
   1516   c->cg_api = NULL;
   1517   c->cg_api_free = NULL;
   1518   c->cg_builtin_layout = NULL;
   1519 }
   1520 
   1521 /* ============================================================
   1522  * KitCg: public codegen API implementation
   1523  *
   1524  * Drives CgTarget directly with its own value stack.
   1525  * ============================================================ */