kit

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

commit 62c8e5a6f8b5e637fa1cd050b0bcacff7dccd7a1
parent 20c503f2205fc65f0715651760fb19035c429301
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 15 Jun 2026 14:17:46 -0700

cg: record-layout view + type/debug split

Two CG type-system changes developed concurrently in the same files, landed
together.

Record-layout view (replaces the split-cache field-access path):
- Split KitCgField into KitCgFieldDesc (completion INPUT: source shape +
  alignment policy, never offsets) and KitCgFieldLayout (computed OUTPUT).
- Add kit_cg_type_record_layout(): a borrowable, CG-owned, compiler-lifetime
  -stable layout view (size/align + per-field offset and bit geometry), cached
  lazily on the type entry. Replaces the per-field kit_cg_type_record_field
  query, so the offsets a frontend needs come from one borrowed view instead of
  N round-trips or a parallel mirror table.
- C frontend's c_abi_record_layout now sources offsets from a single view
  fetch; toy / wasm / api tests migrated. Access ops (kit_cg_field,
  field_at, field_bits, elem, elem_scaled) unchanged.

Type/debug split:
- Separate the operational KitCgTypeId from source-facing/debug types: drop
  KIT_CG_TYPE_ALIAS and KIT_CG_TYPE_SOURCE_BASE and their constructors; add a
  dedicated KitCgDebugType API (kit_cg_debug_base/typedef/ptr/array/func,
  KIT_CG_DEBUG_TYPE_NONE). storage_id now always equals id.

Validated: test-cg-api (incl. cg_type_test, 274), abi_classify_test (384),
test-toy, test-parse all green; full libkit + driver build clean under -Werror.

Diffstat:
Minclude/kit/cg.h | 156+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mlang/c/abi/c_abi.c | 32++++++++++++++++++--------------
Mlang/c/decl/decl.c | 9++++++---
Mlang/c/parse/cg_adapter.c | 3+++
Mlang/c/parse/parse_expr.c | 1+
Mlang/c/type/type.c | 142++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mlang/c/type/type.h | 13++++++++-----
Mlang/toy/asm.c | 37+++++++++++++++++++++----------------
Mlang/toy/attrs.c | 2+-
Mlang/toy/builtins.c | 59+++++++++++++++++++++++++++++++----------------------------
Mlang/toy/data.c | 27+++++++++++----------------
Mlang/toy/decls.c | 4++--
Mlang/toy/expr.c | 89+++++++++++++++++++++++++++++++++++++------------------------------------------
Mlang/toy/internal.h | 8++++----
Mlang/toy/parser.c | 105++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mlang/toy/parser_core.c | 4++--
Mlang/toy/types.c | 43++++++++++++++++++-------------------------
Mlang/wasm/cg.c | 35+++++++++++++++++++----------------
Msrc/abi/abi.c | 4----
Msrc/abi/abi_aapcs64.c | 6------
Msrc/abi/abi_rv64.c | 11-----------
Msrc/abi/abi_sysv_x64.c | 12------------
Msrc/abi/abi_win64_x64.c | 6------
Msrc/arch/c_target/c_emit.c | 72+++++++++++++++++++++++++++++++-----------------------------------------
Msrc/arch/wasm/abi.c | 6------
Msrc/cg/arith.c | 31++++++++++++++-----------------
Msrc/cg/call.c | 11++++-------
Msrc/cg/debug.c | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/cg/fold.c | 7-------
Msrc/cg/internal.h | 3++-
Msrc/cg/memory.c | 13+++++--------
Msrc/cg/session.c | 7+++++--
Msrc/cg/type.c | 270+++++++++++++++++++------------------------------------------------------------
Msrc/cg/type.h | 25+++++++++----------------
Msrc/cg/value.c | 15++++++---------
Mtest/api/abi_classify_test.c | 6+++---
Mtest/api/cg_type_test.c | 134+++++++++++++++++++++++--------------------------------------------------------
37 files changed, 719 insertions(+), 805 deletions(-)

diff --git a/include/kit/cg.h b/include/kit/cg.h @@ -15,6 +15,7 @@ typedef uint32_t KitCgLocal; typedef uint32_t KitCgScope; typedef uint32_t KitCgSym; typedef uint32_t KitCgTypeId; +typedef uint32_t KitCgDebugType; #define KIT_CG_LABEL_NONE 0u #define KIT_CG_LOCAL_NONE 0u @@ -23,6 +24,9 @@ typedef uint32_t KitCgTypeId; /* Invalid or absent type sentinel. Void is represented by the real void * builtin type id, never by KIT_CG_TYPE_NONE. */ #define KIT_CG_TYPE_NONE 0u +/* Optional debug type sentinel. Declaration sites that pass NONE derive a + * default debug type from the operational KitCgTypeId. */ +#define KIT_CG_DEBUG_TYPE_NONE 0u /* ============================================================ * Types, ABI, and Target Capabilities @@ -53,17 +57,12 @@ typedef enum KitCgTypeKind { KIT_CG_TYPE_FUNC, KIT_CG_TYPE_RECORD, KIT_CG_TYPE_ENUM, - KIT_CG_TYPE_ALIAS, KIT_CG_TYPE_VARARG_STATE, - /* A source-facing primitive spelling (sign + name) over a width-only storage - * builtin. Storage/ABI/codegen see the builtin (the id unaliases to it); the - * exact kind, debug info, and the C-source backend see the name + encoding. */ - KIT_CG_TYPE_SOURCE_BASE, } KitCgTypeKind; -/* Debug base-type encoding carried by a source-base type. Mirrors DWARF - * DW_ATE_* (and the producer's DEBUG_BE_* set) so kit_cg_local/param/field can - * round-trip C signedness into debug info without storage carrying it. */ +/* Debug base-type encoding. Mirrors the producer's DEBUG_BE_* set so frontends + * can round-trip source signedness into debug info without storage carrying it. + */ typedef enum KitCgDebugEncoding { KIT_CG_DEBUG_ENC_NONE, KIT_CG_DEBUG_ENC_BOOL, @@ -129,22 +128,50 @@ typedef struct KitCgFuncSig { bool abi_variadic; } KitCgFuncSig; -typedef struct KitCgField { +/* Field descriptor for record completion (INPUT). Carries the field's source + * shape and layout *policy* — alignment knobs and bit-field width — never its + * position: CG computes byte/bit offsets from these and the target ABI. Query + * the results back with kit_cg_type_record_layout after completion. */ +typedef struct KitCgFieldDesc { KitSym name; /* 0 for anonymous fields/tuple elements */ KitCgTypeId type; - uint32_t align_override; /* 0 = natural, 1 = packed, >1 explicit align */ - uint32_t max_align; /* 0 = natural, otherwise cap field alignment */ - uint32_t flags; /* KitCgFieldFlag */ - uint16_t bit_width; /* bit-field width; 0 w/ BITFIELD = layout barrier */ - uint16_t bit_offset; /* filled by record-field queries */ - uint32_t bit_storage_size; /* bytes, filled by record-field queries */ - int bit_signed; /* signed extraction for bit-field loads */ -} KitCgField; + uint32_t align_override; /* 0 = natural, 1 = packed, >1 explicit align */ + uint32_t max_align; /* 0 = natural, otherwise cap field alignment */ + uint32_t flags; /* KitCgFieldFlag */ + uint16_t bit_width; /* bit-field width; 0 w/ BITFIELD = layout barrier */ + int bit_signed; /* signed extraction for bit-field loads */ +} KitCgFieldDesc; typedef enum KitCgFieldFlag { KIT_CG_FIELD_BITFIELD = 1u << 0, } KitCgFieldFlag; +/* Computed layout of one record field (OUTPUT; borrowed via the record-layout + * view, never an input to completion). For a bit-field, `offset` is the byte + * offset of the storage unit and the bit_* members carry the geometry; for an + * ordinary field bit_width == 0 and the bit_* members are 0. */ +typedef struct KitCgFieldLayout { + KitSym name; + KitCgTypeId type; + uint64_t offset; /* byte offset of the field (or its storage unit) */ + uint32_t flags; /* KitCgFieldFlag */ + uint32_t bit_storage_size; /* storage-unit bytes for a bit-field, else 0 */ + uint16_t bit_offset; /* bit position within the storage unit */ + uint16_t bit_width; /* 0 for a non-bit-field */ + int bit_signed; /* signed extraction for bit-field loads */ +} KitCgFieldLayout; + +/* Immutable, CG-owned record layout, borrowed via kit_cg_type_record_layout. + * The pointer and its fields array stay valid and unchanged for the compiler's + * lifetime once the record is complete, so frontends cache this pointer instead + * of copying offsets into a parallel layout table. */ +typedef struct KitCgRecordLayout { + uint64_t size; + uint32_t align; + uint32_t nfields; + const KitCgFieldLayout* fields; +} KitCgRecordLayout; + typedef struct KitCgEnumValue { KitSym name; uint64_t value; /* bit pattern interpreted using the enum's integer base */ @@ -152,7 +179,7 @@ typedef struct KitCgEnumValue { typedef struct KitCgRecordDesc { KitSym tag; - const KitCgField* fields; + const KitCgFieldDesc* fields; uint32_t nfields; int is_union; uint32_t align_override; /* 0 = natural, >0 explicit record alignment */ @@ -184,7 +211,7 @@ typedef struct KitCgTypeLayout { typedef struct KitCgTypeInfo { KitCgTypeId id; - KitCgTypeId storage_id; /* alias-resolved terminal id, or id */ + KitCgTypeId storage_id; /* storage identity; always equal to id */ KitCgTypeKind kind; /* exact kind */ uint32_t flags; /* KitCgTypeFlag */ KitCgTypeLayout layout; /* ABI/storage layout; valid only when sized */ @@ -234,60 +261,56 @@ static inline KitCgTypeId kit_cg_type_record(KitCompiler* c, return record; } -/* Fresh nominal/source-facing types. */ -KIT_API KitCgTypeId kit_cg_type_alias(KitCompiler*, KitSym name, - KitCgTypeId base); - -/* A source-facing primitive spelling over a width-only storage builtin. storage - * must be a scalar builtin (bool/int/float); the result reports - * KIT_CG_TYPE_SOURCE_BASE for the exact kind, carries name + encoding for debug - * info, and unaliases to storage for all ABI/codegen/storage queries. This lets - * frontends pass one type id and get faithful signed/unsigned debug info - * without storage builtins splitting by sign. */ -KIT_API KitCgTypeId kit_cg_type_source_base(KitCompiler*, KitSym name, - KitCgTypeId storage, - KitCgDebugEncoding encoding); +/* Debug type builders. These return KIT_CG_DEBUG_TYPE_NONE when debug emission + * is not active on the KitCg session. The resulting handles are owned by that + * session and are valid only for declaration attributes passed to the same + * session. */ +KIT_API KitCgDebugType kit_cg_debug_base(KitCg*, KitSym name, + KitCgDebugEncoding, uint32_t bytes); +KIT_API KitCgDebugType kit_cg_debug_typedef(KitCg*, KitSym name, + KitCgDebugType base); +KIT_API KitCgDebugType kit_cg_debug_ptr(KitCg*, KitCgDebugType pointee); +KIT_API KitCgDebugType kit_cg_debug_array(KitCg*, KitCgDebugType elem, + uint64_t count); +KIT_API KitCgDebugType kit_cg_debug_func(KitCg*, KitCgDebugType ret, + const KitCgDebugType* params, + uint32_t nparams, int variadic); +KIT_API KitCgDebugType kit_cg_debug_enum(KitCg*, KitCgTypeId enum_type, + KitCgDebugType base); +KIT_API KitCgDebugType kit_cg_debug_of_type(KitCg*, KitCgTypeId); /* Type queries. * - * kit_cg_type_kind is exact: alias ids report KIT_CG_TYPE_ALIAS. Layout and - * width queries report ABI/storage facts and resolve aliases. Shape-specific - * queries are exact: call kit_cg_type_resolve_alias first when storage shape is - * desired. */ + * Layout and width queries report ABI/storage facts. Shape-specific queries are + * exact over the operational type lattice. */ KIT_API KitStatus kit_cg_type_info(KitCompiler*, KitCgTypeId, KitCgTypeInfo*); /* Stable per-id identity view. Returns a pointer to an interned KitCgTypeInfo * whose IDENTITY fields are authoritative for the lifetime of the compiler: - * id, storage_id (the alias-resolved terminal id), kind (exact), and the - * BUILTIN / NOMINAL flag bits. The layout substruct and the COMPLETE / SIZED - * flag bits are NOT maintained on this view — completeness and sizing can - * change as records complete, and layout is computed lazily — so call - * kit_cg_type_info for an authoritative full snapshot. Returns NULL for an - * invalid id. The cheap identity queries below are inline projections over - * this one extern. */ + * id, storage_id (always id), kind, and the BUILTIN / NOMINAL flag bits. The + * layout substruct and the COMPLETE / SIZED flag bits are NOT maintained on + * this view — completeness and sizing can change as records complete, and + * layout is computed lazily — so call kit_cg_type_info for an authoritative + * full snapshot. Returns NULL for an invalid id. The cheap identity queries + * below are inline projections over this one extern. */ KIT_API const KitCgTypeInfo* kit_cg_type_view(KitCompiler*, KitCgTypeId); KIT_API int kit_cg_type_same_storage(KitCompiler*, KitCgTypeId, KitCgTypeId); KIT_API int kit_cg_type_is_complete(KitCompiler*, KitCgTypeId); KIT_API int kit_cg_type_is_sized(KitCompiler*, KitCgTypeId); -/* Exact kind: alias ids report KIT_CG_TYPE_ALIAS. */ static inline KitCgTypeKind kit_cg_type_kind(KitCompiler* c, KitCgTypeId id) { const KitCgTypeInfo* t = kit_cg_type_view(c, id); return t ? t->kind : KIT_CG_TYPE_VOID; } -/* The alias-resolved terminal (storage) id, or KIT_CG_TYPE_NONE for an - * invalid id. */ +/* The storage id. With no transparent wrapper kinds, this is identity. */ static inline KitCgTypeId kit_cg_type_resolve_alias(KitCompiler* c, KitCgTypeId id) { const KitCgTypeInfo* t = kit_cg_type_view(c, id); - return t ? t->storage_id : KIT_CG_TYPE_NONE; + return t ? t->id : KIT_CG_TYPE_NONE; } -/* True iff the type resolves through aliases to void. */ static inline int kit_cg_type_is_void(KitCompiler* c, KitCgTypeId id) { const KitCgTypeInfo* t = kit_cg_type_view(c, id); - if (!t) return 0; - if (t->storage_id != t->id) t = kit_cg_type_view(c, t->storage_id); return t && t->kind == KIT_CG_TYPE_VOID; } /* A function result carries a value unless it is absent or the void builtin. */ @@ -317,10 +340,14 @@ KIT_API int kit_cg_type_func_is_variadic(KitCompiler*, KitCgTypeId); KIT_API KitSym kit_cg_type_record_tag(KitCompiler*, KitCgTypeId); KIT_API int kit_cg_type_record_is_union(KitCompiler*, KitCgTypeId); KIT_API uint32_t kit_cg_type_record_nfields(KitCompiler*, KitCgTypeId); -/* Returns KIT_OK and fills any non-NULL out parameters on success. */ -KIT_API KitStatus kit_cg_type_record_field(KitCompiler*, KitCgTypeId, - uint32_t index, KitCgField* out, - uint64_t* offset_out); +/* Borrow the computed layout of a complete, sized record: total size/align and + * each field's byte offset and bit geometry. Returns NULL for an invalid id, a + * non-record, or an incomplete/unsized record. The returned pointer is owned by + * CG and stable for the compiler's lifetime; frontends cache it instead of + * copying offsets into a parallel layout table. Replaces per-field record + * queries — fetch once and index fields[] directly. */ +KIT_API const KitCgRecordLayout* kit_cg_type_record_layout(KitCompiler*, + KitCgTypeId); KIT_API KitSym kit_cg_type_enum_tag(KitCompiler*, KitCgTypeId); KIT_API KitCgTypeId kit_cg_type_enum_base(KitCompiler*, KitCgTypeId); @@ -328,14 +355,6 @@ KIT_API uint32_t kit_cg_type_enum_nvalues(KitCompiler*, KitCgTypeId); KIT_API KitStatus kit_cg_type_enum_value(KitCompiler*, KitCgTypeId, uint32_t index, KitCgEnumValue* out); -KIT_API KitSym kit_cg_type_alias_name(KitCompiler*, KitCgTypeId); -KIT_API KitCgTypeId kit_cg_type_alias_base(KitCompiler*, KitCgTypeId); - -KIT_API KitSym kit_cg_type_source_base_name(KitCompiler*, KitCgTypeId); -KIT_API KitCgTypeId kit_cg_type_source_base_storage(KitCompiler*, KitCgTypeId); -KIT_API KitCgDebugEncoding kit_cg_type_source_base_encoding(KitCompiler*, - KitCgTypeId); - typedef enum KitCgSymbolFeature { KIT_CG_SYMFEAT_WEAK, KIT_CG_SYMFEAT_PROTECTED_VISIBILITY, @@ -499,6 +518,7 @@ typedef struct KitCgFuncAttrs { KitSym section; /* 0 = target default */ KitSym target_features; KitCgInlinePolicy inline_policy; + KitCgDebugType debug_type; /* 0 = derive from declared function type */ /* Wasm-target import descriptor. Honored only by the wasm backend, ignored * by other targets. Promotes an undefined function symbol into a wasm * `(import "<module>" "<name>" ...)` entry instead of a missing definition. @@ -529,9 +549,10 @@ typedef enum KitCgObjectFlag { typedef struct KitCgObjectAttrs { KitCgTlsModel tls_model; - uint32_t flags; /* KitCgObjectFlag */ - KitSym section; /* 0 = target default */ - uint32_t align; /* 0 = natural */ + uint32_t flags; /* KitCgObjectFlag */ + KitSym section; /* 0 = target default */ + uint32_t align; /* 0 = natural */ + KitCgDebugType debug_type; /* 0 = derive from object type */ } KitCgObjectAttrs; typedef enum KitCgDeclKind { @@ -657,8 +678,9 @@ typedef enum KitCgLocalFlag { typedef struct KitCgLocalAttrs { KitSym name; - uint32_t align; /* 0 = natural */ - uint32_t flags; /* KitCgLocalFlag */ + uint32_t align; /* 0 = natural */ + uint32_t flags; /* KitCgLocalFlag */ + KitCgDebugType debug_type; /* 0 = derive from local/param type */ } KitCgLocalAttrs; KIT_API KitCgLocal kit_cg_local(KitCg*, KitCgTypeId type, diff --git a/lang/c/abi/c_abi.c b/lang/c/abi/c_abi.c @@ -25,44 +25,48 @@ u32 c_abi_alignof(KitCompiler* a, Pool* p, const Type* t) { const ABIRecordLayout* c_abi_record_layout(KitCompiler* a, Pool* p, const Type* t) { KitCgTypeId id; + const KitCgRecordLayout* view; ABIRecordLayout* L; ABIFieldLayout* fl = NULL; u32 nfields; /* Memoized on the Type node (mirrors cg_id). The layout is a pure function of * the complete record + the fixed target, so once built it never changes; an * incomplete record (no stable layout) is never cached. Collapses the former - * O(M member-accesses x N fields) rebuild to one build per distinct record. */ + * O(M member-accesses x N fields) rebuild to one build per distinct record. + */ if (abi_info_cacheable(t) && t->abi_layout) return t->abi_layout; id = type_cg_id_in_pool(a, p, t); if (kit_cg_type_kind(a, id) != KIT_CG_TYPE_RECORD) return NULL; - nfields = kit_cg_type_record_nfields(a, id); + /* Borrow the CG-owned layout view once; every offset/bit value below is + * sourced from it instead of N per-field queries. */ + view = kit_cg_type_record_layout(a, id); + if (!view) return NULL; + nfields = view->nfields; L = arena_znew(p->arena, ABIRecordLayout); if (!L) return NULL; if (nfields) { fl = arena_zarray(p->arena, ABIFieldLayout, nfields); if (!fl) return NULL; for (u32 i = 0; i < nfields; ++i) { - KitCgField f; - uint64_t off = 0; - memset(&f, 0, sizeof(f)); - if (kit_cg_type_record_field(a, id, i, &f, &off) != 0) return NULL; - fl[i].offset = (u32)off; - fl[i].storage_size = f.bit_storage_size - ? f.bit_storage_size - : (u32)kit_cg_type_size(a, f.type); + const KitCgFieldLayout* f = &view->fields[i]; + fl[i].offset = (u32)f->offset; + fl[i].storage_size = f->bit_storage_size + ? f->bit_storage_size + : (u32)kit_cg_type_size(a, f->type); if (t->rec.fields[i].flags & FIELD_BITFIELD) { fl[i].bit_width = t->rec.fields[i].bitfield_width; - fl[i].bit_offset = f.bit_offset; + fl[i].bit_offset = f->bit_offset; } } } - L->size = (u32)kit_cg_type_size(a, id); - L->align = kit_cg_type_align(a, id); + L->size = (u32)view->size; + L->align = view->align; L->nfields = nfields; L->fields = fl; /* Cache for subsequent accesses. Only a complete record is cacheable; the * RECORD-kind check above already implies the id lowered, but guard anyway so - * an incomplete record (which can't reach here via a RECORD id) never sticks. */ + * an incomplete record (which can't reach here via a RECORD id) never sticks. + */ if (abi_info_cacheable(t)) ((Type*)t)->abi_layout = L; return L; } diff --git a/lang/c/decl/decl.c b/lang/c/decl/decl.c @@ -99,21 +99,24 @@ static ObjSymId decl_emit_cg_sym(DeclTable* t, const Decl* slot) { * (e.g. realpath's `__asm("_realpath$DARWIN_EXTSN")`), so routing the label * back through kit_cg_c_linkage_name would double it. Only mangle the plain * source name. */ - decl.linkage_name = slot->asm_name - ? slot->asm_name - : kit_cg_c_linkage_name(t->c, slot->name); + decl.linkage_name = + slot->asm_name ? slot->asm_name : kit_cg_c_linkage_name(t->c, slot->name); decl.type = type_cg_id_in_pool(t->c, t->pool, slot->type); decl.sym = decl_sym_attrs(slot); if (decl.kind == KIT_CG_DECL_FUNC) { if (slot->flags & DF_NORETURN) decl.as.func.flags |= KIT_CG_FUNC_NORETURN; decl.as.func.inline_policy = decl_inline_policy(slot); decl.as.func.section = slot->section_id; + decl.as.func.debug_type = + type_cg_debug_in_pool(t->cg, t->c, t->pool, slot->type); decl.as.func.wasm_import_module = slot->wasm_import_module; decl.as.func.wasm_import_name = slot->wasm_import_name; } else { if (slot->flags & DF_THREAD) decl.as.object.flags |= KIT_CG_OBJ_TLS; decl.as.object.section = slot->section_id; decl.as.object.align = slot->align; + decl.as.object.debug_type = + type_cg_debug_in_pool(t->cg, t->c, t->pool, slot->type); } return kit_cg_decl(t->cg, decl); } diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -422,6 +422,7 @@ FrameSlot pcg_local(Parser* p, const FrameSlotDesc* fsd) { if (!pcg_emit_enabled(p)) return FRAME_SLOT_NONE; attrs.name = fsd->name; attrs.align = fsd->align; + attrs.debug_type = type_cg_debug_in_pool(p->cg, p->c, p->pool, fsd->type); if (pcg_slot_is_volatile(fsd)) attrs.flags |= KIT_CG_LOCAL_MEMORY_REQUIRED; /* FSF_ADDR_TAKEN is no longer propagated to CG: there is no * KIT_CG_LOCAL_ADDRESS_TAKEN attribute. The C-side flag stays for any @@ -436,6 +437,7 @@ FrameSlot pcg_param_slot(Parser* p, u32 index, const FrameSlotDesc* fsd) { memset(&attrs, 0, sizeof attrs); attrs.name = fsd->name; attrs.align = fsd->align; + attrs.debug_type = type_cg_debug_in_pool(p->cg, p->c, p->pool, fsd->type); if (pcg_slot_is_volatile(fsd)) attrs.flags |= KIT_CG_LOCAL_MEMORY_REQUIRED; return kit_cg_param(p->cg, index, pcg_tid(p, fsd->type), attrs); } @@ -450,6 +452,7 @@ void pcg_func_begin(Parser* p, const CGFuncDesc* fd) { KitCgFuncAttrs attrs; memset(&attrs, 0, sizeof attrs); attrs.inline_policy = fd->inline_policy; + attrs.debug_type = type_cg_debug_in_pool(p->cg, p->c, p->pool, fd->fn_type); if (fd->flags & CGFD_NORETURN) attrs.flags |= KIT_CG_FUNC_NORETURN; kit_cg_func_begin_attrs(p->cg, fd->sym, attrs); } diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -1137,6 +1137,7 @@ static KitCgSym builtin_libcall_sym(Parser* p, const char* name, decl.type = pcg_tid(p, fn_ty); decl.sym.bind = KIT_SB_GLOBAL; decl.sym.visibility = KIT_CG_VIS_DEFAULT; + decl.as.func.debug_type = type_cg_debug_in_pool(p->cg, p->c, p->pool, fn_ty); return kit_cg_decl(p->cg, decl); } diff --git a/lang/c/type/type.c b/lang/c/type/type.c @@ -176,10 +176,10 @@ static Type* alloc_type_node(Pool* p, PoolTypeCache* c) { * padding may stay uninitialized. */ static Type* alloc_struct_type(Pool* p) { Type* t = arena_new(p->arena, Type); - /* cg_id is read by the on-node lowering cache, so it must be initialized even - * though the union tail is intentionally left undefined (see the header). The - * qualified/unqual paths that do `*t = *base` then inherit base's cached id, - * which is correct since lowering ignores qualifiers. */ + /* cg_id is read before structural fields, so initialize it even though the + * union tail is intentionally left undefined (see the header). Qualified / + * unqual paths that do `*t = *base` inherit the cache, which is correct since + * lowering ignores qualifiers today. */ if (t) t->cg_id = KIT_CG_TYPE_NONE; return t; } @@ -744,11 +744,9 @@ static KitCgTypeId type_cg_builtin(KitCompiler* c, TypeKind kind) { } /* Source spelling + debug encoding per integer/char TypeKind. CG integer - * storage is width-only, so the frontend wraps each scalar lowering in a - * source-base type (kit_cg_type_source_base) that carries the C signedness and - * name into debug info while still unaliasing to the width-only storage builtin - * for all ABI/codegen. Kinds with a NULL name (void/bool/float/double) keep the - * bare builtin: the CG debug producer already names them correctly. */ + * storage is width-only; this table drives the separate debug channel so C + * signedness and spelling reach DWARF without changing the operational type id. + * Kinds with a NULL name use the debug producer's default derivation. */ typedef struct ScalarDbgSpec { const char* name; u8 enc; /* KitCgDebugEncoding */ @@ -770,19 +768,12 @@ static const ScalarDbgSpec kScalarDbg[TY_ENUM + 1] = { [TY_UINT128] = {"unsigned __int128", KIT_CG_DEBUG_ENC_UNSIGNED}, }; -/* Lower a scalar TypeKind to its CG type id: a source-base spelling over the - * width-only storage builtin for integer/char kinds, the bare builtin for - * void/bool/float, or NONE for non-scalar kinds (caller falls through to the - * structural lowering). Pure function of (kind, target), like type_cg_builtin. */ +/* Lower a scalar TypeKind to its operational CG type id: a bare storage builtin + * for scalar kinds, or NONE for non-scalar kinds (caller falls through to the + * structural lowering). Pure function of (kind, target), like type_cg_builtin. + */ static KitCgTypeId type_cg_scalar(KitCompiler* c, TypeKind kind) { - KitCgTypeId base = type_cg_builtin(c, kind); - const ScalarDbgSpec* s; - if (base == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; - if ((unsigned)kind > (unsigned)TY_ENUM) return base; - s = &kScalarDbg[kind]; - if (!s->name) return base; - return kit_cg_type_source_base(c, kit_sym_intern(c, kit_slice_cstr(s->name)), - base, (KitCgDebugEncoding)s->enc); + return type_cg_builtin(c, kind); } typedef enum TypeCgMode { @@ -839,7 +830,7 @@ static KitCgTypeId type_cg_record_decl_id(TypeCgLower* l, const Type* t) { } static KitCgTypeId type_cg_record_layout(TypeCgLower* l, const Type* t) { - KitCgField* fields = NULL; + KitCgFieldDesc* fields = NULL; KitCgRecordDesc desc; KitCgTypeId id; int tracked = 0; @@ -873,7 +864,7 @@ static KitCgTypeId type_cg_record_layout(TypeCgLower* l, const Type* t) { tracked = 1; } if (t->rec.nfields) { - fields = arena_zarray(l->p->arena, KitCgField, t->rec.nfields); + fields = arena_zarray(l->p->arena, KitCgFieldDesc, t->rec.nfields); if (!fields) { id = KIT_CG_TYPE_NONE; goto done; @@ -1041,3 +1032,108 @@ KitCgTypeId type_cg_id_in_pool(KitCompiler* c, Pool* p, const Type* t) { l.saw_incomplete = 0; return type_cg_lower(&l, t, TYPE_CG_VALUE); } + +typedef struct TypeCgDebugLower { + KitCg* cg; + KitCompiler* c; + Pool* p; + PoolTypeCache* cache; +} TypeCgDebugLower; + +static KitCgDebugType type_cg_debug_scalar(TypeCgDebugLower* l, TypeKind kind) { + KitCgTypeId storage = type_cg_builtin(l->c, kind); + const ScalarDbgSpec* s; + uint32_t bytes; + if (storage == KIT_CG_TYPE_NONE) return KIT_CG_DEBUG_TYPE_NONE; + if ((unsigned)kind > (unsigned)TY_ENUM) { + return kit_cg_debug_of_type(l->cg, storage); + } + s = &kScalarDbg[kind]; + if (!s->name) return kit_cg_debug_of_type(l->cg, storage); + bytes = (uint32_t)kit_cg_type_size(l->c, storage); + if (!bytes) bytes = 1; + return kit_cg_debug_base(l->cg, kit_sym_intern(l->c, kit_slice_cstr(s->name)), + (KitCgDebugEncoding)s->enc, bytes); +} + +static KitCgDebugType type_cg_debug_record_decl(TypeCgDebugLower* l, + const Type* t) { + TypeCgLower op; + KitCgTypeId id; + op.c = l->c; + op.p = l->p; + op.cache = l->cache; + op.saw_incomplete = 0; + id = type_cg_record_decl_id(&op, t); + return kit_cg_debug_of_type(l->cg, id); +} + +static KitCgDebugType type_cg_debug_lower(TypeCgDebugLower* l, const Type* t) { + KitCgDebugType id; + if (!l || !t) return KIT_CG_DEBUG_TYPE_NONE; + + id = type_cg_debug_scalar(l, (TypeKind)t->kind); + if (id != KIT_CG_DEBUG_TYPE_NONE) return id; + + switch ((TypeKind)t->kind) { + case TY_PTR: { + const Type* pointee = t->ptr.pointee; + KitCgDebugType pd; + if (pointee->kind == TY_STRUCT || pointee->kind == TY_UNION) { + pd = type_cg_debug_record_decl(l, pointee); + } else { + pd = type_cg_debug_lower(l, pointee); + } + id = kit_cg_debug_ptr(l->cg, pd); + break; + } + case TY_ARRAY: + id = kit_cg_debug_array(l->cg, type_cg_debug_lower(l, t->arr.elem), + t->arr.incomplete ? 0u : t->arr.count); + break; + case TY_FUNC: { + KitCgDebugType* params = NULL; + KitCgDebugType ret = type_cg_debug_lower(l, t->fn.ret); + if (t->fn.nparams) { + params = arena_zarray(l->p->arena, KitCgDebugType, t->fn.nparams); + if (!params) { + id = KIT_CG_DEBUG_TYPE_NONE; + break; + } + for (u32 i = 0; i < t->fn.nparams; ++i) { + params[i] = type_cg_debug_lower(l, t->fn.params[i]); + } + } + id = kit_cg_debug_func(l->cg, ret, params, t->fn.nparams, t->fn.variadic); + break; + } + case TY_STRUCT: + case TY_UNION: { + KitCgTypeId op_id = type_cg_id_in_pool(l->c, l->p, t); + id = kit_cg_debug_of_type(l->cg, op_id); + break; + } + case TY_ENUM: { + KitCgTypeId op_id = type_cg_id_in_pool(l->c, l->p, t); + KitCgDebugType base = type_cg_debug_lower(l, t->enm.base); + id = kit_cg_debug_enum(l->cg, op_id, base); + break; + } + default: + id = KIT_CG_DEBUG_TYPE_NONE; + break; + } + + return id; +} + +KitCgDebugType type_cg_debug_in_pool(KitCg* cg, KitCompiler* c, Pool* p, + const Type* t) { + TypeCgDebugLower l; + if (!cg || !p) return KIT_CG_DEBUG_TYPE_NONE; + l.cg = cg; + l.c = c; + l.p = p; + l.cache = cache_get(p); + return type_cg_debug_lower(&l, t); +} diff --git a/lang/c/type/type.h b/lang/c/type/type.h @@ -101,13 +101,15 @@ struct Type { * lowered). Sits in the alignment hole before the 8-aligned union, so the * node stays the same size. NOT part of type identity: the structural intern * set compares named fields and type_tagged_eq compares the rec/enm payload, - * so this mutable cache never participates in interning. See type_cg_lower. */ + * so this mutable cache never participates in interning. See type_cg_lower. + */ KitCgTypeId cg_id; /* Memoized record layout for TY_STRUCT/TY_UNION (NULL = not yet built). Like - * cg_id this is a mutable cache, NOT part of type identity — the interning - * comparisons never read it. Only c_abi_record_layout writes it, and only for - * a complete record, whose layout is immutable + arena-lived for the pool's - * lifetime, so sharing the pointer across qualified variants is safe. */ + * the lowering caches this is mutable state, NOT part of type identity — the + * interning comparisons never read it. Only c_abi_record_layout writes it, + * and only for a complete record, whose layout is immutable + arena-lived for + * the pool's lifetime, so sharing the pointer across qualified variants is + * safe. */ const struct ABIRecordLayout* abi_layout; union { struct { @@ -207,5 +209,6 @@ u32 type_kind_int_rank(TypeKind); TypeKind type_kind_unsigned_variant(TypeKind); KitCgTypeId type_cg_id_in_pool(KitCompiler*, Pool*, const Type*); +KitCgDebugType type_cg_debug_in_pool(KitCg*, KitCompiler*, Pool*, const Type*); #endif diff --git a/lang/toy/asm.c b/lang/toy/asm.c @@ -264,14 +264,14 @@ static int toy_parse_asm_clobbers(ToyParser* p, ToyAsmClobberList* clobbers) { static int toy_asm_record_field_by_name(ToyParser* p, KitCgTypeId record_ty, KitSym name, uint32_t* index_out, - KitCgField* field_out) { - uint32_t i, nfields = kit_cg_type_record_nfields(p->c, record_ty); - for (i = 0; i < nfields; ++i) { - KitCgField field; - if (kit_cg_type_record_field(p->c, record_ty, i, &field, NULL) == 0 && - field.name == name) { + KitCgFieldLayout* field_out) { + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, record_ty); + uint32_t i; + if (!L) return 0; + for (i = 0; i < L->nfields; ++i) { + if (L->fields[i].name == name) { if (index_out) *index_out = i; - if (field_out) *field_out = field; + if (field_out) *field_out = L->fields[i]; return 1; } } @@ -413,8 +413,10 @@ int toy_parse_typed_asm_tail(ToyParser* p, KitCgTypeId result_ty, KitSym tmpl, toy_error(p, p->cur.loc, "out of memory growing asm record outputs"); goto done; } + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, result_ty); + if (!L) goto done; for (i = 0; i < nfields; ++i) { - KitCgField field; + KitCgFieldLayout field; uint32_t field_index = i; if (outputs.items[i].name) { if (!toy_asm_record_field_by_name(p, result_ty, outputs.items[i].name, @@ -423,10 +425,11 @@ int toy_parse_typed_asm_tail(ToyParser* p, KitCgTypeId result_ty, KitSym tmpl, toy_error(p, p->cur.loc, "asm record result output mismatch"); goto done; } - } else if (kit_cg_type_record_field(p->c, result_ty, i, &field, NULL) != - 0) { + } else if (i >= L->nfields) { toy_parser_free_mem(p, seen, nfields * sizeof *seen); goto done; + } else { + field = L->fields[i]; } if (outputs.items[i].type != field.type || seen[field_index]) { toy_parser_free_mem(p, seen, nfields * sizeof *seen); @@ -452,21 +455,23 @@ int toy_parse_typed_asm_tail(ToyParser* p, KitCgTypeId result_ty, KitSym tmpl, if (kit_cg_type_kind(p->c, result_ty) == KIT_CG_TYPE_RECORD && outputs.count != 0) { KitCgLocal rec_slot = kit_cg_local(p->cg, result_ty, toy_slot_attrs(0)); + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, result_ty); uint32_t i = outputs.count; + if (!L) goto done; while (i > 0) { - KitCgField field; + const KitCgFieldLayout* field; uint32_t field_index; - uint64_t foff = 0; + uint64_t foff; --i; field_index = record_field_indexes ? record_field_indexes[i] : i; - if (kit_cg_type_record_field(p->c, result_ty, field_index, &field, - &foff) != 0) - goto done; + if (field_index >= L->nfields) goto done; + field = &L->fields[field_index]; + foff = field->offset; kit_cg_push_local(p->cg, rec_slot); kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)foff); kit_cg_swap(p->cg); - kit_cg_store(p->cg, toy_mem_access(p, field.type)); + kit_cg_store(p->cg, toy_mem_access(p, field->type)); } /* Record result lives as a pointer VALUE (its address) on the stack. */ kit_cg_push_local_addr(p->cg, rec_slot); diff --git a/lang/toy/attrs.c b/lang/toy/attrs.c @@ -352,7 +352,7 @@ int toy_parse_abi_attr_list(ToyParser* p, KitCgAbiAttrs* attrs) { return 1; } -int toy_parse_field_attr_list(ToyParser* p, KitCgField* field) { +int toy_parse_field_attr_list(ToyParser* p, KitCgFieldDesc* field) { if (!toy_parser_match(p, TOK_AT)) return 1; if (!toy_parser_expect(p, TOK_LBRACKET)) { toy_error(p, p->cur.loc, "expected '[' after '@'"); diff --git a/lang/toy/builtins.c b/lang/toy/builtins.c @@ -972,29 +972,32 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, toy_error(p, p->cur.loc, "offsetof expects a record type"); return KIT_CG_TYPE_NONE; } - nfields = kit_cg_type_record_nfields(p->c, ty); - if (tuple_index >= 0) { - if (tuple_index >= (int64_t)nfields || - kit_cg_type_record_field(p->c, ty, (uint32_t)tuple_index, NULL, - &off) != 0) { - toy_error(p, p->cur.loc, "invalid tuple field"); + { + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty); + if (!L) { + toy_error(p, p->cur.loc, "offsetof expects a record type"); return KIT_CG_TYPE_NONE; } - found = 1; - } else { - for (i = 0; i < nfields; ++i) { - KitCgField field; - uint64_t field_off = 0; - if (kit_cg_type_record_field(p->c, ty, i, &field, &field_off) == 0 && - field.name == field_name) { - off = field_off; - found = 1; - break; + nfields = L->nfields; + if (tuple_index >= 0) { + if (tuple_index >= (int64_t)nfields) { + toy_error(p, p->cur.loc, "invalid tuple field"); + return KIT_CG_TYPE_NONE; + } + off = L->fields[tuple_index].offset; + found = 1; + } else { + for (i = 0; i < nfields; ++i) { + if (L->fields[i].name == field_name) { + off = L->fields[i].offset; + found = 1; + break; + } + } + if (!found) { + toy_error(p, p->cur.loc, "unknown record field"); + return KIT_CG_TYPE_NONE; } - } - if (!found) { - toy_error(p, p->cur.loc, "unknown record field"); - return KIT_CG_TYPE_NONE; } } kit_cg_push_int(p->cg, off, p->size_type); @@ -1023,7 +1026,7 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, toy_sym_is(p, name, "sub_overflow") || toy_sym_is(p, name, "mul_overflow")) { KitCgTypeId lhs_ty, rhs_ty, rec_ty; - KitCgField fields[2]; + KitCgFieldDesc fields[2]; KitCgLocal rec_slot; KitCgIntrinsic intrin = KIT_CG_INTRIN_SADD_OVERFLOW; if (toy_sym_is(p, name, "sub_overflow")) @@ -1063,9 +1066,9 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, rec_ty = toy_cg_record_type(p, 0, fields, 2, 0, 0); rec_slot = kit_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); { - uint64_t f0_off = 0, f1_off = 0; - kit_cg_type_record_field(p->c, rec_ty, 0, NULL, &f0_off); - kit_cg_type_record_field(p->c, rec_ty, 1, NULL, &f1_off); + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, rec_ty); + uint64_t f0_off = (L && L->nfields > 0) ? L->fields[0].offset : 0; + uint64_t f1_off = (L && L->nfields > 1) ? L->fields[1].offset : 0; kit_cg_push_local(p->cg, rec_slot); kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)f1_off); @@ -1323,7 +1326,7 @@ KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, KitCgMemOrder success_order, failure_order; int weak; KitCgMemAccess access; - KitCgField fields[2]; + KitCgFieldDesc fields[2]; KitCgLocal rec_slot; if (!toy_parser_expect(p, TOK_LT)) return KIT_CG_TYPE_NONE; ty = toy_parse_type(p); @@ -1370,9 +1373,9 @@ KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, rec_ty = toy_cg_record_type(p, 0, fields, 2, 0, 0); rec_slot = kit_cg_local(p->cg, rec_ty, toy_slot_attrs(0)); { - uint64_t f0_off = 0, f1_off = 0; - kit_cg_type_record_field(p->c, rec_ty, 0, NULL, &f0_off); - kit_cg_type_record_field(p->c, rec_ty, 1, NULL, &f1_off); + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, rec_ty); + uint64_t f0_off = (L && L->nfields > 0) ? L->fields[0].offset : 0; + uint64_t f1_off = (L && L->nfields > 1) ? L->fields[1].offset : 0; kit_cg_push_local(p->cg, rec_slot); kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)f1_off); diff --git a/lang/toy/data.c b/lang/toy/data.c @@ -222,10 +222,12 @@ int toy_parse_global_record_initializer(ToyParser* p, KitCgSym sym, uint8_t* seen; uint64_t pos = 0; uint64_t total_size = kit_cg_type_size(p->c, record_ty); - uint32_t nfields = kit_cg_type_record_nfields(p->c, record_ty); + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, record_ty); + uint32_t nfields = L ? L->nfields : 0; size_t seen_size = (size_t)(nfields ? nfields : 1u) * sizeof *seen; ToyNamedType* named = toy_find_named_type_by_type(p, record_ty); int positional = named && named->kind == TOY_NAMED_TUPLE; + if (!L) return 0; seen = (uint8_t*)toy_parser_zalloc(p, nfields ? nfields : 1u, sizeof *seen, "record initializer"); if (!seen) { @@ -241,24 +243,21 @@ int toy_parse_global_record_initializer(ToyParser* p, KitCgSym sym, if (positional) { uint32_t field_index = 0; while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) { - KitCgField field; + const KitCgFieldLayout* field; uint64_t field_off; if (field_index >= nfields) { toy_error(p, p->cur.loc, "too many tuple initializer elements"); toy_parser_free_mem(p, seen, seen_size); return 0; } - if (kit_cg_type_record_field(p->c, record_ty, field_index, &field, - &field_off) != 0) { - toy_parser_free_mem(p, seen, seen_size); - return 0; - } + field = &L->fields[field_index]; + field_off = field->offset; if (field_off > pos) { kit_cg_data_zero(p->cg, field_off - pos); pos = field_off; } if (p->cur.kind == TOK_AT) { - if (!toy_parse_data_array_builtin(p, field.type, total_size, &pos)) { + if (!toy_parse_data_array_builtin(p, field->type, total_size, &pos)) { toy_parser_free_mem(p, seen, seen_size); return 0; } @@ -267,8 +266,8 @@ int toy_parse_global_record_initializer(ToyParser* p, KitCgSym sym, toy_parser_free_mem(p, seen, seen_size); return 0; } else { - kit_cg_data_int(p->cg, (uint64_t)p->cur.int_value, field.type); - pos += kit_cg_type_size(p->c, field.type); + kit_cg_data_int(p->cg, (uint64_t)p->cur.int_value, field->type); + pos += kit_cg_type_size(p->c, field->type); toy_parser_advance(p); } field_index++; @@ -286,7 +285,7 @@ int toy_parse_global_record_initializer(ToyParser* p, KitCgSym sym, } while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) { KitSym field_name; - KitCgField field; + KitCgFieldLayout field; uint32_t field_index; uint64_t field_off; if (p->cur.kind != TOK_IDENT) { @@ -313,11 +312,7 @@ int toy_parse_global_record_initializer(ToyParser* p, KitCgSym sym, return 0; } seen[field_index] = 1; - if (kit_cg_type_record_field(p->c, record_ty, field_index, NULL, - &field_off) != 0) { - toy_parser_free_mem(p, seen, seen_size); - return 0; - } + field_off = field.offset; if (field_off < pos) { toy_error(p, p->cur.loc, "record initializer fields out of order"); toy_parser_free_mem(p, seen, seen_size); diff --git a/lang/toy/decls.c b/lang/toy/decls.c @@ -28,7 +28,7 @@ int toy_parse_type_alias_decl(ToyParser* p) { int toy_parse_record_decl(ToyParser* p) { KitSym name; - KitCgField* fields = NULL; + KitCgFieldDesc* fields = NULL; ToyRecordFieldInfo* field_infos = NULL; size_t nfields = 0; size_t cap_fields = 0; @@ -140,7 +140,7 @@ done: int toy_parse_tuple_decl(ToyParser* p) { KitSym name; - KitCgField* fields = NULL; + KitCgFieldDesc* fields = NULL; ToyRecordFieldInfo* field_infos = NULL; size_t nfields = 0; size_t cap_fields = 0; diff --git a/lang/toy/expr.c b/lang/toy/expr.c @@ -601,22 +601,24 @@ KitCgTypeId toy_emit_slice_index_lvalue(ToyParser* p, KitCgTypeId slice_ty, ToyTypeId* elem_toy_out) { ToyTypeId elem_toy = toy_type_slice_elem(p, slice_toy_type); KitCgTypeId elem_ty = toy_type_id_cg_or_none(p, elem_toy); - KitCgField ptr_field; + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, slice_ty); KitCgLocal idx_slot; - uint64_t ptr_field_off = 0; + uint64_t ptr_field_off; + KitCgTypeId ptr_field_type; if (elem_ty == KIT_CG_TYPE_NONE || - kit_cg_type_kind(p->c, slice_ty) != KIT_CG_TYPE_RECORD || - kit_cg_type_record_field(p->c, slice_ty, 0, &ptr_field, &ptr_field_off) != - 0) { + kit_cg_type_kind(p->c, slice_ty) != KIT_CG_TYPE_RECORD || !L || + L->nfields < 1) { toy_error(p, p->cur.loc, "cannot index non-array/non-pointer"); return KIT_CG_TYPE_NONE; } + ptr_field_off = L->fields[0].offset; + ptr_field_type = L->fields[0].type; /* Stash the index, then load the slice's ptr field, then re-push idx * and compute element pointer. */ idx_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); toy_store_tos_to_local(p, idx_slot, p->size_type); kit_cg_deref(p->cg, (int64_t)ptr_field_off); - kit_cg_load(p->cg, toy_mem_access(p, ptr_field.type)); + kit_cg_load(p->cg, toy_mem_access(p, ptr_field_type)); kit_cg_push_local(p->cg, idx_slot); kit_cg_load(p->cg, toy_mem_access(p, p->size_type)); toy_addr_index(p, kit_cg_type_size(p->c, elem_ty), @@ -632,7 +634,7 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, KitCgTypeId elem_ty = KIT_CG_TYPE_NONE; ToyTypeId slice_toy; KitCgTypeId slice_ty; - KitCgField ptr_field; + KitCgTypeId ptr_field_type = KIT_CG_TYPE_NONE; KitCgLocal start_slot; KitCgLocal end_slot; KitCgLocal result_slot; @@ -661,16 +663,14 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, { uint64_t ptr_off = 0; uint64_t len_off = 0; - KitCgField len_field; - (void)len_field; - if (slice_ty == KIT_CG_TYPE_NONE || - kit_cg_type_record_field(p->c, slice_ty, 0, &ptr_field, &ptr_off) != - 0 || - kit_cg_type_record_field(p->c, slice_ty, 1, &len_field, &len_off) != - 0) { + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, slice_ty); + if (slice_ty == KIT_CG_TYPE_NONE || !L || L->nfields < 2) { toy_error(p, p->cur.loc, "failed to create slice type"); return KIT_CG_TYPE_NONE; } + ptr_off = L->fields[0].offset; + ptr_field_type = L->fields[0].type; + len_off = L->fields[1].offset; end_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); toy_store_tos_to_local(p, end_slot, p->size_type); @@ -682,7 +682,7 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, if (toy_type_is_slice(p, base_toy_type)) { /* Replace slice base with its data pointer (a pointer-rvalue). */ kit_cg_deref(p->cg, (int64_t)ptr_off); - kit_cg_load(p->cg, toy_mem_access(p, ptr_field.type)); + kit_cg_load(p->cg, toy_mem_access(p, ptr_field_type)); } else { /* Array base: TOS is a pointer-rvalue (callers always project * to a pointer for array/slice bases now). Bitcast to *elem. */ @@ -699,7 +699,7 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)ptr_off); kit_cg_swap(p->cg); - kit_cg_store(p->cg, toy_mem_access(p, ptr_field.type)); + kit_cg_store(p->cg, toy_mem_access(p, ptr_field_type)); /* len = end - start; store into result_slot.len. */ kit_cg_push_local(p->cg, result_slot); @@ -1048,7 +1048,7 @@ static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) { KitSym field_name; uint32_t i, nfields; int found = 0; - KitCgField found_field; + KitCgFieldLayout found_field; uint64_t found_off = 0; ToyNamedType* named; ToyTypeId field_toy_type = TOY_TYPE_NONE; @@ -1063,18 +1063,16 @@ static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) { named = toy_find_named_type_by_type(p, ty); if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { uint32_t field_index; - if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD || - p->cur.int_value < 0 || - p->cur.int_value >= (int64_t)kit_cg_type_record_nfields(p->c, ty)) { + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty); + if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD || !L || + p->cur.int_value < 0 || p->cur.int_value >= (int64_t)L->nfields) { toy_error(p, p->cur.loc, "invalid tuple field"); return KIT_CG_TYPE_NONE; } field_index = (uint32_t)p->cur.int_value; toy_parser_advance(p); - if (kit_cg_type_record_field(p->c, ty, field_index, &found_field, - &found_off) != 0) { - return KIT_CG_TYPE_NONE; - } + found_field = L->fields[field_index]; + found_off = found_field.offset; if (named && field_index < named->nfields) field_toy_type = named->fields[field_index].toy_type; ty = found_field.type; @@ -1105,19 +1103,19 @@ static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) { toy_error(p, p->cur.loc, "field access on non-record"); return KIT_CG_TYPE_NONE; } - nfields = kit_cg_type_record_nfields(p->c, ty); - memset(&found_field, 0, sizeof found_field); - for (i = 0; i < nfields; ++i) { - KitCgField field; - uint64_t off = 0; - if (kit_cg_type_record_field(p->c, ty, i, &field, &off) == 0 && - field.name == field_name) { - found = 1; - found_field = field; - found_off = off; - if (named && i < named->nfields) - field_toy_type = named->fields[i].toy_type; - break; + { + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty); + nfields = L ? L->nfields : 0; + memset(&found_field, 0, sizeof found_field); + for (i = 0; L && i < nfields; ++i) { + if (L->fields[i].name == field_name) { + found = 1; + found_field = L->fields[i]; + found_off = found_field.offset; + if (named && i < named->nfields) + field_toy_type = named->fields[i].toy_type; + break; + } } } if (!found) { @@ -1306,7 +1304,7 @@ static KitCgTypeId toy_parse_expr_unary(ToyParser* p) { continue; } if (toy_parser_match(p, TOK_DOT)) { - KitCgField field; + KitCgFieldLayout field; uint32_t field_index = 0; uint64_t foff = 0; ToyNamedType* named; @@ -1325,17 +1323,16 @@ static KitCgTypeId toy_parse_expr_unary(ToyParser* p) { } named = toy_find_named_type_by_type(p, ty); if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { - if (p->cur.int_value < 0 || - p->cur.int_value >= - (int64_t)kit_cg_type_record_nfields(p->c, ty)) { + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty); + if (!L || p->cur.int_value < 0 || + p->cur.int_value >= (int64_t)L->nfields) { toy_error(p, p->cur.loc, "invalid tuple field"); return KIT_CG_TYPE_NONE; } field_index = (uint32_t)p->cur.int_value; toy_parser_advance(p); - if (kit_cg_type_record_field(p->c, ty, field_index, &field, - &foff) != 0) - return KIT_CG_TYPE_NONE; + field = L->fields[field_index]; + foff = field.offset; } else { KitSym field_name; if (p->cur.kind != TOK_IDENT) { @@ -1349,9 +1346,7 @@ static KitCgTypeId toy_parse_expr_unary(ToyParser* p) { toy_error(p, p->cur.loc, "unknown record field"); return KIT_CG_TYPE_NONE; } - if (kit_cg_type_record_field(p->c, ty, field_index, NULL, &foff) != - 0) - return KIT_CG_TYPE_NONE; + foff = field.offset; } ty = field.type; ty_toy = (named && field_index < named->nfields) diff --git a/lang/toy/internal.h b/lang/toy/internal.h @@ -285,10 +285,10 @@ typedef struct ToyParser { KitCgTypeId toy_builtin_type(ToyParser* p, KitCgBuiltinType ty); KitCgTypeId toy_cg_record_type(ToyParser* p, KitSym tag, - const KitCgField* fields, uint32_t nfields, + const KitCgFieldDesc* fields, uint32_t nfields, int is_union, uint32_t align_override); int toy_cg_record_complete(ToyParser* p, KitCgTypeId record, KitSym tag, - const KitCgField* fields, uint32_t nfields, + const KitCgFieldDesc* fields, uint32_t nfields, int is_union, uint32_t align_override); /* The toy frontend models a single return value: the function's first result * type, or void when it has no results. */ @@ -377,7 +377,7 @@ int toy_parse_attr_list(ToyParser* p, ToyAttrSet* attrs, int toy_validate_attr_placement(ToyParser* p, const ToyAttrSet* attrs, uint32_t allowed, const char* message); int toy_parse_abi_attr_list(ToyParser* p, KitCgAbiAttrs* attrs); -int toy_parse_field_attr_list(ToyParser* p, KitCgField* field); +int toy_parse_field_attr_list(ToyParser* p, KitCgFieldDesc* field); int toy_parse_record_attr_list(ToyParser* p, int* packed_out, uint32_t* align_out); KitCgTypeId toy_parse_type(ToyParser* p); @@ -474,7 +474,7 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, KitCgTypeId end_ty, ToyTypeId* slice_toy_out); int toy_record_field_index(ToyParser* p, KitCgTypeId record_ty, KitSym field_name, uint32_t* index_out, - KitCgField* field_out); + KitCgFieldLayout* field_out); int toy_add_named_type(ToyParser* p, KitSym name, KitCgTypeId type, ToyNamedTypeKind kind, KitCgTypeId base_type); int toy_set_named_type_fields(ToyParser* p, ToyNamedType* named, diff --git a/lang/toy/parser.c b/lang/toy/parser.c @@ -64,22 +64,19 @@ static int toy_check_source_value(ToyParser* p, KitCgTypeId expected_cg, static int toy_records_have_matching_storage(ToyParser* p, KitCgTypeId expected, KitCgTypeId actual) { uint32_t i; - uint32_t nfields; + const KitCgRecordLayout* el; + const KitCgRecordLayout* al; if (kit_cg_type_kind(p->c, expected) != KIT_CG_TYPE_RECORD || kit_cg_type_kind(p->c, actual) != KIT_CG_TYPE_RECORD) { return 0; } - nfields = kit_cg_type_record_nfields(p->c, expected); - if (nfields != kit_cg_type_record_nfields(p->c, actual)) return 0; - for (i = 0; i < nfields; ++i) { - KitCgField expected_field; - KitCgField actual_field; - if (kit_cg_type_record_field(p->c, expected, i, &expected_field, NULL) || - kit_cg_type_record_field(p->c, actual, i, &actual_field, NULL)) { - return 0; - } - if (expected_field.name != actual_field.name || - expected_field.type != actual_field.type) { + el = kit_cg_type_record_layout(p->c, expected); + al = kit_cg_type_record_layout(p->c, actual); + if (!el || !al) return 0; + if (el->nfields != al->nfields) return 0; + for (i = 0; i < el->nfields; ++i) { + if (el->fields[i].name != al->fields[i].name || + el->fields[i].type != al->fields[i].type) { return 0; } } @@ -90,24 +87,24 @@ static int toy_copy_record_lvalue_to_local(ToyParser* p, KitCgTypeId src_ty, KitCgLocal dst_slot, KitCgTypeId dst_ty) { uint32_t i; - uint32_t nfields; + const KitCgRecordLayout* L; if (!toy_records_have_matching_storage(p, dst_ty, src_ty)) { toy_error(p, p->cur.loc, "record storage mismatch"); return 0; } - nfields = kit_cg_type_record_nfields(p->c, dst_ty); - for (i = 0; i < nfields; ++i) { - KitCgField field; - uint64_t offset = 0; - if (kit_cg_type_record_field(p->c, dst_ty, i, &field, &offset)) return 0; + L = kit_cg_type_record_layout(p->c, dst_ty); + if (!L) return 0; + for (i = 0; i < L->nfields; ++i) { + const KitCgFieldLayout* field = &L->fields[i]; + uint64_t offset = field->offset; kit_cg_dup(p->cg); kit_cg_deref(p->cg, (int64_t)offset); - kit_cg_load(p->cg, toy_mem_access(p, field.type)); + kit_cg_load(p->cg, toy_mem_access(p, field->type)); kit_cg_push_local(p->cg, dst_slot); kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)offset); kit_cg_swap(p->cg); - kit_cg_store(p->cg, toy_mem_access(p, field.type)); + kit_cg_store(p->cg, toy_mem_access(p, field->type)); } kit_cg_drop(p->cg); return 1; @@ -118,19 +115,19 @@ static int toy_copy_record_lvalue_to_var(ToyParser* p, KitCgTypeId src_ty, const ToyGlobal* dst_global) { KitCgTypeId dst_ty = dst_var ? dst_var->type : dst_global->type; uint32_t i; - uint32_t nfields; + const KitCgRecordLayout* L; if (!toy_records_have_matching_storage(p, dst_ty, src_ty)) { toy_error(p, p->cur.loc, "record storage mismatch"); return 0; } - nfields = kit_cg_type_record_nfields(p->c, dst_ty); - for (i = 0; i < nfields; ++i) { - KitCgField field; - uint64_t offset = 0; - if (kit_cg_type_record_field(p->c, dst_ty, i, &field, &offset)) return 0; + L = kit_cg_type_record_layout(p->c, dst_ty); + if (!L) return 0; + for (i = 0; i < L->nfields; ++i) { + const KitCgFieldLayout* field = &L->fields[i]; + uint64_t offset = field->offset; kit_cg_dup(p->cg); kit_cg_deref(p->cg, (int64_t)offset); - kit_cg_load(p->cg, toy_mem_access(p, field.type)); + kit_cg_load(p->cg, toy_mem_access(p, field->type)); if (dst_var) { toy_push_var_lvalue(p, dst_var); } else { @@ -138,7 +135,7 @@ static int toy_copy_record_lvalue_to_var(ToyParser* p, KitCgTypeId src_ty, } kit_cg_deref(p->cg, (int64_t)offset); kit_cg_swap(p->cg); - kit_cg_store(p->cg, toy_mem_access(p, field.type)); + kit_cg_store(p->cg, toy_mem_access(p, field->type)); } kit_cg_drop(p->cg); return 1; @@ -193,10 +190,13 @@ static int toy_parse_array_initializer(ToyParser* p, KitCgLocal slot, static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot, KitCgTypeId record_ty, ToyTypeId record_toy_type) { - uint32_t i, nfields = kit_cg_type_record_nfields(p->c, record_ty); + uint32_t i; + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, record_ty); + uint32_t nfields = L ? L->nfields : 0; ToyNamedType* named = toy_find_named_type_by_type(p, record_ty); int positional = named && named->kind == TOY_NAMED_TUPLE; (void)record_toy_type; + if (!L) return 0; if (p->cur.kind == TOK_IDENT) toy_parser_advance(p); if (!toy_parser_expect(p, TOK_LBRACE)) { toy_error(p, p->cur.loc, "expected record literal"); @@ -204,30 +204,27 @@ static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot, } for (i = 0; i < nfields; ++i) { - KitCgField field; - uint64_t foff = 0; - if (kit_cg_type_record_field(p->c, record_ty, i, &field, &foff) != 0) - return 0; + const KitCgFieldLayout* field = &L->fields[i]; + uint64_t foff = field->offset; kit_cg_push_local(p->cg, slot); kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)foff); - kit_cg_push_int(p->cg, 0, field.type); - kit_cg_store(p->cg, toy_mem_access(p, field.type)); + kit_cg_push_int(p->cg, 0, field->type); + kit_cg_store(p->cg, toy_mem_access(p, field->type)); } if (positional) { uint32_t field_index = 0; while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) { - KitCgField field; + const KitCgFieldLayout* field; KitCgTypeId expr_ty; - uint64_t foff = 0; + uint64_t foff; if (field_index >= nfields) { toy_error(p, p->cur.loc, "too many tuple fields"); return 0; } - if (kit_cg_type_record_field(p->c, record_ty, field_index, &field, - &foff) != 0) - return 0; + field = &L->fields[field_index]; + foff = field->offset; kit_cg_push_local(p->cg, slot); kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)foff); @@ -237,16 +234,16 @@ static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot, ToyTypeId expected = (named && field_index < named->nfields) ? named->fields[field_index].toy_type : TOY_TYPE_NONE; - if (!toy_check_source_value(p, field.type, expected, expr_ty, + if (!toy_check_source_value(p, field->type, expected, expr_ty, p->last_type, "tuple field type mismatch")) { return 0; } } - if (expr_ty != field.type && - !toy_emit_checked_cast(p, expr_ty, field.type)) + if (expr_ty != field->type && + !toy_emit_checked_cast(p, expr_ty, field->type)) return 0; - kit_cg_store(p->cg, toy_mem_access(p, field.type)); + kit_cg_store(p->cg, toy_mem_access(p, field->type)); field_index++; if (!toy_parser_match(p, TOK_COMMA)) break; } @@ -259,7 +256,7 @@ static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot, while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) { KitSym field_name; - KitCgField field; + KitCgFieldLayout field; uint32_t field_index; KitCgTypeId expr_ty; uint64_t foff = 0; @@ -278,9 +275,7 @@ static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot, toy_error(p, p->cur.loc, "unknown record field"); return 0; } - if (kit_cg_type_record_field(p->c, record_ty, field_index, NULL, &foff) != - 0) - return 0; + foff = field.offset; kit_cg_push_local(p->cg, slot); kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)foff); @@ -1648,7 +1643,7 @@ static int toy_parse_stmt(ToyParser* p) { continue; } if (toy_parser_match(p, TOK_DOT)) { - KitCgField field; + KitCgFieldLayout field; uint32_t field_index = 0; ToyNamedType* named; uint64_t foff = 0; @@ -1674,11 +1669,13 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "invalid tuple field"); return 0; } + const KitCgRecordLayout* L; field_index = (uint32_t)p->cur.int_value; toy_parser_advance(p); - if (kit_cg_type_record_field(p->c, lhs_ty, field_index, &field, - &foff) != 0) - return 0; + L = kit_cg_type_record_layout(p->c, lhs_ty); + if (!L || field_index >= L->nfields) return 0; + field = L->fields[field_index]; + foff = field.offset; } else { KitSym field_name; if (p->cur.kind != TOK_IDENT) { @@ -1692,9 +1689,7 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "unknown record field"); return 0; } - if (kit_cg_type_record_field(p->c, lhs_ty, field_index, NULL, - &foff) != 0) - return 0; + foff = field.offset; } lhs_slice_metadata = toy_type_is_slice(p, lhs_toy_type) && (field_index == 0 || field_index == 1); diff --git a/lang/toy/parser_core.c b/lang/toy/parser_core.c @@ -9,7 +9,7 @@ KitCgTypeId toy_builtin_type(ToyParser* p, KitCgBuiltinType ty) { } KitCgTypeId toy_cg_record_type(ToyParser* p, KitSym tag, - const KitCgField* fields, uint32_t nfields, + const KitCgFieldDesc* fields, uint32_t nfields, int is_union, uint32_t align_override) { KitCgRecordDesc desc; memset(&desc, 0, sizeof desc); @@ -22,7 +22,7 @@ KitCgTypeId toy_cg_record_type(ToyParser* p, KitSym tag, } int toy_cg_record_complete(ToyParser* p, KitCgTypeId record, KitSym tag, - const KitCgField* fields, uint32_t nfields, + const KitCgFieldDesc* fields, uint32_t nfields, int is_union, uint32_t align_override) { KitCgRecordDesc desc; memset(&desc, 0, sizeof desc); diff --git a/lang/toy/types.c b/lang/toy/types.c @@ -211,7 +211,7 @@ KitCgTypeId toy_parse_type(ToyParser* p) { } } if (toy_parser_match(p, TOK_RECORD)) { - KitCgField* fields = NULL; + KitCgFieldDesc* fields = NULL; size_t nfields = 0; size_t cap_fields = 0; int packed = 0; @@ -465,7 +465,6 @@ ToyTypeId toy_type_from_cg(ToyParser* p, KitCgTypeId cg) { case KIT_CG_TYPE_INT: case KIT_CG_TYPE_FLOAT: case KIT_CG_TYPE_VARARG_STATE: - case KIT_CG_TYPE_SOURCE_BASE: type.kind = TOY_TYPE_BUILTIN; break; case KIT_CG_TYPE_PTR: @@ -490,9 +489,6 @@ ToyTypeId toy_type_from_cg(ToyParser* p, KitCgTypeId cg) { case KIT_CG_TYPE_ENUM: type.kind = TOY_TYPE_ENUM; break; - case KIT_CG_TYPE_ALIAS: - type.kind = TOY_TYPE_ALIAS; - break; } return toy_type_add(p, &type); } @@ -560,7 +556,7 @@ ToyTypeId toy_type_register_ptr(ToyParser* p, KitCgTypeId cg, ToyTypeId pointee, ToyTypeId toy_type_register_slice(ToyParser* p, KitCgTypeId elem_cg, ToyTypeId elem) { - KitCgField fields[2]; + KitCgFieldDesc fields[2]; KitCgTypeId ptr_ty; ToyType type; size_t i; @@ -657,22 +653,19 @@ int toy_type_is_slice(ToyParser* p, ToyTypeId id) { static int toy_anon_record_types_match(ToyParser* p, KitCgTypeId expected, KitCgTypeId actual) { uint32_t i; - uint32_t nfields; + const KitCgRecordLayout* el; + const KitCgRecordLayout* al; if (kit_cg_type_kind(p->c, expected) != KIT_CG_TYPE_RECORD || kit_cg_type_kind(p->c, actual) != KIT_CG_TYPE_RECORD) { return 0; } - nfields = kit_cg_type_record_nfields(p->c, expected); - if (nfields != kit_cg_type_record_nfields(p->c, actual)) return 0; - for (i = 0; i < nfields; ++i) { - KitCgField exp_field; - KitCgField act_field; - if (kit_cg_type_record_field(p->c, expected, i, &exp_field, NULL) != 0 || - kit_cg_type_record_field(p->c, actual, i, &act_field, NULL) != 0) { - return 0; - } - if (exp_field.name != act_field.name) return 0; - if (exp_field.type != act_field.type) return 0; + el = kit_cg_type_record_layout(p->c, expected); + al = kit_cg_type_record_layout(p->c, actual); + if (!el || !al) return 0; + if (el->nfields != al->nfields) return 0; + for (i = 0; i < el->nfields; ++i) { + if (el->fields[i].name != al->fields[i].name) return 0; + if (el->fields[i].type != al->fields[i].type) return 0; } return 1; } @@ -774,14 +767,14 @@ int toy_type_accepts_type(ToyParser* p, ToyTypeId expected, ToyTypeId actual) { int toy_record_field_index(ToyParser* p, KitCgTypeId record_ty, KitSym field_name, uint32_t* index_out, - KitCgField* field_out) { - uint32_t i, nfields = kit_cg_type_record_nfields(p->c, record_ty); - for (i = 0; i < nfields; ++i) { - KitCgField field; - if (kit_cg_type_record_field(p->c, record_ty, i, &field, NULL) == 0 && - field.name == field_name) { + KitCgFieldLayout* field_out) { + const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, record_ty); + uint32_t i; + if (!L) return 0; + for (i = 0; i < L->nfields; ++i) { + if (L->fields[i].name == field_name) { if (index_out) *index_out = i; - if (field_out) *field_out = field; + if (field_out) *field_out = L->fields[i]; return 1; } } diff --git a/lang/wasm/cg.c b/lang/wasm/cg.c @@ -16,7 +16,7 @@ static WasmCgBuiltinTypes wasm_cg_builtin_types(KitCompiler* c) { } static KitCgTypeId wasm_cg_record_type(KitCompiler* c, KitSym tag, - const KitCgField* fields, + const KitCgFieldDesc* fields, uint32_t nfields) { KitCgRecordDesc desc; memset(&desc, 0, sizeof desc); @@ -266,11 +266,12 @@ static void wasm_indexed_name(char* name, size_t cap, const char* prefix, static uint64_t wasm_cg_field_offset(KitCompiler* c, KitCgTypeId ty, uint32_t index) { - uint64_t off = 0; - KitStatus st = kit_cg_type_record_field(c, ty, index, NULL, &off); - if (st != KIT_OK) + const KitCgRecordLayout* L = kit_cg_type_record_layout(c, ty); + if (!L || index >= L->nfields) { wasm_error(c, wasm_loc(0, 0), "wasm: failed to query field offset"); - return off; + return 0; + } + return L->fields[index].offset; } static uint32_t wasm_cg_checked_add_u32(KitCompiler* c, uint32_t a, uint32_t b, @@ -283,20 +284,21 @@ static uint32_t wasm_cg_checked_add_u32(KitCompiler* c, uint32_t a, uint32_t b, static void wasm_cg_build_runtime(KitCompiler* c, WasmCgBuiltinTypes b, const WasmModule* m, WasmCgRuntime* rt, KitArena* arena) { - KitCgField memory_fields[4]; - KitCgField func_import_fields[1]; - KitCgField global_import_fields[1]; - KitCgField table_entry_fields[2]; - KitCgField table_fields[3]; - KitCgField passive_data_fields[2]; - KitCgField passive_elem_fields[2]; + KitCgFieldDesc memory_fields[4]; + KitCgFieldDesc func_import_fields[1]; + KitCgFieldDesc global_import_fields[1]; + KitCgFieldDesc table_entry_fields[2]; + KitCgFieldDesc table_fields[3]; + KitCgFieldDesc passive_data_fields[2]; + KitCgFieldDesc passive_elem_fields[2]; /* Total instance fields = nmemories + (#import funcs) + nfuncs (one * func_ref entry per func) + nglobals + 2*ntables + ndata + nelems. * Allocate the upper bound from the arena so nfields can grow with the * module. */ uint32_t instance_cap = 0; - KitCgField* instance_fields = - instance_cap ? kit_arena_zarray(arena, KitCgField, instance_cap) : NULL; + KitCgFieldDesc* instance_fields = + instance_cap ? kit_arena_zarray(arena, KitCgFieldDesc, instance_cap) + : NULL; uint32_t nfields = 0; uint32_t* memory_field_idx = NULL; uint32_t* func_import_field_idx = NULL; @@ -324,8 +326,9 @@ static void wasm_cg_build_runtime(KitCompiler* c, WasmCgBuiltinTypes b, wasm_error(c, wasm_loc(0, 0), "wasm: module layout is too large"); instance_cap = wasm_cg_checked_add_u32(c, instance_cap, 2u * m->nelems, wasm_loc(0, 0)); - instance_fields = - instance_cap ? kit_arena_zarray(arena, KitCgField, instance_cap) : NULL; + instance_fields = instance_cap + ? kit_arena_zarray(arena, KitCgFieldDesc, instance_cap) + : NULL; rt->memory_field = m->nmemories ? kit_arena_zarray(arena, uint32_t, m->nmemories) : NULL; diff --git a/src/abi/abi.c b/src/abi/abi.c @@ -30,10 +30,6 @@ static ABITypeInfo abi_cg_type_info_compute(TargetABI* a, KitCgTypeId id) { t = cg_type_get(a->c, id); if (!t) return r; switch (t->kind) { - case KIT_CG_TYPE_ALIAS: - return abi_cg_type_info(a, t->alias.base); - case KIT_CG_TYPE_SOURCE_BASE: - return abi_cg_type_info(a, t->source_base.base); case KIT_CG_TYPE_PTR: r.size = a->c->target.ptr_size ? a->c->target.ptr_size : 8; r.align = a->c->target.ptr_align ? a->c->target.ptr_align : 8; diff --git a/src/abi/abi_aapcs64.c b/src/abi/abi_aapcs64.c @@ -76,12 +76,6 @@ static void classify_one(TargetABI* a, KitCgTypeId t, ABIArgInfo* out, case KIT_CG_TYPE_RECORD: classify_aggregate(a, t, out, is_return); return; - case KIT_CG_TYPE_ALIAS: - classify_one(a, ty->alias.base, out, is_return); - return; - case KIT_CG_TYPE_SOURCE_BASE: - classify_one(a, ty->source_base.base, out, is_return); - return; default: classify_scalar(a, t, out); return; diff --git a/src/abi/abi_rv64.c b/src/abi/abi_rv64.c @@ -94,11 +94,6 @@ static u32 riscv_collect_leaves(TargetABI* a, KitCgTypeId tid, u32 base_off, AbiLeaf* out, u32 cap, u32 written) { const CgType* t = cg_type_get(a->c, tid); if (!t) return written + 1u; /* poison: treat as too-many */ - if (t->kind == KIT_CG_TYPE_ALIAS) - return riscv_collect_leaves(a, t->alias.base, base_off, out, cap, written); - if (t->kind == KIT_CG_TYPE_SOURCE_BASE) - return riscv_collect_leaves(a, t->source_base.base, base_off, out, cap, - written); if (t->kind == KIT_CG_TYPE_RECORD) { if (t->record.is_union) return cap + 1u; /* unions: bail */ for (u32 i = 0; i < t->record.nfields; ++i) { @@ -273,12 +268,6 @@ static void classify_one(TargetABI* a, KitCgTypeId t, ABIArgInfo* out, case KIT_CG_TYPE_RECORD: classify_aggregate(a, t, out, is_return); return; - case KIT_CG_TYPE_ALIAS: - classify_one(a, ty->alias.base, out, is_return); - return; - case KIT_CG_TYPE_SOURCE_BASE: - classify_one(a, ty->source_base.base, out, is_return); - return; default: classify_scalar(a, t, out); return; diff --git a/src/abi/abi_sysv_x64.c b/src/abi/abi_sysv_x64.c @@ -70,12 +70,6 @@ static int classify_range(TargetABI* a, KitCgTypeId t, u32 base, const CgType* ty = cg_type_get(a->c, t); ABITypeInfo ti; if (!ty) return 0; - if (ty->kind == KIT_CG_TYPE_ALIAS) { - return classify_range(a, ty->alias.base, base, cls); - } - if (ty->kind == KIT_CG_TYPE_SOURCE_BASE) { - return classify_range(a, ty->source_base.base, base, cls); - } if (ty->kind == KIT_CG_TYPE_ENUM) { return classify_range(a, ty->enum_.base, base, cls); } @@ -182,12 +176,6 @@ static void classify_one(TargetABI* a, KitCgTypeId t, ABIArgInfo* out, case KIT_CG_TYPE_RECORD: classify_aggregate(a, t, out, is_return); return; - case KIT_CG_TYPE_ALIAS: - classify_one(a, ty->alias.base, out, is_return); - return; - case KIT_CG_TYPE_SOURCE_BASE: - classify_one(a, ty->source_base.base, out, is_return); - return; default: classify_scalar(a, t, out, is_return); return; diff --git a/src/abi/abi_win64_x64.c b/src/abi/abi_win64_x64.c @@ -108,12 +108,6 @@ static void classify_one(TargetABI* a, KitCgTypeId t, ABIArgInfo* out, case KIT_CG_TYPE_RECORD: classify_aggregate(a, t, out, is_return); return; - case KIT_CG_TYPE_ALIAS: - classify_one(a, ty->alias.base, out, is_return); - return; - case KIT_CG_TYPE_SOURCE_BASE: - classify_one(a, ty->source_base.base, out, is_return); - return; default: classify_scalar(a, t, out, is_return); return; diff --git a/src/arch/c_target/c_emit.c b/src/arch/c_target/c_emit.c @@ -141,8 +141,7 @@ static const char* c_int_type_name_for_width(u32 width, int signed_) { * fixed-width integer (float, ptr, void, aggregate). */ static u32 c_int_width_for_signedness(CTarget* t, KitCgTypeId type) { if (type == KIT_CG_TYPE_NONE) return 0; - KitCgTypeId u = api_unalias_type(t->c, type); - const CgType* ty = cg_type_get(t->c, u); + const CgType* ty = cg_type_get(t->c, type); if (!ty) return 0; if (ty->kind == KIT_CG_TYPE_INT) return ty->integer.width; if (ty->kind == KIT_CG_TYPE_BOOL) return 32; /* bool maps to int32_t */ @@ -170,9 +169,8 @@ static void c_grow_type_state(CTarget* t, u32 needed) { } static const char* c_typedef_name(CTarget* t, KitCgTypeId tid) { - KitCgTypeId u = api_unalias_type(t->c, tid); char buf[32]; - int n = snprintf(buf, sizeof buf, "__ty_%u", (unsigned)u); + int n = snprintf(buf, sizeof buf, "__ty_%u", (unsigned)tid); Sym s = pool_intern_slice(t->c->global, (Slice){.s = buf, .len = (size_t)n}); return pool_slice(t->c->global, s).s; } @@ -182,7 +180,7 @@ static void c_emit_typedef_for_func(CTarget* t, KitCgTypeId tid, const CgType* ty); static void c_ensure_typedef(CTarget* t, KitCgTypeId tid) { - KitCgTypeId u = api_unalias_type(t->c, tid); + KitCgTypeId u = tid; if ((u32)u >= t->type_state_cap) c_grow_type_state(t, (u32)u + 1u); if (t->type_state[u] >= 2) return; if (t->type_state[u] == 1) return; /* cyclic — emit forward-only */ @@ -203,7 +201,7 @@ static void c_ensure_typedef(CTarget* t, KitCgTypeId tid) { for (u32 i = 0; i < ty->record.nfields; ++i) { if (!(ty->record.fields[i].flags & KIT_CG_FIELD_BITFIELD)) { KitCgTypeId ft = ty->record.fields[i].type; - KitCgTypeId ftu = api_unalias_type(t->c, ft); + KitCgTypeId ftu = ft; const CgType* fty = cg_type_get(t->c, ftu); if (fty && (fty->kind == KIT_CG_TYPE_RECORD || fty->kind == KIT_CG_TYPE_ARRAY || @@ -222,7 +220,7 @@ static void c_ensure_typedef(CTarget* t, KitCgTypeId tid) { break; } case KIT_CG_TYPE_ARRAY: { - KitCgTypeId eu = api_unalias_type(t->c, ty->array.elem); + KitCgTypeId eu = ty->array.elem; const CgType* ety = cg_type_get(t->c, eu); if (ety && (ety->kind == KIT_CG_TYPE_RECORD || ety->kind == KIT_CG_TYPE_ARRAY || @@ -249,7 +247,7 @@ static void c_ensure_typedef(CTarget* t, KitCgTypeId tid) { static void c_emit_typedef_for_func(CTarget* t, KitCgTypeId tid, const CgType* ty) { /* Emit recursively for return and param types if they're composites. */ - KitCgTypeId ret = api_unalias_type(t->c, cg_func_ret_type(ty)); + KitCgTypeId ret = cg_func_ret_type(ty); const CgType* rty = cg_type_get(t->c, ret); if (rty && (rty->kind == KIT_CG_TYPE_RECORD || rty->kind == KIT_CG_TYPE_ARRAY || @@ -257,7 +255,7 @@ static void c_emit_typedef_for_func(CTarget* t, KitCgTypeId tid, c_ensure_typedef(t, ret); } for (u32 i = 0; i < ty->func.nparams; ++i) { - KitCgTypeId pt = api_unalias_type(t->c, ty->func.params[i].type); + KitCgTypeId pt = ty->func.params[i].type; const CgType* pty = cg_type_get(t->c, pt); if (pty && (pty->kind == KIT_CG_TYPE_RECORD || pty->kind == KIT_CG_TYPE_ARRAY || @@ -315,7 +313,7 @@ static const char* c_float_type_name(u32 width) { * composites (records/arrays/funcs) emit an opaque-storage typedef on first * sighting and return the typedef name. */ static const char* c_typename(CTarget* t, KitCgTypeId type) { - KitCgTypeId resolved = api_unalias_type(t->c, type); + KitCgTypeId resolved = type; const CgType* ty = cg_type_get(t->c, resolved); SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; if (!ty) { @@ -416,7 +414,7 @@ static void c_grow_local_table(CTarget* t, u32 needed) { * x86-64 SysV) where `= 0` is invalid, and `= {0}` is also valid for the * pointer form (e.g. Apple), so it is the portable choice. */ static void c_emit_zero_init(CTarget* t, KitCgTypeId ty) { - const CgType* cgt = ty ? cg_type_get(t->c, api_unalias_type(t->c, ty)) : NULL; + const CgType* cgt = ty ? cg_type_get(t->c, ty) : NULL; int braced = cgt && (cgt->kind == KIT_CG_TYPE_RECORD || cgt->kind == KIT_CG_TYPE_ARRAY || cgt->kind == KIT_CG_TYPE_VARARG_STATE); @@ -431,14 +429,11 @@ void c_ensure_local(CTarget* t, CLocal r, KitCgTypeId type) { } if ((u32)r >= t->local_cap) c_grow_local_table(t, (u32)r + 1u); if (t->local_declared[r]) { - if (type && api_unalias_type(t->c, t->local_type[r]) != - api_unalias_type(t->c, type)) { + if (type && t->local_type[r] != type) { compiler_panic(t->c, t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}, "C target: local v%u used with inconsistent type " "(declared %u, used %u)", - (unsigned)r, - (unsigned)api_unalias_type(t->c, t->local_type[r]), - (unsigned)api_unalias_type(t->c, type)); + (unsigned)r, (unsigned)t->local_type[r], (unsigned)type); } return; } @@ -570,9 +565,7 @@ void c_emit_operand(CTarget* t, Operand op) { obj_sym_mark_referenced(t->obj, op.v.global.sym); const char* nm = c_sym_name(t, op.v.global.sym); const CgType* gty = - (op.type != KIT_CG_TYPE_NONE) - ? cg_type_get(t->c, api_unalias_type(t->c, op.type)) - : NULL; + (op.type != KIT_CG_TYPE_NONE) ? cg_type_get(t->c, op.type) : NULL; int is_aggregate = gty && (gty->kind == KIT_CG_TYPE_RECORD || gty->kind == KIT_CG_TYPE_ARRAY); if (is_aggregate) { @@ -612,14 +605,15 @@ void c_emit_operand(CTarget* t, Operand op) { static int c_type_is_float(CTarget* t, KitCgTypeId type) { if (type == KIT_CG_TYPE_NONE) return 0; - const CgType* ty = cg_type_get(t->c, api_unalias_type(t->c, type)); + const CgType* ty = cg_type_get(t->c, type); return ty && ty->kind == KIT_CG_TYPE_FLOAT; } -/* True iff a and b name the same CG type after alias resolution. */ +/* True iff a and b name the same CG type. */ static int c_types_equiv(CTarget* t, KitCgTypeId a, KitCgTypeId b) { + (void)t; if (a == 0 || b == 0) return 0; - return api_unalias_type(t->c, a) == api_unalias_type(t->c, b); + return a == b; } /* Emit " vN = " plus any cast needed for a C assignment expression. @@ -694,19 +688,19 @@ void c_emit_operand_signed(CTarget* t, Operand op, int signed_) { /* Returns 1 if `type` is a pointer (or void*). */ static int c_type_is_ptr(CTarget* t, KitCgTypeId type) { if (type == KIT_CG_TYPE_NONE) return 0; - const CgType* ty = cg_type_get(t->c, api_unalias_type(t->c, type)); + const CgType* ty = cg_type_get(t->c, type); return ty && ty->kind == KIT_CG_TYPE_PTR; } static int c_type_is_bool(CTarget* t, KitCgTypeId type) { if (type == KIT_CG_TYPE_NONE) return 0; - const CgType* ty = cg_type_get(t->c, api_unalias_type(t->c, type)); + const CgType* ty = cg_type_get(t->c, type); return ty && ty->kind == KIT_CG_TYPE_BOOL; } static int c_type_is_aggregate(CTarget* t, KitCgTypeId type) { if (type == KIT_CG_TYPE_NONE) return 0; - const CgType* ty = cg_type_get(t->c, api_unalias_type(t->c, type)); + const CgType* ty = cg_type_get(t->c, type); return ty && (ty->kind == KIT_CG_TYPE_RECORD || ty->kind == KIT_CG_TYPE_ARRAY); } @@ -782,9 +776,7 @@ static void c_emit_addr_deref(CTarget* t, Operand addr, case OPK_LOCAL: { c_ensure_local(t, addr.v.local, addr.type); c_local_name(addr.v.local, buf, sizeof buf); - if (access_type == 0 || addr.type == 0 || - api_unalias_type(t->c, access_type) == - api_unalias_type(t->c, addr.type)) { + if (access_type == 0 || addr.type == 0 || access_type == addr.type) { cbuf_puts(&t->body, buf); } else { cbuf_puts(&t->body, "(*("); @@ -961,7 +953,7 @@ void c_emit_prologue(CTarget* t) { static void c_emit_func_signature(CTarget* t, CBuf* b, const char* name, KitCgTypeId fn_type) { KitCgTypeId ret_type = cg_type_func_ret_id(t->c, fn_type); - const CgType* fty = cg_type_get(t->c, api_unalias_type(t->c, fn_type)); + const CgType* fty = cg_type_get(t->c, fn_type); SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; if (!fty || fty->kind != KIT_CG_TYPE_FUNC) { compiler_panic(t->c, loc, "C target: fn_type is not a function type"); @@ -1732,13 +1724,13 @@ static void c_grow_local_static_entries(CTarget* t, u32 want) { int c_emit_can_local_static_data(CTarget* t, const CGLocalStaticDataDesc* desc) { SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; - const CgType* ty = cg_type_get(t->c, api_unalias_type(t->c, desc->type)); + const CgType* ty = cg_type_get(t->c, desc->type); if (!ty) { compiler_panic(t->c, loc, "C target: unknown local static type %u", (unsigned)desc->type); } if (ty->kind == KIT_CG_TYPE_ARRAY) { - ty = cg_type_get(t->c, api_unalias_type(t->c, ty->array.elem)); + ty = cg_type_get(t->c, ty->array.elem); } return ty && ty->kind == KIT_CG_TYPE_PTR; } @@ -1754,7 +1746,7 @@ int c_emit_local_static_data_begin(CTarget* t, compiler_panic(t->c, loc, "C target: nested function-local static data definition"); } - const CgType* ty = cg_type_get(t->c, api_unalias_type(t->c, desc->type)); + const CgType* ty = cg_type_get(t->c, desc->type); if (!ty) { compiler_panic(t->c, loc, "C target: unknown local static type %u", (unsigned)desc->type); @@ -1767,7 +1759,7 @@ int c_emit_local_static_data_begin(CTarget* t, is_array = 1; count = ty->array.count; elem = ty->array.elem; - ty = cg_type_get(t->c, api_unalias_type(t->c, elem)); + ty = cg_type_get(t->c, elem); } if (!c_emit_can_local_static_data(t, desc)) { return 0; @@ -2197,13 +2189,12 @@ const char* c_emit_tail_call_unrealizable_reason(CTarget* t, const char* c_emit_tail_call_unrealizable_reason_for( CTarget* t, const CGFuncDesc* caller_fd, const CGCallDesc* d) { SrcLoc loc = caller_fd ? caller_fd->loc : (SrcLoc){0, 0, 0}; - const CgType* fty = cg_type_get(t->c, api_unalias_type(t->c, d->fn_type)); + const CgType* fty = cg_type_get(t->c, d->fn_type); if (!fty || fty->kind != KIT_CG_TYPE_FUNC) { compiler_panic(t->c, loc, "C target: tail call: bad fn_type"); } const CgType* caller = - caller_fd ? cg_type_get(t->c, api_unalias_type(t->c, caller_fd->fn_type)) - : NULL; + caller_fd ? cg_type_get(t->c, caller_fd->fn_type) : NULL; if (!caller || caller->kind != KIT_CG_TYPE_FUNC) { compiler_panic(t->c, loc, "C target: tail call outside function"); } @@ -2224,7 +2215,7 @@ const char* c_emit_tail_call_unrealizable_reason_for( void c_emit_call(CTarget* t, const CGCallDesc* d) { SrcLoc loc = t->cur_fn ? t->cur_fn->loc : (SrcLoc){0, 0, 0}; - const CgType* fty = cg_type_get(t->c, api_unalias_type(t->c, d->fn_type)); + const CgType* fty = cg_type_get(t->c, d->fn_type); if (!fty || fty->kind != KIT_CG_TYPE_FUNC) { compiler_panic(t->c, loc, "C target: call: bad fn_type"); } @@ -2312,8 +2303,7 @@ void c_emit_ret(CTarget* t, CGLocal value) { if (value != CG_LOCAL_NONE) { cbuf_puts(&t->body, " "); KitCgTypeId ret_type = t->cur_fn ? t->cur_fn->result_type : (KitCgTypeId)0; - const CgType* rty = - ret_type ? cg_type_get(t->c, api_unalias_type(t->c, ret_type)) : NULL; + const CgType* rty = ret_type ? cg_type_get(t->c, ret_type) : NULL; int is_aggregate = rty && (rty->kind == KIT_CG_TYPE_RECORD || rty->kind == KIT_CG_TYPE_ARRAY); if (ret_type && !is_aggregate) { @@ -2357,7 +2347,7 @@ void c_emit_alias(CTarget* t, ObjSymId alias_sym, ObjSymId target_sym, if (c_sym_forwarded_test_and_set(t, alias_sym)) return; const char* alias_name = c_sym_name(t, alias_sym); const char* target_name = c_sym_name(t, target_sym); - const CgType* fty = cg_type_get(t->c, api_unalias_type(t->c, type)); + const CgType* fty = cg_type_get(t->c, type); int is_func = fty && fty->kind == KIT_CG_TYPE_FUNC; const ObjFormatImpl* fmt = obj_format_lookup(t->c->target.obj); @@ -2719,7 +2709,7 @@ void c_emit_va_start(CTarget* t, Operand ap_addr) { const CGFuncDesc* fd = t->cur_fn; SrcLoc loc = fd ? fd->loc : (SrcLoc){0, 0, 0}; if (!fd) compiler_panic(t->c, loc, "C target: va_start outside function"); - const CgType* fty = cg_type_get(t->c, api_unalias_type(t->c, fd->fn_type)); + const CgType* fty = cg_type_get(t->c, fd->fn_type); if (!fty || fty->kind != KIT_CG_TYPE_FUNC || fty->func.nparams == 0) { compiler_panic(t->c, loc, "C target: va_start in non-variadic function shape"); diff --git a/src/arch/wasm/abi.c b/src/arch/wasm/abi.c @@ -113,12 +113,6 @@ static void classify_one(TargetABI* a, KitCgTypeId t, ABIArgInfo* out, * the classifier, route indirect. */ classify_aggregate(a, t, out, is_return); return; - case KIT_CG_TYPE_ALIAS: - classify_one(a, ty->alias.base, out, is_return); - return; - case KIT_CG_TYPE_SOURCE_BASE: - classify_one(a, ty->source_base.base, out, is_return); - return; default: classify_scalar(a, t, out); return; diff --git a/src/cg/arith.c b/src/cg/arith.c @@ -274,14 +274,12 @@ void api_cg_convert_kind(KitCg* g, KitCgTypeId dst_type, ConvKind ck) { Operand dst; if (!g) return; T = g->target; - /* api_unalias_type already validates (returns NONE for a bad id), so it - * subsumes the standalone resolve_type that preceded it. Keep the - * return-before-pop order on an invalid dst_type. */ - dty = api_unalias_type(g->c, dst_type); + /* Keep the return-before-pop order on an invalid dst_type. */ + dty = resolve_type(g->c, dst_type); if (!dty) return; in_const = api_const_at(g, 0); v = api_pop(g); - sty = api_unalias_type(g->c, v.type ? v.type : v.op.type); + sty = resolve_type(g->c, v.type ? v.type : v.op.type); if (!sty) { api_release(g, &v); return; @@ -451,7 +449,7 @@ static int api_binop_is_shift(BinOp iop) { } static int api_is_bool_type(Compiler* c, KitCgTypeId ty) { - const CgType* cg = cg_type_get(c, api_unalias_type(c, ty)); + const CgType* cg = cg_type_get(c, ty); return cg && cg->kind == KIT_CG_TYPE_BOOL; } @@ -1014,7 +1012,7 @@ int api_try_wide8_convert(KitCg* g, ConvKind ck, KitCgTypeId sty, ApiSValue res_lv; Operand ar; Operand hival; - if (api_unalias_type(g->c, sty) != i32) { + if (sty != i32) { api_push(g, *v); api_cg_convert_kind(g, i32, ck == CV_SEXT ? CV_SEXT : CV_ZEXT); *v = api_pop(g); @@ -1049,8 +1047,7 @@ int api_try_wide8_convert(KitCg* g, ConvKind ck, KitCgTypeId sty, Operand lolane = api_wide8_load_lane(g, addr, lo); api_release(g, v); api_push(g, api_make_sv(lolane, i32)); - if (api_unalias_type(g->c, dty) != i32) - api_cg_convert_kind(g, dty, CV_TRUNC); + if (dty != i32) api_cg_convert_kind(g, dty, CV_TRUNC); return 1; } } @@ -1670,7 +1667,7 @@ void kit_cg_fpext(KitCg* g, KitCgTypeId dst) { } if (api_is_f128_type(g->c, dty)) { ApiSValue v = api_pop(g); - KitCgTypeId sty = api_unalias_type(g->c, api_sv_type(&v)); + KitCgTypeId sty = api_sv_type(&v); const char* name = sty == builtin_id(KIT_CG_BUILTIN_F32) ? "__extendsftf2" : "__extenddftf2"; api_push(g, v); @@ -1680,7 +1677,7 @@ void kit_cg_fpext(KitCg* g, KitCgTypeId dst) { /* float -> soft double: runtime widen via __extendsfdf2. */ if (api_type_is_soft_double(g, dty)) { ApiSValue v = api_pop(g); - KitCgTypeId sty = api_unalias_type(g->c, api_sv_type(&v)); + KitCgTypeId sty = api_sv_type(&v); api_push(g, v); api_f128_call_unary(g, "__extendsfdf2", dty, sty); return; @@ -1710,7 +1707,7 @@ void kit_cg_fptrunc(KitCg* g, KitCgTypeId dst) { /* soft double -> float: runtime narrow via __truncdfsf2. */ if (api_soft_double_stack_top(g, 0)) { ApiSValue v = api_pop(g); - KitCgTypeId sty = api_unalias_type(g->c, api_sv_type(&v)); + KitCgTypeId sty = api_sv_type(&v); api_push(g, v); api_f128_call_unary(g, "__truncdfsf2", dty, sty); return; @@ -1778,7 +1775,7 @@ void kit_cg_sint_to_float(KitCg* g, KitCgTypeId dst, KitCgRounding rounding) { } if (api_is_f128_type(g->c, dst)) { ApiSValue v = api_pop(g); - KitCgTypeId sty = api_unalias_type(g->c, api_sv_type(&v)); + KitCgTypeId sty = api_sv_type(&v); u32 sz = (u32)abi_cg_sizeof(g->c->abi, sty); char name[16]; api_fp_conv_name(name, sizeof name, API_FPCONV_SINT_TO_FLOAT, "tf", sz); @@ -1789,7 +1786,7 @@ void kit_cg_sint_to_float(KitCg* g, KitCgTypeId dst, KitCgRounding rounding) { /* signed int -> soft double: __floatsidf (i32) / __floatdidf (i64). */ if (api_type_is_soft_double(g, dst)) { ApiSValue v = api_pop(g); - KitCgTypeId sty = api_unalias_type(g->c, api_sv_type(&v)); + KitCgTypeId sty = api_sv_type(&v); u32 sz = (u32)abi_cg_sizeof(g->c->abi, sty); char name[16]; api_fp_conv_name(name, sizeof name, API_FPCONV_SINT_TO_FLOAT, "df", sz); @@ -1818,7 +1815,7 @@ void kit_cg_uint_to_float(KitCg* g, KitCgTypeId dst, KitCgRounding rounding) { } if (api_is_f128_type(g->c, dst)) { ApiSValue v = api_pop(g); - KitCgTypeId sty = api_unalias_type(g->c, api_sv_type(&v)); + KitCgTypeId sty = api_sv_type(&v); u32 sz = (u32)abi_cg_sizeof(g->c->abi, sty); char name[16]; api_fp_conv_name(name, sizeof name, API_FPCONV_UINT_TO_FLOAT, "tf", sz); @@ -1829,7 +1826,7 @@ void kit_cg_uint_to_float(KitCg* g, KitCgTypeId dst, KitCgRounding rounding) { /* unsigned int -> soft double: __floatunsidf (i32) / __floatundidf (i64). */ if (api_type_is_soft_double(g, dst)) { ApiSValue v = api_pop(g); - KitCgTypeId sty = api_unalias_type(g->c, api_sv_type(&v)); + KitCgTypeId sty = api_sv_type(&v); u32 sz = (u32)abi_cg_sizeof(g->c->abi, sty); char name[16]; api_fp_conv_name(name, sizeof name, API_FPCONV_UINT_TO_FLOAT, "df", sz); @@ -2121,7 +2118,7 @@ void kit_cg_intrinsic(KitCg* g, KitCgIntrinsic intrin, uint32_t nargs, ApiSValue arg = api_pop(g); KitCgTypeId ps[1] = {i64}; api_runtime_call_values(g, name, ret, ps, 1, &arg); - if (ret == i32 && api_unalias_type(g->c, result_type) != i32) + if (ret == i32 && result_type != i32) api_cg_convert_kind(g, result_type, CV_ZEXT); return; } diff --git a/src/cg/call.c b/src/cg/call.c @@ -1,7 +1,7 @@ #include "cg/internal.h" static u32 api_func_nparams(KitCg* g, KitCgTypeId fty) { - const CgType* ty = cg_type_get(g->c, api_unalias_type(g->c, fty)); + const CgType* ty = cg_type_get(g->c, fty); if (!ty || ty->kind != KIT_CG_TYPE_FUNC) return 0; return ty->func.nparams; } @@ -17,8 +17,7 @@ static CGLocal api_materialize_call_local(KitCg* g, ApiSValue* arg, KitCgTypeId ty) { if (cg_type_is_aggregate(g->c, ty)) { if (api_is_lvalue_sv(arg) && arg->op.kind == OPK_LOCAL) { - if (api_unalias_type(g->c, arg->op.type) == api_unalias_type(g->c, ty)) - return arg->op.v.local; + if (arg->op.type == ty) return arg->op.v.local; } CGLocal r = api_alloc_temp_local(g, ty); Operand dst = api_op_local(r, ty); @@ -54,8 +53,7 @@ static CGLocal api_materialize_call_local(KitCg* g, ApiSValue* arg, *arg = api_make_wide8_int_const(g, arg->op.v.imm, ty); } op = api_force_local_unless_imm(g, arg, src_ty); - if (op.kind == OPK_LOCAL && - api_unalias_type(g->c, op.type) == api_unalias_type(g->c, ty)) { + if (op.kind == OPK_LOCAL && op.type == ty) { return op.v.local; } @@ -140,8 +138,7 @@ static void api_call_clobber_boundary(KitCg* g, const CGCallDesc* d) { static int api_tail_ret_compatible(KitCg* g, KitCgTypeId callee_fn_type) { KitCgTypeId cr = cg_type_func_result_id(g->c, callee_fn_type); - return api_unalias_type(g->c, g->fn_desc.result_type) == - api_unalias_type(g->c, cr); + return g->fn_desc.result_type == cr; } static int api_tail_decide(KitCg* g, const CGCallDesc* desc, diff --git a/src/cg/debug.c b/src/cg/debug.c @@ -1,10 +1,9 @@ #include "cg/internal.h" -/* Map the public source-base encoding onto the DWARF producer's base-type - * encoding. KitCgDebugEncoding deliberately mirrors the DEBUG_BE_* set the - * frontends care about; NONE has no DWARF spelling, so fall back to signed. */ -static DebugBaseEncoding debug_base_encoding(u8 enc) { - switch ((KitCgDebugEncoding)enc) { +/* Map the public debug encoding onto the DWARF producer's base-type encoding. + * NONE has no DWARF spelling, so fall back to signed. */ +static DebugBaseEncoding debug_base_encoding(KitCgDebugEncoding enc) { + switch (enc) { case KIT_CG_DEBUG_ENC_BOOL: return DEBUG_BE_BOOL; case KIT_CG_DEBUG_ENC_UNSIGNED: @@ -22,7 +21,60 @@ static DebugBaseEncoding debug_base_encoding(u8 enc) { return DEBUG_BE_SIGNED; } -DebugTypeId api_debug_type(KitCg* g, KitCgTypeId id) { +KitCgDebugType kit_cg_debug_base(KitCg* g, KitSym name, KitCgDebugEncoding enc, + uint32_t bytes) { + if (!g || !g->debug || !name) return KIT_CG_DEBUG_TYPE_NONE; + return (KitCgDebugType)debug_type_base(g->debug, (Sym)name, + debug_base_encoding(enc), bytes); +} + +KitCgDebugType kit_cg_debug_typedef(KitCg* g, KitSym name, + KitCgDebugType base) { + if (!g || !g->debug || !name) return KIT_CG_DEBUG_TYPE_NONE; + if (base == KIT_CG_DEBUG_TYPE_NONE) base = debug_type_void(g->debug); + return (KitCgDebugType)debug_type_typedef(g->debug, (Sym)name, + (DebugTypeId)base); +} + +KitCgDebugType kit_cg_debug_ptr(KitCg* g, KitCgDebugType pointee) { + if (!g || !g->debug) return KIT_CG_DEBUG_TYPE_NONE; + if (pointee == KIT_CG_DEBUG_TYPE_NONE) pointee = debug_type_void(g->debug); + return (KitCgDebugType)debug_type_ptr(g->debug, (DebugTypeId)pointee); +} + +KitCgDebugType kit_cg_debug_array(KitCg* g, KitCgDebugType elem, + uint64_t count) { + u32 n; + if (!g || !g->debug) return KIT_CG_DEBUG_TYPE_NONE; + if (elem == KIT_CG_DEBUG_TYPE_NONE) elem = debug_type_void(g->debug); + n = count > UINT32_MAX ? 0u : (u32)count; + return (KitCgDebugType)debug_type_array(g->debug, (DebugTypeId)elem, n); +} + +KitCgDebugType kit_cg_debug_func(KitCg* g, KitCgDebugType ret, + const KitCgDebugType* params, uint32_t nparams, + int variadic) { + Heap* h = NULL; + DebugTypeId* tmp = NULL; + DebugTypeId out; + if (!g || !g->debug || (nparams && !params)) return KIT_CG_DEBUG_TYPE_NONE; + if (ret == KIT_CG_DEBUG_TYPE_NONE) ret = debug_type_void(g->debug); + if (nparams) { + h = (Heap*)g->c->ctx->heap; + tmp = (DebugTypeId*)h->alloc(h, sizeof(*tmp) * nparams, + _Alignof(DebugTypeId)); + if (!tmp) return KIT_CG_DEBUG_TYPE_NONE; + for (u32 i = 0; i < nparams; ++i) { + tmp[i] = params[i] == KIT_CG_DEBUG_TYPE_NONE ? debug_type_void(g->debug) + : (DebugTypeId)params[i]; + } + } + out = debug_type_func(g->debug, (DebugTypeId)ret, tmp, nparams, variadic); + if (tmp) h->free(h, tmp, sizeof(*tmp) * nparams); + return (KitCgDebugType)out; +} + +static DebugTypeId api_debug_of_type(KitCg* g, KitCgTypeId id) { const CgType* ty; if (!g || !g->debug) return DEBUG_TYPE_NONE; ty = cg_type_get(g->c, id); @@ -53,12 +105,12 @@ DebugTypeId api_debug_type(KitCg* g, KitCgTypeId id) { DEBUG_BE_FLOAT, (u32)((ty->fp.width + 7u) / 8u)); } case KIT_CG_TYPE_PTR: { - DebugTypeId pointee = api_debug_type(g, ty->ptr.pointee); + DebugTypeId pointee = api_debug_of_type(g, ty->ptr.pointee); if (pointee == DEBUG_TYPE_NONE) pointee = debug_type_void(g->debug); return debug_type_ptr(g->debug, pointee); } case KIT_CG_TYPE_ARRAY: { - DebugTypeId elem = api_debug_type(g, ty->array.elem); + DebugTypeId elem = api_debug_of_type(g, ty->array.elem); u32 count = ty->array.count > UINT32_MAX ? 0u : (u32)ty->array.count; if (elem == DEBUG_TYPE_NONE) elem = debug_type_void(g->debug); return debug_type_array(g->debug, elem, count); @@ -66,7 +118,7 @@ DebugTypeId api_debug_type(KitCg* g, KitCgTypeId id) { case KIT_CG_TYPE_FUNC: { Heap* h = (Heap*)g->c->ctx->heap; DebugTypeId ret = ty->func.result.type - ? api_debug_type(g, ty->func.result.type) + ? api_debug_of_type(g, ty->func.result.type) : DEBUG_TYPE_NONE; DebugTypeId* params = NULL; DebugTypeId fn; @@ -76,7 +128,7 @@ DebugTypeId api_debug_type(KitCg* g, KitCgTypeId id) { _Alignof(DebugTypeId)); if (!params) return DEBUG_TYPE_NONE; for (u32 i = 0; i < ty->func.nparams; ++i) { - params[i] = api_debug_type(g, ty->func.params[i].type); + params[i] = api_debug_of_type(g, ty->func.params[i].type); if (params[i] == DEBUG_TYPE_NONE) params[i] = debug_type_void(g->debug); } @@ -94,9 +146,9 @@ DebugTypeId api_debug_type(KitCg* g, KitCgTypeId id) { return debug_type_record_end(b); } case KIT_CG_TYPE_ENUM: { - DebugTypeId base = api_debug_type(g, ty->enum_.base); - DebugEnumBuilder* eb = debug_type_enum_begin(g->debug, - (Sym)ty->enum_.tag, base); + DebugTypeId base = api_debug_of_type(g, ty->enum_.base); + DebugEnumBuilder* eb = + debug_type_enum_begin(g->debug, (Sym)ty->enum_.tag, base); if (!eb) return DEBUG_TYPE_NONE; for (u32 i = 0; i < ty->enum_.nvalues; ++i) { debug_type_enum_value(eb, (Sym)ty->enum_.values[i].name, @@ -104,19 +156,39 @@ DebugTypeId api_debug_type(KitCg* g, KitCgTypeId id) { } return debug_type_enum_end(eb); } - case KIT_CG_TYPE_ALIAS: { - DebugTypeId base = api_debug_type(g, ty->alias.base); - if (base == DEBUG_TYPE_NONE) base = debug_type_void(g->debug); - return debug_type_typedef(g->debug, (Sym)ty->alias.name, base); - } - case KIT_CG_TYPE_SOURCE_BASE: - return debug_type_base(g->debug, (Sym)ty->source_base.name, - debug_base_encoding(ty->source_base.encoding), - ty->size ? (u32)ty->size : 1u); case KIT_CG_TYPE_VARARG_STATE: return debug_type_void(g->debug); } return DEBUG_TYPE_NONE; } +KitCgDebugType kit_cg_debug_enum(KitCg* g, KitCgTypeId enum_type, + KitCgDebugType base) { + const CgType* ty; + DebugEnumBuilder* eb; + if (!g || !g->debug) return KIT_CG_DEBUG_TYPE_NONE; + ty = cg_type_get(g->c, enum_type); + if (!ty || ty->kind != KIT_CG_TYPE_ENUM) return KIT_CG_DEBUG_TYPE_NONE; + if (base == KIT_CG_DEBUG_TYPE_NONE) + base = api_debug_of_type(g, ty->enum_.base); + eb = debug_type_enum_begin(g->debug, (Sym)ty->enum_.tag, (DebugTypeId)base); + if (!eb) return KIT_CG_DEBUG_TYPE_NONE; + for (u32 i = 0; i < ty->enum_.nvalues; ++i) { + debug_type_enum_value(eb, (Sym)ty->enum_.values[i].name, + (i64)ty->enum_.values[i].value); + } + return (KitCgDebugType)debug_type_enum_end(eb); +} + +KitCgDebugType kit_cg_debug_of_type(KitCg* g, KitCgTypeId id) { + return (KitCgDebugType)api_debug_of_type(g, id); +} + +DebugTypeId api_debug_type(KitCg* g, KitCgDebugType debug_type, + KitCgTypeId fallback_type) { + if (!g || !g->debug) return DEBUG_TYPE_NONE; + if (debug_type != KIT_CG_DEBUG_TYPE_NONE) return (DebugTypeId)debug_type; + return api_debug_of_type(g, fallback_type); +} + /* ---- value stack helpers ---- */ diff --git a/src/cg/fold.c b/src/cg/fold.c @@ -54,10 +54,6 @@ void api_delayed_reset(KitCg* g) { u32 api_int_like_width(Compiler* c, KitCgTypeId id) { const CgType* ty = cg_type_get(c, id); if (!ty) return 0; - if (ty->kind == KIT_CG_TYPE_ALIAS) - return api_int_like_width(c, ty->alias.base); - if (ty->kind == KIT_CG_TYPE_SOURCE_BASE) - return api_int_like_width(c, ty->source_base.base); if (ty->kind == KIT_CG_TYPE_INT || ty->kind == KIT_CG_TYPE_BOOL) return ty->integer.width; if (ty->kind == KIT_CG_TYPE_ENUM) return (u32)(ty->size * 8u); @@ -68,9 +64,6 @@ u32 api_int_like_width(Compiler* c, KitCgTypeId id) { int api_type_is_bool(Compiler* c, KitCgTypeId id) { const CgType* ty = cg_type_get(c, id); if (!ty) return 0; - if (ty->kind == KIT_CG_TYPE_ALIAS) return api_type_is_bool(c, ty->alias.base); - if (ty->kind == KIT_CG_TYPE_SOURCE_BASE) - return api_type_is_bool(c, ty->source_base.base); return ty->kind == KIT_CG_TYPE_BOOL; } diff --git a/src/cg/internal.h b/src/cg/internal.h @@ -488,7 +488,8 @@ void kit_cg_data_symdiff(KitCg* g, KitCgSym lhs, KitCgSym rhs, int64_t addend, uint32_t width); void kit_cg_data_end(KitCg* g); ObjSymId api_emit_label_table(KitCg* g, const Label* labels, u32 n); -DebugTypeId api_debug_type(KitCg* g, KitCgTypeId id); +DebugTypeId api_debug_type(KitCg* g, KitCgDebugType debug_type, + KitCgTypeId fallback_type); int api_local_requires_memory(KitCg* g, KitCgTypeId ty, KitCgLocalAttrs attrs); KitCgLocal api_local_handle(u32 index); int api_grow_locals(KitCg* g, u32 want); diff --git a/src/cg/memory.c b/src/cg/memory.c @@ -353,8 +353,7 @@ void kit_cg_load(KitCg* g, KitCgMemAccess access) { /* Scalar local place: the value already lives in the local; hand it back * directly without a memory access. Decode each id's predicate bitset once - * (api_type_pred_bits also warms the entry's unalias cache), then read the - * aggregate bit and the unalias terminal locally instead of re-decoding. */ + * and compare exact operational ids. */ if (!is_bitfield && base.source_local != KIT_CG_LOCAL_NONE && base.op.kind == OPK_LOCAL && !api_sv_local_storage_is_aggregate(g, &base)) { @@ -362,7 +361,7 @@ void kit_cg_load(KitCg* g, KitCgMemAccess access) { u8 base_bits = api_type_pred_bits(g->c, base_ty); u8 ty_bits = api_type_pred_bits(g->c, ty); if (!(base_bits & API_PRED_AGGREGATE) && !(ty_bits & API_PRED_AGGREGATE) && - api_unalias_type(g->c, base_ty) == api_unalias_type(g->c, ty)) { + base_ty == ty) { api_sv_set_lvalue(&base, 0); api_sv_set_res(&base, RES_FIXED_LOCAL); api_push(g, base); @@ -589,8 +588,8 @@ static void api_cg_store_impl(KitCg* g, KitCgMemAccess access, /* Does this store land a scalar value straight into a local's own storage * (a plain `x = <expr>` / `int x = <expr>`, not * bit-field/aggregate/indirect)? Single-decode: `ty`'s aggregate bit was - * already taken (ty_is_agg); decode base's id once for both its aggregate bit - * and its unalias terminal. */ + * already taken (ty_is_agg); decode base's id once for its aggregate bit and + * compare exact operational ids. */ int scalar_local_place = !is_bitfield && base.source_local != KIT_CG_LOCAL_NONE && base.op.kind == OPK_LOCAL && @@ -598,9 +597,7 @@ static void api_cg_store_impl(KitCg* g, KitCgMemAccess access, if (scalar_local_place) { KitCgTypeId base_ty = api_sv_type(&base); u8 base_bits = api_type_pred_bits(g->c, base_ty); - scalar_local_place = - !(base_bits & API_PRED_AGGREGATE) && - api_unalias_type(g->c, base_ty) == api_unalias_type(g->c, ty); + scalar_local_place = !(base_bits & API_PRED_AGGREGATE) && base_ty == ty; } /* A still-delayed arith/cmp value going into a scalar local: emit the op diff --git a/src/cg/session.c b/src/cg/session.c @@ -424,7 +424,10 @@ void kit_cg_func_begin_attrs(KitCg* g, KitCgSym cg_sym, api_delayed_reset(g); if (g->debug) { - DebugTypeId dt = api_debug_type(g, fty); + KitCgDebugType supplied_dt = begin_attrs.debug_type + ? begin_attrs.debug_type + : attrs.as.func.debug_type; + DebugTypeId dt = api_debug_type(g, supplied_dt, fty); if (dt != DEBUG_TYPE_NONE) debug_func_begin(g->debug, sym, dt, g->cur_loc); } T->func_begin(T, &g->fn_desc); @@ -475,7 +478,7 @@ static void api_debug_emit_source_locals(KitCg* g) { memset(&cg_loc, 0, sizeof cg_loc); if (!g->target->local_debug_loc(g->target, rec->storage, &cg_loc)) continue; if (!api_debug_var_loc_from_cg(cg_loc, &dbg_loc)) continue; - dbg_type = api_debug_type(g, rec->type); + dbg_type = api_debug_type(g, rec->attrs.debug_type, rec->type); if (dbg_type == DEBUG_TYPE_NONE) continue; if (rec->kind == API_SOURCE_LOCAL_PARAM) { debug_param(g->debug, (Sym)rec->name, dbg_type, rec->loc, diff --git a/src/cg/type.c b/src/cg/type.c @@ -19,7 +19,7 @@ typedef struct CgApiType { u32 flags; u32 address_space; u64 array_count; - const KitCgField* fields; + const KitCgFieldDesc* fields; const KitCgEnumValue* values; const KitCgFuncParam* params; KitCgFuncResult result; /* void builtin means no value */ @@ -34,12 +34,10 @@ typedef struct CgApiType { u8 abi_scalar_kind; u8 abi_signed; 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, 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. */ + /* Lazily-filled flat predicate descriptor. Extends the cached_class + * mechanism: pred_bits is a bitset of API_PRED_* computed on the exact + * operational type, and pred_valid distinguishes a computed all-zero set from + * unfilled. */ u8 pred_bits; u8 pred_valid; u32 abi_size; @@ -214,21 +212,18 @@ static u8 api_pred_bits_for_kind(const CgType* ty); int api_type_is_float(Compiler* c, KitCgTypeId ty) { const CgType* cg; - ty = api_unalias_type(c, ty); cg = cg_type_get(c, ty); return cg && cg->kind == KIT_CG_TYPE_FLOAT; } int api_is_f128_type(Compiler* c, KitCgTypeId ty) { const CgType* cg; - ty = api_unalias_type(c, ty); cg = cg_type_get(c, ty); return cg && cg->kind == KIT_CG_TYPE_FLOAT && cg->fp.width == 128; } int api_is_i128_type(Compiler* c, KitCgTypeId ty) { const CgType* cg; - ty = api_unalias_type(c, ty); cg = cg_type_get(c, ty); return cg && cg->kind == KIT_CG_TYPE_INT && cg->integer.width == 128; } @@ -302,8 +297,8 @@ static void cg_api_init_builtins(Compiler* c, CgApiState* s) { * 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]); - /* Stable identity view for kit_cg_type_view. Builtins are never aliases, so - * storage_id == id; layout/complete/sized are left to kit_cg_type_info. */ + /* Stable identity view for kit_cg_type_view. storage_id == id; + * layout/complete/sized are left to kit_cg_type_info. */ s->builtin_info[i].id = builtin_id((KitCgBuiltinType)i); s->builtin_info[i].storage_id = s->builtin_info[i].id; s->builtin_info[i].kind = s->builtins[i].kind; @@ -439,8 +434,8 @@ u8 api_type_pred_bits(Compiler* c, KitCgTypeId id) { CgApiType* e; if (id == KIT_CG_TYPE_NONE) return 0; if (id <= KIT_CG_BUILTIN_COUNT) { - /* Builtins are never aliases; their predicate bitset is precomputed at - * init, so this is one indexed load (no cg_type_get + re-classify). */ + /* Builtin predicate bitsets are precomputed at init, so this is one indexed + * load (no cg_type_get + re-classify). */ u32 off = id - 1u; 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]; @@ -449,10 +444,7 @@ u8 api_type_pred_bits(Compiler* c, KitCgTypeId id) { e = api_type_from_id(c, id); if (!e) return 0; if (!e->pred_valid) { - /* Classify on the unaliased terminal — the legacy predicates recurse - * through KIT_CG_TYPE_ALIAS before testing the kind. */ - KitCgTypeId u = api_unalias_type(c, id); - e->pred_bits = api_pred_bits_for_kind(cg_type_get(c, u)); + e->pred_bits = api_pred_bits_for_kind(cg_type_get(c, id)); e->pred_valid = 1; } return e->pred_bits; @@ -494,15 +486,11 @@ KitCgTypeId cg_type_ptr_to(Compiler* c, KitCgTypeId pointee) { KitCgTypeId cg_type_pointee(Compiler* c, KitCgTypeId id) { const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == KIT_CG_TYPE_ALIAS) - return cg_type_pointee(c, ty->alias.base); return ty && ty->kind == KIT_CG_TYPE_PTR ? ty->ptr.pointee : KIT_CG_TYPE_NONE; } KitCgTypeId cg_type_func_ret_id(Compiler* c, KitCgTypeId id) { const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == KIT_CG_TYPE_ALIAS) - return cg_type_func_ret_id(c, ty->alias.base); if (!ty || ty->kind != KIT_CG_TYPE_FUNC) return KIT_CG_TYPE_NONE; return ty->func.result.type; } @@ -513,16 +501,12 @@ KitCgTypeId cg_func_ret_type(const CgType* fnty) { KitCgTypeId cg_type_func_result_id(Compiler* c, KitCgTypeId id) { const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == KIT_CG_TYPE_ALIAS) - return cg_type_func_result_id(c, ty->alias.base); if (!ty || ty->kind != KIT_CG_TYPE_FUNC) return KIT_CG_TYPE_NONE; return ty->func.result.type; } KitCgTypeId cg_type_func_param_id(Compiler* c, KitCgTypeId id, u32 index) { const CgType* ty = cg_type_get(c, id); - if (ty && ty->kind == KIT_CG_TYPE_ALIAS) - return cg_type_func_param_id(c, ty->alias.base, index); if (!ty || ty->kind != KIT_CG_TYPE_FUNC || index >= ty->func.nparams) return KIT_CG_TYPE_NONE; return ty->func.params[index].type; @@ -646,25 +630,16 @@ 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). */ +/* Fill an entry's identity prefix (the kit/cg.h KitCgTypeInfo) once. 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; + (void)c; 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) + if (e->cg.kind == KIT_CG_TYPE_RECORD || e->cg.kind == KIT_CG_TYPE_ENUM) 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; + e->info.storage_id = id; } /* The CgApiType for a user id with its identity prefix filled, or NULL. */ @@ -675,18 +650,6 @@ static CgApiType* api_type_entry_filled(Compiler* c, KitCgTypeId id) { return e; } -KitCgTypeId api_unalias_type(Compiler* c, KitCgTypeId id) { - const CgType* ty; - 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_entry_filled(c, id); - return e ? e->info.storage_id : KIT_CG_TYPE_NONE; -} - static KitCgFuncParam* copy_cg_params(Compiler* c, const KitCgFuncParam* src, u32 n) { KitCgFuncParam* dst; @@ -698,7 +661,8 @@ static KitCgFuncParam* copy_cg_params(Compiler* c, const KitCgFuncParam* src, return dst; } -static CgTypeField* copy_cg_fields(Compiler* c, const KitCgField* src, u32 n) { +static CgTypeField* copy_cg_fields(Compiler* c, const KitCgFieldDesc* src, + u32 n) { CgTypeField* dst; if (!n) return NULL; if (!src) return NULL; @@ -726,8 +690,6 @@ static int cg_type_complete_id(Compiler* c, KitCgTypeId id) { const CgType* ty = cg_type_get(c, id); if (!ty) return 0; switch (ty->kind) { - case KIT_CG_TYPE_ALIAS: - return cg_type_complete_id(c, ty->alias.base); case KIT_CG_TYPE_ARRAY: return cg_type_complete_id(c, ty->array.elem); case KIT_CG_TYPE_RECORD: @@ -740,7 +702,6 @@ static int cg_type_complete_id(Compiler* c, KitCgTypeId id) { static int cg_type_sized_id(Compiler* c, KitCgTypeId id) { ABITypeInfo ti; const CgType* ty; - id = api_unalias_type(c, id); ty = cg_type_get(c, id); if (!ty) return 0; switch (ty->kind) { @@ -762,7 +723,7 @@ static int cg_type_sized_id(Compiler* c, KitCgTypeId id) { } static int cg_type_valid_by_value(Compiler* c, KitCgTypeId id) { - const CgType* ty = cg_type_get(c, api_unalias_type(c, id)); + const CgType* ty = cg_type_get(c, id); if (!ty) return 0; if (ty->kind == KIT_CG_TYPE_VOID || ty->kind == KIT_CG_TYPE_FUNC) return 0; return cg_type_sized_id(c, id); @@ -771,7 +732,6 @@ static int cg_type_valid_by_value(Compiler* c, KitCgTypeId id) { static int cg_type_contains_by_value(Compiler* c, KitCgTypeId id, KitCgTypeId needle) { const CgType* ty; - id = api_unalias_type(c, id); if (!id) return 0; if (id == needle) return 1; ty = cg_type_get(c, id); @@ -913,46 +873,8 @@ static int cg_type_set_array(Compiler* c, CgApiType* e, KitCgTypeId elem, return 1; } -static int cg_type_set_alias(Compiler* c, CgApiType* e, KitSym name, - KitCgTypeId base) { - const CgType* bty = cg_type_get(c, base); - ABITypeInfo ti; - if (!bty) return 0; - ti = abi_cg_type_info(c->abi, base); - memset(&e->cg, 0, sizeof(e->cg)); - e->cg.kind = KIT_CG_TYPE_ALIAS; - e->cg.size = ti.size; - e->cg.align = ti.align; - e->cg.alias.name = name; - e->cg.alias.base = base; - return 1; -} - -/* A source-base wraps a scalar storage builtin (bool/int/float) with a source - * spelling + debug encoding. It mirrors the builtin's size/align so width/size - * queries answer directly, and (like an alias) unaliases to the builtin for all - * storage/ABI/codegen. */ -static int cg_type_set_source_base(Compiler* c, CgApiType* e, KitSym name, - KitCgTypeId base, u8 encoding) { - const CgType* bty = cg_type_get(c, base); - ABITypeInfo ti; - if (!bty || !(bty->kind == KIT_CG_TYPE_INT || bty->kind == KIT_CG_TYPE_BOOL || - bty->kind == KIT_CG_TYPE_FLOAT)) { - return 0; - } - ti = abi_cg_type_info(c->abi, base); - memset(&e->cg, 0, sizeof(e->cg)); - e->cg.kind = KIT_CG_TYPE_SOURCE_BASE; - e->cg.size = ti.size; - e->cg.align = ti.align; - e->cg.source_base.name = name; - e->cg.source_base.base = base; - e->cg.source_base.encoding = encoding; - return 1; -} - static int cg_type_set_record(Compiler* c, CgApiType* e, KitSym tag, - const KitCgField* fields, u32 nfields, + const KitCgFieldDesc* fields, u32 nfields, int is_union, u32 align_override, u32 flags) { CgTypeField* copied = copy_cg_fields(c, fields, nfields); if (nfields && !copied) return 0; @@ -973,10 +895,7 @@ static int cg_type_set_enum(Compiler* c, CgApiType* e, KitSym tag, const CgType* sty; ABITypeInfo ti; if (base == KIT_CG_TYPE_NONE) base = builtin_id(KIT_CG_BUILTIN_I32); - /* The base may be a source-base spelling (e.g. an `enum E : unsigned int`) - * or an alias; validate the underlying storage kind but keep the exact base - * id so debug emits the spelled underlying type. */ - sty = cg_type_get(c, api_unalias_type(c, base)); + sty = cg_type_get(c, base); if (!sty || !(sty->kind == KIT_CG_TYPE_INT || sty->kind == KIT_CG_TYPE_BOOL)) { return 0; @@ -1057,35 +976,6 @@ KitCgTypeId kit_cg_type_array(KitCompiler* c, KitCgTypeId elem, return id; } -KitCgTypeId kit_cg_type_alias(KitCompiler* c, KitSym name, KitCgTypeId base) { - KitCgTypeId id; - CgApiType* e; - if (!cg_type_get(c, base)) return KIT_CG_TYPE_NONE; - e = type_alloc(c, &id); - if (!e) return KIT_CG_TYPE_NONE; - e->base = base; - e->name = name; - return cg_type_set_alias(c, e, name, base) ? id : KIT_CG_TYPE_NONE; -} - -KitCgTypeId kit_cg_type_source_base(KitCompiler* c, KitSym name, - KitCgTypeId storage, - KitCgDebugEncoding encoding) { - KitCgTypeId id; - CgApiType* e; - if (!cg_type_get(c, storage)) return KIT_CG_TYPE_NONE; - /* Source-base ids are fresh (not interned), like aliases/enums. Frontends - * cache the lowered id on their own canonical type node, so the handful of C - * primitive spellings yield a bounded set of entries in practice. */ - e = type_alloc(c, &id); - if (!e) return KIT_CG_TYPE_NONE; - e->base = storage; - e->name = name; - return cg_type_set_source_base(c, e, name, storage, (u8)encoding) - ? id - : KIT_CG_TYPE_NONE; -} - KitCgTypeId kit_cg_type_record_decl(KitCompiler* c, KitSym tag, int is_union) { KitCgTypeId id; CgApiType* e; @@ -1105,7 +995,7 @@ KitCgTypeId kit_cg_type_record_decl(KitCompiler* c, KitSym tag, int is_union) { KitStatus kit_cg_type_record_complete(KitCompiler* c, KitCgTypeId record, const KitCgRecordDesc* desc) { CgApiType* e; - KitCgField* copied = NULL; + KitCgFieldDesc* copied = NULL; if (!c || !desc || (desc->nfields && !desc->fields) || desc->nfields > UINT16_MAX) { return KIT_INVALID; @@ -1116,7 +1006,7 @@ KitStatus kit_cg_type_record_complete(KitCompiler* c, KitCgTypeId record, if (e->cg.record.is_union != (desc->is_union != 0)) return KIT_INVALID; if (desc->nfields) { - copied = arena_array(&c->global->arena, KitCgField, desc->nfields); + copied = arena_array(&c->global->arena, KitCgFieldDesc, desc->nfields); if (!copied) return KIT_NOMEM; } for (u32 i = 0; i < desc->nfields; ++i) { @@ -1208,9 +1098,9 @@ uint32_t kit_cg_type_align(KitCompiler* c, KitCgTypeId id) { /* Identity view backing the inline kit_cg_type_{kind,resolve_alias,is_void} and * kit_cg_func_result_has_value queries in kit/cg.h. Builtins read the * precomputed table; user entries fill their identity prefix once (immutable - * thereafter: kind and storage are stable, NOMINAL is fixed at creation), then - * hand back the entry's first member. Layout and the COMPLETE/SIZED flags are - * deliberately left to kit_cg_type_info. */ + * thereafter: kind and storage identity are stable, NOMINAL is fixed at + * creation), then hand back the entry's first member. Layout and the + * COMPLETE/SIZED flags are deliberately left to kit_cg_type_info. */ const KitCgTypeInfo* kit_cg_type_view(KitCompiler* kc, KitCgTypeId id) { Compiler* c = (Compiler*)kc; CgApiState* s; @@ -1305,8 +1195,6 @@ KitStatus kit_cg_type_info(KitCompiler* kc, KitCgTypeId id, static int cg_type_same_storage_rec(Compiler* c, KitCgTypeId a, KitCgTypeId b) { const CgType* ta; const CgType* tb; - a = api_unalias_type(c, a); - b = api_unalias_type(c, b); if (!a || !b) return 0; if (a == b) return 1; ta = cg_type_get(c, a); @@ -1354,11 +1242,6 @@ static int cg_type_same_storage_rec(Compiler* c, KitCgTypeId a, KitCgTypeId b) { return 1; case KIT_CG_TYPE_RECORD: return 0; - /* a and b were unaliased before this switch, so ALIAS/SOURCE_BASE are - * unreachable here; the cases keep the switch exhaustive. */ - case KIT_CG_TYPE_ALIAS: - case KIT_CG_TYPE_SOURCE_BASE: - return 0; case KIT_CG_TYPE_ENUM: return 0; case KIT_CG_TYPE_VARARG_STATE: { @@ -1383,12 +1266,6 @@ uint32_t kit_cg_type_int_width(KitCompiler* c, KitCgTypeId id) { if (ty->kind == KIT_CG_TYPE_ENUM) { return kit_cg_type_int_width(c, ty->enum_.base); } - if (ty->kind == KIT_CG_TYPE_ALIAS) { - return kit_cg_type_int_width(c, ty->alias.base); - } - if (ty->kind == KIT_CG_TYPE_SOURCE_BASE) { - return kit_cg_type_int_width(c, ty->source_base.base); - } return 0; } @@ -1396,12 +1273,6 @@ uint32_t kit_cg_type_float_width(KitCompiler* c, KitCgTypeId id) { const CgType* ty = cg_type_get(c, id); if (!ty) return 0; if (ty->kind == KIT_CG_TYPE_FLOAT) return ty->fp.width; - if (ty->kind == KIT_CG_TYPE_ALIAS) { - return kit_cg_type_float_width(c, ty->alias.base); - } - if (ty->kind == KIT_CG_TYPE_SOURCE_BASE) { - return kit_cg_type_float_width(c, ty->source_base.base); - } return 0; } @@ -1479,29 +1350,44 @@ uint32_t kit_cg_type_record_nfields(KitCompiler* c, KitCgTypeId id) { : 0; } -KitStatus kit_cg_type_record_field(KitCompiler* c, KitCgTypeId id, - uint32_t index, KitCgField* out, - uint64_t* offset_out) { - const CgType* ty = cg_type_get(c, id); - const CgTypeField* f; - if (!ty || ty->kind != KIT_CG_TYPE_RECORD || !cg_type_record_complete(ty) || - index >= ty->record.nfields) { - return KIT_NOT_FOUND; - } - f = &ty->record.fields[index]; - if (out) { - out->name = f->name; - out->type = f->type; - out->align_override = f->align_override; - out->max_align = f->max_align; - out->flags = f->flags; - out->bit_width = f->bit_width; - out->bit_offset = f->bit_offset; - out->bit_storage_size = f->bit_storage_size; - out->bit_signed = f->bit_signed; +const KitCgRecordLayout* kit_cg_type_record_layout(KitCompiler* c, + KitCgTypeId id) { + CgApiType* e; + CgType* ty; + KitCgRecordLayout* view; + KitCgFieldLayout* fields; + u32 n; + e = api_type_from_id(c, id); + if (!e || e->cg.kind != KIT_CG_TYPE_RECORD) return NULL; + ty = &e->cg; + if (!cg_type_record_complete(ty)) return NULL; + /* Force/confirm sizing through the same path size/align queries use; an + * unsized record (e.g. a field that never sized) has no borrowable layout. */ + if (!cg_type_sized_id(c, id)) return NULL; + if (ty->record.layout_view) return ty->record.layout_view; + + n = ty->record.nfields; + view = arena_new(&c->global->arena, KitCgRecordLayout); + if (!view) return NULL; + fields = n ? arena_array(&c->global->arena, KitCgFieldLayout, n) : NULL; + if (n && !fields) return NULL; + for (u32 i = 0; i < n; ++i) { + const CgTypeField* f = &ty->record.fields[i]; + fields[i].name = f->name; + fields[i].type = f->type; + fields[i].offset = f->offset; + fields[i].flags = f->flags; + fields[i].bit_storage_size = f->bit_storage_size; + fields[i].bit_offset = f->bit_offset; + fields[i].bit_width = f->bit_width; + fields[i].bit_signed = f->bit_signed; } - if (offset_out) *offset_out = f->offset; - return KIT_OK; + view->size = ty->size; + view->align = ty->align; + view->nfields = n; + view->fields = fields; + ty->record.layout_view = view; + return view; } KitSym kit_cg_type_enum_tag(KitCompiler* c, KitCgTypeId id) { @@ -1529,36 +1415,6 @@ KitStatus kit_cg_type_enum_value(KitCompiler* c, KitCgTypeId id, uint32_t index, return KIT_OK; } -KitSym kit_cg_type_alias_name(KitCompiler* c, KitCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - return (ty && ty->kind == KIT_CG_TYPE_ALIAS) ? ty->alias.name : 0; -} - -KitCgTypeId kit_cg_type_alias_base(KitCompiler* c, KitCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - return (ty && ty->kind == KIT_CG_TYPE_ALIAS) ? ty->alias.base - : KIT_CG_TYPE_NONE; -} - -KitSym kit_cg_type_source_base_name(KitCompiler* c, KitCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - return (ty && ty->kind == KIT_CG_TYPE_SOURCE_BASE) ? ty->source_base.name : 0; -} - -KitCgTypeId kit_cg_type_source_base_storage(KitCompiler* c, KitCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - return (ty && ty->kind == KIT_CG_TYPE_SOURCE_BASE) ? ty->source_base.base - : KIT_CG_TYPE_NONE; -} - -KitCgDebugEncoding kit_cg_type_source_base_encoding(KitCompiler* c, - KitCgTypeId id) { - const CgType* ty = cg_type_get(c, id); - return (ty && ty->kind == KIT_CG_TYPE_SOURCE_BASE) - ? (KitCgDebugEncoding)ty->source_base.encoding - : KIT_CG_DEBUG_ENC_NONE; -} - int kit_cg_target_supports_call_conv(KitCompiler* c, KitCgCallConv cc) { const ArchImpl* a; if (!c) return 0; diff --git a/src/cg/type.h b/src/cg/type.h @@ -52,6 +52,10 @@ typedef struct CgType { int is_union; u32 align_override; u32 flags; + /* Lazily-built, CG-owned record-layout view returned by + * kit_cg_type_record_layout. NULL until first request; allocated from the + * compiler arena so the pointer is stable for the compiler's lifetime. */ + KitCgRecordLayout* layout_view; } record; struct { KitSym tag; @@ -59,15 +63,6 @@ typedef struct CgType { KitCgEnumValue* values; u32 nvalues; } enum_; - struct { - KitSym name; - KitCgTypeId base; - } alias; - struct { - KitSym name; - KitCgTypeId base; /* width-only storage builtin */ - u8 encoding; /* KitCgDebugEncoding */ - } source_base; }; } CgType; @@ -83,16 +78,14 @@ int cg_type_is_record(Compiler*, KitCgTypeId); KitCgTypeId builtin_id(KitCgBuiltinType); KitCgTypeId resolve_type(Compiler*, KitCgTypeId); -KitCgTypeId api_unalias_type(Compiler*, KitCgTypeId); int cg_type_is_void(Compiler*, KitCgTypeId); int cg_type_is_aggregate(Compiler*, KitCgTypeId); -/* Flat per-id predicate bitset (computed on the UNALIASED type). The six - * cg_type_is_* predicates are (bits & API_PRED_*) tests over this set; a site - * that asks several predicates of the SAME id reads the bitset once via - * api_type_pred_bits and tests the masks locally (one decode, not N). The - * membership rules MUST match cg_type_is_* exactly: INT covers INT|BOOL|ENUM - * and AGGREGATE == RECORD. */ +/* Flat per-id predicate bitset. The six cg_type_is_* predicates are + * (bits & API_PRED_*) tests over this set; a site that asks several predicates + * of the SAME id reads the bitset once via api_type_pred_bits and tests the + * masks locally (one decode, not N). The membership rules MUST match + * cg_type_is_* exactly: INT covers INT|BOOL|ENUM and AGGREGATE == RECORD. */ #define API_PRED_INT 0x01u #define API_PRED_FLOAT 0x02u #define API_PRED_PTR 0x04u diff --git a/src/cg/value.c b/src/cg/value.c @@ -380,15 +380,13 @@ void api_ensure_local(KitCg* g, ApiSValue* sv) { if (api_unevaluated(g)) return; if (api_sv_kind(sv) == SV_CMP) { KitCgTypeId ty = api_sv_type(sv); - KitCgTypeId uty = - api_unalias_type(g->c, ty); /* compute the dst terminal once */ Operand dst; if (sv->delayed->cmp.a_owned && sv->delayed->cmp.a.kind == OPK_LOCAL && - api_unalias_type(g->c, sv->delayed->cmp.a.type) == uty) { + sv->delayed->cmp.a.type == ty) { dst = api_op_local(sv->delayed->cmp.a.v.local, ty); } else if (sv->delayed->cmp.b_owned && sv->delayed->cmp.b.kind == OPK_LOCAL && - api_unalias_type(g->c, sv->delayed->cmp.b.type) == uty) { + sv->delayed->cmp.b.type == ty) { dst = api_op_local(sv->delayed->cmp.b.v.local, ty); } else { CGLocal r = @@ -400,15 +398,13 @@ void api_ensure_local(KitCg* g, ApiSValue* sv) { } if (api_sv_kind(sv) == SV_ARITH) { KitCgTypeId ty = api_sv_type(sv); - KitCgTypeId uty = - api_unalias_type(g->c, ty); /* compute the dst terminal once */ Operand dst; if (sv->delayed->arith.a_owned && sv->delayed->arith.a.kind == OPK_LOCAL && - api_unalias_type(g->c, sv->delayed->arith.a.type) == uty) { + sv->delayed->arith.a.type == ty) { dst = api_op_local(sv->delayed->arith.a.v.local, ty); } else if (api_arith_rhs_reusable(sv) && sv->delayed->arith.b_owned && sv->delayed->arith.b.kind == OPK_LOCAL && - api_unalias_type(g->c, sv->delayed->arith.b.type) == uty) { + sv->delayed->arith.b.type == ty) { dst = api_op_local(sv->delayed->arith.b.v.local, ty); } else { CGLocal r = @@ -423,7 +419,8 @@ void api_ensure_local(KitCg* g, ApiSValue* sv) { Operand api_force_local(KitCg* g, ApiSValue* v, KitCgTypeId ty) { CgTarget* T = g->target; - ty = api_unalias_type(g->c, ty); + ty = resolve_type(g->c, ty); + if (!ty) return api_op_imm(0, KIT_CG_TYPE_NONE); if (api_unevaluated(g)) return api_op_imm(0, ty); api_ensure_local(g, v); if (v->op.kind == OPK_LOCAL && !api_is_lvalue_sv(v)) { diff --git a/test/api/abi_classify_test.c b/test/api/abi_classify_test.c @@ -176,7 +176,7 @@ static void expect_direct_2(const char* tag, const ABIArgInfo* ai, u8 c0, u8 c1, } static KitCgTypeId record2(KitCompiler* c, KitCgTypeId a, KitCgTypeId b) { - KitCgField f[2]; + KitCgFieldDesc f[2]; KitCgRecordDesc desc; memset(f, 0, sizeof f); f[0].type = a; @@ -318,7 +318,7 @@ static void check_target(KitArchKind arch, KitOSKind os, KitObjFmt obj) { static KitCgTypeId make_i8_record(KitCompiler* c, const char* tag_name, u32 nfields) { KitCgTypeId i8 = builtin(c, KIT_CG_BUILTIN_I8); - KitCgField fields[16]; + KitCgFieldDesc fields[16]; KitCgRecordDesc desc; static const char* const names[16] = {"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", @@ -339,7 +339,7 @@ static KitCgTypeId make_i8_record(KitCompiler* c, const char* tag_name, /* Build a record { i64 a; i64 b; } — size 16, align 8. */ static KitCgTypeId make_two_i64_record(KitCompiler* c, const char* tag_n) { KitCgTypeId i64 = builtin(c, KIT_CG_BUILTIN_I64); - KitCgField fields[2]; + KitCgFieldDesc fields[2]; KitCgRecordDesc desc; memset(fields, 0, sizeof fields); fields[0].name = kit_sym_intern(c, KIT_SLICE_LIT("a")); diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -1736,12 +1736,6 @@ int main(void) { KitCgFuncParam params[2]; KitCgFuncSig sig; KitCgTypeId fn; - KitCgTypeId alias; - KitCgTypeId alias_ptr_i32; - KitCgTypeId ptr_alias_i32; - KitCgTypeId src_uint; - KitCgTypeId src_uchar; - KitCgTypeId ptr_src_uint; KitCgTypeInfo info; KitCgTypeId rec; KitCgTypeId rec_ex; @@ -1751,8 +1745,9 @@ int main(void) { KitCgTypeId rec_bad; KitCgTypeId enm; KitCgRecordDesc rdesc; - KitCgField fields[2]; - KitCgField field_out; + KitCgFieldDesc fields[2]; + const KitCgRecordLayout* rlayout; + KitCgFieldLayout field_out; KitCgEnumValue vals[2]; uint64_t field_off; @@ -1807,80 +1802,21 @@ int main(void) { EXPECT(huge_array_b != KIT_CG_TYPE_NONE, "small array after huge rejection should still work"); - alias = kit_cg_type_alias(c, kit_sym_intern(c, KIT_SLICE_LIT("I")), i32_ty); - EXPECT(alias != KIT_CG_TYPE_NONE && alias != i32_ty, - "alias id should be fresh"); - EXPECT(kit_cg_type_kind(c, alias) == KIT_CG_TYPE_ALIAS, - "alias kind mismatch"); - EXPECT(kit_cg_type_resolve_alias(c, alias) == i32_ty, - "alias should resolve to base"); - EXPECT(kit_cg_type_size(c, alias) == kit_cg_type_size(c, i32_ty), - "alias size mismatch"); - EXPECT(kit_cg_type_info(c, alias, &info) == KIT_OK, "alias info failed"); - EXPECT(info.kind == KIT_CG_TYPE_ALIAS && info.storage_id == i32_ty, - "alias info exact/storage mismatch"); - EXPECT(info.layout.valid && info.layout.storage_kind == KIT_CG_STORAGE_INT && - info.layout.scalar_width == 32, - "alias storage info mismatch"); - EXPECT(kit_cg_type_same_storage(c, alias, i32_ty), - "alias should share storage with base"); - alias_ptr_i32 = - kit_cg_type_alias(c, kit_sym_intern(c, KIT_SLICE_LIT("PI")), i32_ty); - ptr_alias_i32 = kit_cg_type_ptr(c, alias_ptr_i32, 0); - EXPECT(ptr_alias_i32 != KIT_CG_TYPE_NONE, "ptr(alias(i32)) failed"); - EXPECT(kit_cg_type_same_storage(c, ptr_alias_i32, ptr_i32), - "ptr(alias(i32)) should share storage with ptr(i32)"); - - /* Source-base scalars: a source-facing primitive spelling (sign/name) over a - * width-only storage builtin. Exact kind and debug see the spelling; storage, - * ABI, and codegen see the underlying builtin (the id unaliases to it). */ - src_uint = kit_cg_type_source_base( - c, kit_sym_intern(c, KIT_SLICE_LIT("unsigned int")), i32_ty, - KIT_CG_DEBUG_ENC_UNSIGNED); - EXPECT(src_uint != KIT_CG_TYPE_NONE && src_uint != i32_ty, - "source-base id should be fresh and distinct from its storage"); - EXPECT(kit_cg_type_kind(c, src_uint) == KIT_CG_TYPE_SOURCE_BASE, - "source-base exact kind mismatch"); - EXPECT(kit_cg_type_source_base_storage(c, src_uint) == i32_ty, - "source-base storage accessor mismatch"); - EXPECT(kit_cg_type_source_base_encoding(c, src_uint) == - KIT_CG_DEBUG_ENC_UNSIGNED, - "source-base encoding accessor mismatch"); - EXPECT(kit_cg_type_resolve_alias(c, src_uint) == i32_ty, - "source-base should unalias to its storage builtin"); - EXPECT(kit_cg_type_same_storage(c, src_uint, i32_ty), - "source-base should share storage with its builtin"); - EXPECT(kit_cg_type_size(c, src_uint) == kit_cg_type_size(c, i32_ty) && - kit_cg_type_int_width(c, src_uint) == 32, - "source-base size/width should follow its storage"); - EXPECT(kit_cg_type_is_sized(c, src_uint), - "source-base over a sized builtin should be sized"); - EXPECT(kit_cg_type_info(c, src_uint, &info) == KIT_OK, - "source-base info failed"); - EXPECT(info.kind == KIT_CG_TYPE_SOURCE_BASE && info.storage_id == i32_ty && - (info.flags & KIT_CG_TYPEF_NOMINAL) && + EXPECT(kit_cg_type_resolve_alias(c, i32_ty) == i32_ty, + "storage identity should resolve to itself"); + EXPECT(kit_cg_type_info(c, i32_ty, &info) == KIT_OK, "i32 info failed"); + EXPECT(info.kind == KIT_CG_TYPE_INT && info.storage_id == i32_ty && + info.layout.valid && info.layout.storage_kind == KIT_CG_STORAGE_INT && info.layout.scalar_width == 32, - "source-base info exact/storage/layout mismatch"); - /* A composite built over a source-base preserves the spelling (debug fidelity - * for `unsigned int *`) yet stays storage-equivalent to the builtin form. */ - ptr_src_uint = kit_cg_type_ptr(c, src_uint, 0); - EXPECT(ptr_src_uint != KIT_CG_TYPE_NONE && - kit_cg_type_ptr_pointee(c, ptr_src_uint) == src_uint, - "ptr(source-base) should preserve the source-base pointee"); - EXPECT(kit_cg_type_same_storage(c, ptr_src_uint, ptr_i32), - "ptr(source-base) should share storage with ptr(i32)"); - src_uchar = kit_cg_type_source_base( - c, kit_sym_intern(c, KIT_SLICE_LIT("unsigned char")), i8_ty, - KIT_CG_DEBUG_ENC_UNSIGNED_CHAR); - EXPECT(src_uchar != KIT_CG_TYPE_NONE && - kit_cg_type_same_storage(c, src_uchar, i8_ty), - "unsigned-char source-base should share storage with i8"); - /* The storage operand must be a real scalar builtin. */ - EXPECT(kit_cg_type_source_base( - c, kit_sym_intern(c, KIT_SLICE_LIT("bad")), ptr_i32, - KIT_CG_DEBUG_ENC_SIGNED) == KIT_CG_TYPE_NONE, - "source-base over a non-scalar storage should be rejected"); + "i32 info identity/layout mismatch"); + EXPECT(kit_cg_type_info(c, ptr_i32, &info) == KIT_OK, "ptr info failed"); + EXPECT(info.kind == KIT_CG_TYPE_PTR && info.storage_id == ptr_i32, + "ptr info should keep storage identity"); + EXPECT(kit_cg_type_same_storage(c, i32_ty, i32_ty), + "type should share storage with itself"); + EXPECT(!kit_cg_type_same_storage(c, ptr_i32, i32_ty), + "unrelated types should not share storage"); memset(fields, 0, sizeof fields); fields[0].name = kit_sym_intern(c, KIT_SLICE_LIT("a")); @@ -1903,8 +1839,10 @@ int main(void) { "record kind mismatch"); EXPECT(kit_cg_type_record_nfields(c, rec) == 2, "record field count mismatch"); - EXPECT(kit_cg_type_record_field(c, rec, 1, &field_out, &field_off) == 0, - "record field query failed"); + rlayout = kit_cg_type_record_layout(c, rec); + EXPECT(rlayout && rlayout->nfields > 1, "record field query failed"); + field_out = rlayout->fields[1]; + field_off = field_out.offset; EXPECT(field_out.name == fields[1].name && field_out.type == ptr_i32, "record field data mismatch"); EXPECT(field_off == 4, "record field offset mismatch"); @@ -1925,8 +1863,10 @@ int main(void) { rec_ex = kit_cg_type_record(c, &rdesc); EXPECT(rec_ex != KIT_CG_TYPE_NONE, "bit-field record type failed"); EXPECT(kit_cg_type_size(c, rec_ex) == 4, "bit-field record size mismatch"); - EXPECT(kit_cg_type_record_field(c, rec_ex, 1, &field_out, &field_off) == 0, - "bit-field record query failed"); + rlayout = kit_cg_type_record_layout(c, rec_ex); + EXPECT(rlayout && rlayout->nfields > 1, "bit-field record query failed"); + field_out = rlayout->fields[1]; + field_off = field_out.offset; EXPECT(field_off == 0 && field_out.bit_offset == 5 && field_out.bit_width == 3 && field_out.bit_storage_size == 4, "bit-field metadata mismatch"); @@ -1947,8 +1887,10 @@ int main(void) { EXPECT(rec_ex != KIT_CG_TYPE_NONE, "record desc type failed"); EXPECT(kit_cg_type_size(c, rec_ex) == 16, "record desc size mismatch"); EXPECT(kit_cg_type_align(c, rec_ex) == 16, "record desc align mismatch"); - EXPECT(kit_cg_type_record_field(c, rec_ex, 1, &field_out, &field_off) == 0, - "record desc field query failed"); + rlayout = kit_cg_type_record_layout(c, rec_ex); + EXPECT(rlayout && rlayout->nfields > 1, "record desc field query failed"); + field_out = rlayout->fields[1]; + field_off = field_out.offset; EXPECT(field_off == 0, "union field offset mismatch"); rec_decl = @@ -1960,7 +1902,7 @@ int main(void) { "fresh record decl should be incomplete"); EXPECT(!kit_cg_type_is_sized(c, rec_decl), "fresh record decl should be unsized"); - EXPECT(kit_cg_type_record_field(c, rec_decl, 0, NULL, NULL) == KIT_NOT_FOUND, + EXPECT(kit_cg_type_record_layout(c, rec_decl) == NULL, "incomplete record should not expose fields"); rec_ptr = kit_cg_type_ptr(c, rec_decl, 0); EXPECT(rec_ptr != KIT_CG_TYPE_NONE, @@ -2014,18 +1956,18 @@ int main(void) { ev.name == vals[1].name && ev.value == 2, "enum should preserve enumerator name/value pairs"); } - /* An enum whose underlying type is a source-base spelling (e.g. - * `enum E : unsigned int`) must construct: the base validates through its - * storage, and the source-facing base id is retained for debug. */ + /* An enum with an explicit integer underlying type must construct and retain + * that operational base exactly. Source spellings now travel through the + * debug type channel rather than wrapper type ids. */ { KitCgTypeId enm_u = kit_cg_type_enum( - c, kit_sym_intern(c, KIT_SLICE_LIT("EU")), src_uint, vals, 2); + c, kit_sym_intern(c, KIT_SLICE_LIT("EU")), i8_ty, vals, 2); EXPECT(enm_u != KIT_CG_TYPE_NONE, - "enum over a source-base underlying type should construct"); - EXPECT(kit_cg_type_enum_base(c, enm_u) == src_uint, - "enum should retain its source-base underlying type id"); - EXPECT(kit_cg_type_int_width(c, enm_u) == 32, - "enum width should follow its source-base underlying type"); + "enum over an explicit integer underlying type should construct"); + EXPECT(kit_cg_type_enum_base(c, enm_u) == i8_ty, + "enum should retain its explicit underlying type id"); + EXPECT(kit_cg_type_int_width(c, enm_u) == 8, + "enum width should follow its explicit underlying type"); } memset(params, 0, sizeof(params));