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:
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));