commit 9ef2979b70072891cc096bffa3b00a6db7a3f68d
parent 4d79515eb873bad5a8cd75952628e0eebe1f2df1
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 14 May 2026 07:28:34 -0700
Add CG type registry
Diffstat:
4 files changed, 995 insertions(+), 109 deletions(-)
diff --git a/doc/cg-type-migration-plan.md b/doc/cg-type-migration-plan.md
@@ -0,0 +1,404 @@
+# CG Type Migration Plan
+
+## Goal
+
+Make the C frontend just another language frontend, like `lang/toy`, while
+removing the C language `Type` dependency from `src/`.
+
+The C frontend should keep its rich C semantic type system privately in
+`lang/c`. Codegen, ABI, arch lowering, optimizer, and object emission should
+use a narrower, language-neutral `CgType` model constructed only through the
+public `include/cfree/cg.h` type constructors.
+
+## Status Checklist
+
+Keep this section current as migration work lands.
+
+- [x] Phase 1: Add an internal `CgType` payload behind `CfreeCgTypeId`.
+- [x] Phase 1: Add internal `cg_type_*` lookup, layout, and classification
+ helpers.
+- [x] Phase 1: Populate `CgType` from public CG constructors and the temporary
+ legacy C `Type*` import bridge.
+- [x] Phase 1: Move public CG type query APIs to `CgType`.
+- [ ] Phase 1: Move `CgType` into a dedicated internal header/module if the
+ next migration slice needs it outside `src/api/cg.c`.
+- [ ] Phase 2: Cache lowered `CfreeCgTypeId` values in the C frontend or in a
+ frontend-owned `Type*` map.
+- [ ] Phase 2: Replace recursive-record placeholder lowering with a real
+ forward/begin/complete public CG record API.
+- [ ] Phase 3: Replace stored `const Type*` in `src/api/cg.c` state with
+ `CfreeCgTypeId` or `CgType` facts.
+- [ ] Phase 4: Migrate ABI APIs and record/function caches from C `Type*` to
+ CG type handles.
+- [ ] Phase 5: Migrate `CGTarget` and arch lowering away from C semantic
+ types.
+- [ ] Phase 6: Migrate optimizer and generic debug bridges away from C
+ semantic types.
+- [ ] Phase 7: Remove legacy C type bridges and shim headers.
+- [ ] Phase 8: Register C through the frontend mechanism and remove direct
+ `src` dependencies on `lang/c`.
+
+## Target Boundary
+
+- `lang/c/Type`: C semantic type. It carries C-only facts such as qualifiers,
+ typedef/tag behavior, incomplete types, decay rules, bitfield syntax, and
+ source-level compatibility.
+- `CgType`: language-neutral codegen type. It carries only storage, layout,
+ calling convention, and lowering information expressible through
+ `include/cfree/cg.h`.
+- `src/`: must not include or depend on `lang/c` headers.
+- `ObjBuilder`: should see symbols, sections, relocs, and bytes, not C types.
+- `CGTarget`: should see codegen facts such as size, alignment, register class,
+ pointer/float/int shape, and operation flags, not C semantic facts.
+
+## Why This Is Needed
+
+Today `CfreeCgTypeId` is public, but internally `src/api/cg.c` resolves it back
+to the C frontend `Type*`. That makes the public CG API a wrapper around the C
+type system and keeps `src` coupled to `lang/c` through compatibility headers.
+
+The main current dependency shape is:
+
+- public `cfree_cg_type_*` constructors create/import C `Type*`
+- CG stack values, operands, slots, symbols, ABI calls, and target descriptors
+ store `const Type*`
+- ABI and arch helpers inspect `Type*` directly
+- `src/type/type.h` is currently a shim to `lang/c/type/type.h`
+
+The migration inverts that relationship. C `Type` lowers to `CfreeCgTypeId`;
+CG internals resolve `CfreeCgTypeId` to `CgType`.
+
+## CgType Shape
+
+Add an internal `CgType` representation, probably under `src/api/cg_type.h` or
+`src/cg/type.h`.
+
+It should model only concepts from public `include/cfree/cg.h`:
+
+```c
+typedef struct CgType CgType;
+
+typedef struct CgTypeField {
+ CfreeSym name;
+ CfreeCgTypeId type;
+ uint64_t offset;
+ uint32_t align_override;
+} CgTypeField;
+
+struct CgType {
+ CfreeCgTypeKind kind;
+ uint64_t size;
+ uint32_t align;
+
+ union {
+ struct {
+ uint32_t width;
+ } integer;
+
+ struct {
+ uint32_t width;
+ } fp;
+
+ struct {
+ CfreeCgTypeId pointee;
+ uint32_t address_space;
+ } ptr;
+
+ struct {
+ CfreeCgTypeId elem;
+ uint64_t count;
+ } array;
+
+ struct {
+ CfreeCgTypeId ret;
+ CfreeCgParam* params;
+ uint32_t nparams;
+ CfreeCgCallConv call_conv;
+ int abi_variadic;
+ CfreeCgAbiAttrs ret_attrs;
+ } func;
+
+ struct {
+ CfreeSym tag;
+ CgTypeField* fields;
+ uint32_t nfields;
+ int is_union;
+ uint32_t align_override;
+ uint32_t flags;
+ } record;
+
+ struct {
+ CfreeSym tag;
+ CfreeCgTypeId base;
+ CfreeCgEnumValue* values;
+ uint32_t nvalues;
+ } enum_;
+
+ struct {
+ CfreeSym name;
+ CfreeCgTypeId base;
+ } alias;
+ };
+};
+```
+
+Exact field names can change, but the important rule is that `CgType` cannot
+grow C-only semantics.
+
+## Public API Gaps To Address
+
+Before fully migrating internals, confirm the public type constructors can
+represent codegen needs without C-specific escape hatches.
+
+Known gaps:
+
+- Record construction needs a forward/incomplete or begin/complete story for
+ self-referential records.
+- Records need to distinguish struct and union.
+- Packed/aligned record and field layout must be expressible.
+- Bitfields need either direct representation or an explicit frontend-lowered
+ representation.
+- Signedness should stay out of storage type identity where possible. Keep it
+ on integer operations, comparisons, conversions, and ABI extension attrs.
+- `va_list` should be expressible as a target-provided CG type without relying
+ on C `Type`.
+
+## Migration Phases
+
+### Phase 1: Add CgType Registry Behind CfreeCgTypeId
+
+Change the existing public type registry in `src/api/cg.c` so each
+`CfreeCgTypeId` resolves to a canonical `CgType`.
+
+During this phase, keep the legacy C type pointer as a bridge:
+
+```c
+typedef struct CgApiType {
+ CgType cg;
+ const Type* legacy_type; /* temporary migration bridge */
+} CgApiType;
+```
+
+Add internal helpers:
+
+```c
+const CgType* cg_type_get(Compiler*, CfreeCgTypeId);
+uint64_t cg_type_size(Compiler*, CfreeCgTypeId);
+uint32_t cg_type_align(Compiler*, CfreeCgTypeId);
+int cg_type_is_int(Compiler*, CfreeCgTypeId);
+int cg_type_is_float(Compiler*, CfreeCgTypeId);
+int cg_type_is_ptr(Compiler*, CfreeCgTypeId);
+int cg_type_is_record(Compiler*, CfreeCgTypeId);
+```
+
+Public query APIs such as `cfree_cg_type_size` and
+`cfree_cg_type_record_field` should use `CgType`, not C `Type`.
+
+Deliverable:
+
+- No behavior change.
+- Public tests still pass.
+- Existing code may still use `legacy_type`, but new code should not add new
+ direct `Type*` usage.
+
+### Phase 2: Cache CgTypeId In The C Frontend Type
+
+Keep the C frontend `Type`, but make its lowered CG representation explicit.
+
+Add a cache field to `lang/c/type/type.h`:
+
+```c
+CfreeCgTypeId cg_id;
+```
+
+or, if mutability of interned `Type` is undesirable, add a frontend-side
+map from `Type*` to `CfreeCgTypeId`.
+
+Update `type_cg_id(CfreeCompiler*, const Type*)` so it constructs through the
+public CG API once and returns the cached id thereafter.
+
+Recursive records need special handling. Prefer a real public
+begin/complete/forward record API over the current placeholder behavior.
+
+Deliverable:
+
+- `lang/c` lowers to public CG type constructors.
+- `src` still builds with the legacy bridge.
+
+### Phase 3: Migrate src/api/cg.c State To CgType
+
+Replace stored `const Type*` in CG state with `CfreeCgTypeId` or
+`const CgType*`.
+
+High-priority structures:
+
+- stack values
+- operands
+- slots
+- symbol type table
+- function return type
+- memory access descriptors
+- conversion helpers
+- call descriptors
+- intrinsic and atomic lowering helpers
+
+Temporary bridge calls into old ABI/arch code are acceptable, but they should
+be centralized. Do not continue storing C `Type*` in CG state.
+
+Deliverable:
+
+- `src/api/cg.c` mostly reasons in `CfreeCgTypeId`/`CgType`.
+- Remaining `Type*` use is isolated to bridge functions.
+
+### Phase 4: Migrate ABI To CgType
+
+Change ABI APIs from C `Type*` to CG type handles.
+
+Current APIs to migrate:
+
+```c
+ABITypeInfo abi_type_info(TargetABI*, const Type*);
+u32 abi_sizeof(TargetABI*, const Type*);
+u32 abi_alignof(TargetABI*, const Type*);
+const ABIRecordLayout* abi_record_layout(TargetABI*, const Type*);
+const ABIFuncInfo* abi_func_info(TargetABI*, const Type* fn_type);
+```
+
+Target APIs should look more like:
+
+```c
+ABITypeInfo abi_type_info(TargetABI*, CfreeCgTypeId);
+u32 abi_sizeof(TargetABI*, CfreeCgTypeId);
+u32 abi_alignof(TargetABI*, CfreeCgTypeId);
+const ABIRecordLayout* abi_record_layout(TargetABI*, CfreeCgTypeId);
+const ABIFuncInfo* abi_func_info(TargetABI*, CfreeCgTypeId fn_type);
+```
+
+Record layout should be cached by `CfreeCgTypeId`, not `Type*`.
+
+Deliverable:
+
+- ABI no longer includes `type/type.h`.
+- ABI classification uses only `CgType` and target facts.
+
+### Phase 5: Migrate CGTarget And Arch Lowering
+
+Change target-facing structs in `src/arch/arch.h` from `const Type*` to
+`CfreeCgTypeId` or derived `CgType` facts.
+
+Most arch code only needs:
+
+- byte size
+- alignment
+- integer width
+- float width
+- pointer vs integer vs float
+- register class
+- signedness for specific signed operations
+
+Replace helpers such as:
+
+```c
+type_is_64(t)
+type_is_fp_double(t)
+type_byte_size(t)
+type_is_signed(t)
+```
+
+with CG-type helpers. Where signedness is operation-specific, pass it through
+operation metadata instead of reading it from type identity.
+
+Deliverable:
+
+- arch code does not include `type/type.h`
+- `CGTarget` is language-neutral
+
+### Phase 6: Migrate Optimizer And Debug Bridges
+
+Optimizer IR currently stores `const Type*` in several places. Move it to
+`CfreeCgTypeId` or `CgType` facts.
+
+Debug should remain a separate concern:
+
+- Codegen debug emission can consume frontend-provided debug type IDs.
+- C-specific debug lowering from C `Type` should live in `lang/c` or an
+ explicit C debug adapter, not in generic `src` code.
+
+Deliverable:
+
+- optimizer no longer includes C type headers
+- generic debug producer does not depend on C type
+
+### Phase 7: Remove Legacy C Type Bridges
+
+After CG, ABI, arch, opt, and generic debug no longer need C `Type*`, remove:
+
+- `legacy_type` from `CgApiType`
+- `cg_api_type_import`
+- `cg_api_type_resolve`
+- `cfree_cg_internal_*_type`
+- `src/type/type.h` shim
+- `src/decl/*` shims if no longer needed
+
+Deliverable:
+
+- `src` no longer depends on `lang/c/type`.
+- `lang/c` is the only owner of C semantic types.
+
+### Phase 8: Make C A Registered Frontend
+
+Once `src` no longer needs C headers, make C follow the same pattern as Toy.
+
+Current special case:
+
+- `src/api/pipeline.c` directly includes `../../lang/c/c.h`
+- `compile_into` has a hardcoded `CFREE_LANG_C` branch
+
+Target:
+
+- `cfree_c_compile` is registered through the same frontend mechanism as Toy.
+- `src/api/pipeline.c` only calls `c->frontends[input->lang]` for language
+ compilation.
+- Eventually replace enum-indexed registration with string registration.
+
+ASM can remain a builtin path temporarily, or be moved to its own registered
+frontend in a later cleanup.
+
+Deliverable:
+
+- no `src -> lang/c` include
+- C frontend is linked/registered the same way as Toy
+
+## Suggested PR Sequence
+
+1. Add `CgType` and registry helpers; keep legacy `Type*`.
+2. Add C frontend `Type -> CfreeCgTypeId` cache.
+3. Convert public type query APIs to read `CgType`.
+4. Convert `src/api/cg.c` stack/operand/slot/symbol state to CG types.
+5. Convert ABI to CG types.
+6. Convert `CGTarget` and arch lowering to CG types.
+7. Convert optimizer/debug generic paths.
+8. Delete legacy bridges and shim headers.
+9. Register C like Toy and remove direct `src/api/pipeline.c -> lang/c/c.h`.
+
+Each PR should keep `make lib` and `CFREE_TEST_ALLOW_SKIP=1 make test-parse`
+green. Broader `test-cg` and arch-specific tests should be run around phases
+4 through 6.
+
+## Non-Goals
+
+- Do not remove the C frontend `Type` early. It is still needed for C language
+ semantics.
+- Do not move C-only rules into `CgType`.
+- Do not make `ObjBuilder` understand type systems.
+- Do not make `CGTarget` inspect language-specific types.
+
+## Completion Criteria
+
+- No `src` file includes `lang/c` headers directly or indirectly.
+- No `src` file includes `type/type.h` as a C semantic type.
+- Public CG type constructors create all codegen-visible type facts.
+- ABI, arch, CG, and optimizer operate on `CgType`/`CfreeCgTypeId`.
+- C and Toy are both registered language frontends.
+- C-specific lexer, preprocessor, parser, decl, and type code live under
+ `lang/c` only.
diff --git a/src/api/cg.c b/src/api/cg.c
@@ -13,6 +13,62 @@
#include "obj/obj.h"
#include "type/type.h"
+typedef struct CgTypeField {
+ CfreeSym name;
+ CfreeCgTypeId type;
+ u64 offset;
+ u32 align_override;
+} CgTypeField;
+
+typedef struct CgType {
+ CfreeCgTypeKind kind;
+ u64 size;
+ u32 align;
+ u32 pad;
+ union {
+ struct {
+ u32 width;
+ } integer;
+ struct {
+ u32 width;
+ } fp;
+ struct {
+ CfreeCgTypeId pointee;
+ u32 address_space;
+ } ptr;
+ struct {
+ CfreeCgTypeId elem;
+ u64 count;
+ } array;
+ struct {
+ CfreeCgTypeId ret;
+ CfreeCgParam* params;
+ u32 nparams;
+ CfreeCgCallConv call_conv;
+ int abi_variadic;
+ CfreeCgAbiAttrs ret_attrs;
+ } func;
+ struct {
+ CfreeSym tag;
+ CgTypeField* fields;
+ u32 nfields;
+ int is_union;
+ u32 align_override;
+ u32 flags;
+ } record;
+ struct {
+ CfreeSym tag;
+ CfreeCgTypeId base;
+ CfreeCgEnumValue* values;
+ u32 nvalues;
+ } enum_;
+ struct {
+ CfreeSym name;
+ CfreeCgTypeId base;
+ } alias;
+ };
+} CgType;
+
typedef enum CgApiTypeKind {
CG_API_TYPE_PTR,
CG_API_TYPE_ARRAY,
@@ -23,6 +79,7 @@ typedef enum CgApiTypeKind {
} CgApiTypeKind;
typedef struct CgApiType {
+ CgType cg;
const Type* type;
CfreeCgTypeId base;
CfreeSym name;
@@ -45,6 +102,9 @@ SEGVEC_DEFINE(CgApiTypes, CgApiType, CG_API_TYPE_SEG_SHIFT);
typedef struct CgApiState {
Heap* heap;
CgApiTypes types;
+ CgType builtins[CFREE_CG_BUILTIN_COUNT];
+ u8 builtins_init;
+ u8 pad[3];
} CgApiState;
static CfreeCgTypeId type_id_from_tuple(u32 seg, u32 index) {
@@ -79,6 +139,11 @@ static CfreeCgTypeId type_id_for_user_index(u32 index) {
return user_id_from_index(index);
}
+static u64 cg_align_to(u64 n, u32 align) {
+ u64 a = align ? (u64)align : 1u;
+ return ((n + a - 1u) / a) * a;
+}
+
static const Type* builtin_type(Compiler* c, CfreeCgBuiltinType t) {
switch (t) {
case CFREE_CG_BUILTIN_VOID:
@@ -107,6 +172,116 @@ static const Type* builtin_type(Compiler* c, CfreeCgBuiltinType t) {
return NULL;
}
+static CfreeCgTypeId builtin_id_from_type_kind(TypeKind kind) {
+ switch (kind) {
+ case TY_VOID:
+ return builtin_id(CFREE_CG_BUILTIN_VOID);
+ case TY_BOOL:
+ return builtin_id(CFREE_CG_BUILTIN_BOOL);
+ case TY_CHAR:
+ case TY_SCHAR:
+ case TY_UCHAR:
+ return builtin_id(CFREE_CG_BUILTIN_I8);
+ case TY_SHORT:
+ case TY_USHORT:
+ return builtin_id(CFREE_CG_BUILTIN_I16);
+ case TY_INT:
+ case TY_UINT:
+ return builtin_id(CFREE_CG_BUILTIN_I32);
+ case TY_LONG:
+ case TY_ULONG:
+ case TY_LLONG:
+ case TY_ULLONG:
+ return builtin_id(CFREE_CG_BUILTIN_I64);
+ case TY_INT128:
+ case TY_UINT128:
+ return builtin_id(CFREE_CG_BUILTIN_I128);
+ case TY_FLOAT:
+ return builtin_id(CFREE_CG_BUILTIN_F32);
+ case TY_DOUBLE:
+ case TY_LDOUBLE:
+ return builtin_id(CFREE_CG_BUILTIN_F64);
+ default:
+ return CFREE_CG_TYPE_NONE;
+ }
+}
+
+static void builtin_cg_type_init(Compiler* c, CgType* out,
+ CfreeCgBuiltinType t) {
+ memset(out, 0, sizeof(*out));
+ switch (t) {
+ case CFREE_CG_BUILTIN_VOID:
+ out->kind = CFREE_CG_TYPE_VOID;
+ out->align = 1;
+ break;
+ case CFREE_CG_BUILTIN_BOOL:
+ out->kind = CFREE_CG_TYPE_BOOL;
+ out->size = 1;
+ out->align = 1;
+ out->integer.width = 8;
+ break;
+ case CFREE_CG_BUILTIN_I8:
+ out->kind = CFREE_CG_TYPE_INT;
+ out->size = 1;
+ out->align = 1;
+ out->integer.width = 8;
+ break;
+ case CFREE_CG_BUILTIN_I16:
+ out->kind = CFREE_CG_TYPE_INT;
+ out->size = 2;
+ out->align = 2;
+ out->integer.width = 16;
+ break;
+ case CFREE_CG_BUILTIN_I32:
+ out->kind = CFREE_CG_TYPE_INT;
+ out->size = 4;
+ out->align = 4;
+ out->integer.width = 32;
+ break;
+ case CFREE_CG_BUILTIN_I64:
+ out->kind = CFREE_CG_TYPE_INT;
+ out->size = 8;
+ out->align = 8;
+ out->integer.width = 64;
+ break;
+ case CFREE_CG_BUILTIN_I128:
+ out->kind = CFREE_CG_TYPE_INT;
+ out->size = 16;
+ out->align = 16;
+ out->integer.width = 128;
+ break;
+ case CFREE_CG_BUILTIN_F32:
+ out->kind = CFREE_CG_TYPE_FLOAT;
+ out->size = 4;
+ out->align = 4;
+ out->fp.width = 32;
+ break;
+ case CFREE_CG_BUILTIN_F64:
+ out->kind = CFREE_CG_TYPE_FLOAT;
+ out->size = 8;
+ out->align = 8;
+ out->fp.width = 64;
+ break;
+ case CFREE_CG_BUILTIN_VARARG_STATE: {
+ const Type* ty = builtin_type(c, t);
+ out->kind = CFREE_CG_TYPE_VARARG_STATE;
+ out->size = ty ? abi_sizeof(c->abi, ty) : 0;
+ out->align = ty ? abi_alignof(c->abi, ty) : 1;
+ break;
+ }
+ case CFREE_CG_BUILTIN_COUNT:
+ break;
+ }
+}
+
+static void cg_api_init_builtins(Compiler* c, CgApiState* s) {
+ if (s->builtins_init) return;
+ for (u32 i = 0; i < CFREE_CG_BUILTIN_COUNT; ++i) {
+ builtin_cg_type_init(c, &s->builtins[i], (CfreeCgBuiltinType)i);
+ }
+ s->builtins_init = 1;
+}
+
static CgApiState* cg_api_get(Compiler* c) {
Heap* h;
CgApiState* s;
@@ -120,9 +295,75 @@ static CgApiState* cg_api_get(Compiler* c) {
CgApiTypes_init(&s->types, h);
c->cg_api = s;
c->cg_api_free = cg_api_fini;
+ cg_api_init_builtins(c, s);
return s;
}
+static CgApiType* api_type_from_id(Compiler* c, CfreeCgTypeId id);
+
+const CgType* cg_type_get(Compiler* c, CfreeCgTypeId id) {
+ u32 seg;
+ u32 off;
+ CgApiState* s;
+ CgApiType* e;
+ if (!c || id == CFREE_CG_TYPE_NONE) return NULL;
+ seg = id >> CG_API_TYPE_SEG_SHIFT;
+ off = id & CG_API_TYPE_SEG_MASK;
+ if (seg == CG_API_TYPE_BUILTIN_SEG) {
+ if (off >= CFREE_CG_BUILTIN_COUNT) return NULL;
+ s = cg_api_get(c);
+ if (!s) return NULL;
+ cg_api_init_builtins(c, s);
+ return &s->builtins[off];
+ }
+ e = api_type_from_id(c, id);
+ return e ? &e->cg : NULL;
+}
+
+uint64_t cg_type_size(Compiler* c, CfreeCgTypeId id) {
+ const CgType* ty = cg_type_get(c, id);
+ return ty ? ty->size : 0;
+}
+
+uint32_t cg_type_align(Compiler* c, CfreeCgTypeId id) {
+ const CgType* ty = cg_type_get(c, id);
+ return ty ? ty->align : 0;
+}
+
+int cg_type_is_int(Compiler* c, CfreeCgTypeId id) {
+ const CgType* ty = cg_type_get(c, id);
+ if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) {
+ return cg_type_is_int(c, ty->alias.base);
+ }
+ return ty && (ty->kind == CFREE_CG_TYPE_INT ||
+ ty->kind == CFREE_CG_TYPE_BOOL ||
+ ty->kind == CFREE_CG_TYPE_ENUM);
+}
+
+int cg_type_is_float(Compiler* c, CfreeCgTypeId id) {
+ const CgType* ty = cg_type_get(c, id);
+ if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) {
+ return cg_type_is_float(c, ty->alias.base);
+ }
+ return ty && ty->kind == CFREE_CG_TYPE_FLOAT;
+}
+
+int cg_type_is_ptr(Compiler* c, CfreeCgTypeId id) {
+ const CgType* ty = cg_type_get(c, id);
+ if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) {
+ return cg_type_is_ptr(c, ty->alias.base);
+ }
+ return ty && ty->kind == CFREE_CG_TYPE_PTR;
+}
+
+int cg_type_is_record(Compiler* c, CfreeCgTypeId id) {
+ const CgType* ty = cg_type_get(c, id);
+ if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) {
+ return cg_type_is_record(c, ty->alias.base);
+ }
+ return ty && ty->kind == CFREE_CG_TYPE_RECORD;
+}
+
static CgApiType* type_alloc(Compiler* c, CfreeCgTypeId* id_out) {
CgApiState* s = cg_api_get(c);
CgApiType* e;
@@ -243,6 +484,167 @@ static CfreeCgParam* copy_cg_params(Compiler* c, const CfreeCgParam* src,
return dst;
}
+static CgTypeField* copy_cg_fields(Compiler* c, const CfreeCgField* src,
+ u32 n) {
+ CgTypeField* dst;
+ if (!n) return NULL;
+ if (!src) return NULL;
+ dst = arena_array(&c->global->arena, CgTypeField, n);
+ if (!dst) return NULL;
+ memset(dst, 0, sizeof(*dst) * n);
+ for (u32 i = 0; i < n; ++i) {
+ dst[i].name = src[i].name;
+ dst[i].type = src[i].type;
+ dst[i].align_override = src[i].align_override;
+ }
+ return dst;
+}
+
+static int cg_type_layout_record(Compiler* c, CgType* cg) {
+ u32 max_align = 1;
+ u64 size = 0;
+ if (!c || !cg || cg->kind != CFREE_CG_TYPE_RECORD) return 0;
+ if (cg->record.nfields && !cg->record.fields) return 0;
+ if (cg->record.is_union) {
+ for (u32 i = 0; i < cg->record.nfields; ++i) {
+ CgTypeField* f = &cg->record.fields[i];
+ u64 fsize = cg_type_size(c, f->type);
+ u32 falign = cg_type_align(c, f->type);
+ if (!falign) return 0;
+ if (f->align_override == 1u) {
+ falign = 1;
+ } else if (f->align_override > falign) {
+ falign = f->align_override;
+ }
+ if (falign > max_align) max_align = falign;
+ if (fsize > size) size = fsize;
+ f->offset = 0;
+ }
+ } else {
+ u64 off = 0;
+ for (u32 i = 0; i < cg->record.nfields; ++i) {
+ CgTypeField* f = &cg->record.fields[i];
+ u64 fsize = cg_type_size(c, f->type);
+ u32 falign = cg_type_align(c, f->type);
+ if (!falign) return 0;
+ if (f->align_override == 1u) {
+ falign = 1;
+ } else if (f->align_override > falign) {
+ falign = f->align_override;
+ }
+ if (falign > max_align) max_align = falign;
+ off = cg_align_to(off, falign);
+ f->offset = off;
+ off += fsize;
+ }
+ size = off;
+ }
+ if (cg->record.align_override > max_align) {
+ max_align = cg->record.align_override;
+ }
+ cg->align = max_align;
+ cg->size = cg_align_to(size, max_align);
+ return 1;
+}
+
+static int cg_type_set_ptr(Compiler* c, CgApiType* e, CfreeCgTypeId pointee,
+ u32 address_space) {
+ u32 ptr_size;
+ u32 ptr_align;
+ if (!cg_type_get(c, pointee)) return 0;
+ memset(&e->cg, 0, sizeof(e->cg));
+ ptr_size = c->target.ptr_size ? c->target.ptr_size : 8;
+ ptr_align = c->target.ptr_align ? c->target.ptr_align : ptr_size;
+ e->cg.kind = CFREE_CG_TYPE_PTR;
+ e->cg.size = ptr_size;
+ e->cg.align = ptr_align;
+ e->cg.ptr.pointee = pointee;
+ e->cg.ptr.address_space = address_space;
+ return 1;
+}
+
+static int cg_type_set_array(Compiler* c, CgApiType* e, CfreeCgTypeId elem,
+ u64 count) {
+ const CgType* ety = cg_type_get(c, elem);
+ if (!ety) return 0;
+ memset(&e->cg, 0, sizeof(e->cg));
+ e->cg.kind = CFREE_CG_TYPE_ARRAY;
+ e->cg.size = ety->size * count;
+ e->cg.align = ety->align;
+ e->cg.array.elem = elem;
+ e->cg.array.count = count;
+ return 1;
+}
+
+static int cg_type_set_alias(Compiler* c, CgApiType* e, CfreeSym name,
+ CfreeCgTypeId base) {
+ const CgType* bty = cg_type_get(c, base);
+ if (!bty) return 0;
+ memset(&e->cg, 0, sizeof(e->cg));
+ e->cg.kind = CFREE_CG_TYPE_ALIAS;
+ e->cg.size = bty->size;
+ e->cg.align = bty->align;
+ e->cg.alias.name = name;
+ e->cg.alias.base = base;
+ return 1;
+}
+
+static int cg_type_set_record(Compiler* c, CgApiType* e, CfreeSym tag,
+ const CfreeCgField* fields, u32 nfields,
+ int is_union, u32 align_override, u32 flags) {
+ CgTypeField* copied = copy_cg_fields(c, fields, nfields);
+ if (nfields && !copied) return 0;
+ memset(&e->cg, 0, sizeof(e->cg));
+ e->cg.kind = CFREE_CG_TYPE_RECORD;
+ e->cg.record.tag = tag;
+ e->cg.record.fields = copied;
+ e->cg.record.nfields = nfields;
+ e->cg.record.is_union = is_union != 0;
+ e->cg.record.align_override = align_override;
+ e->cg.record.flags = flags;
+ return cg_type_layout_record(c, &e->cg);
+}
+
+static int cg_type_set_enum(Compiler* c, CgApiType* e, CfreeSym tag,
+ CfreeCgTypeId base, CfreeCgEnumValue* values,
+ u32 nvalues) {
+ const CgType* bty;
+ if (base == CFREE_CG_TYPE_NONE) base = builtin_id(CFREE_CG_BUILTIN_I32);
+ bty = cg_type_get(c, base);
+ if (!bty || !(bty->kind == CFREE_CG_TYPE_INT ||
+ bty->kind == CFREE_CG_TYPE_BOOL)) {
+ return 0;
+ }
+ memset(&e->cg, 0, sizeof(e->cg));
+ e->cg.kind = CFREE_CG_TYPE_ENUM;
+ e->cg.size = bty->size;
+ e->cg.align = bty->align;
+ e->cg.enum_.tag = tag;
+ e->cg.enum_.base = base;
+ e->cg.enum_.values = values;
+ e->cg.enum_.nvalues = nvalues;
+ return 1;
+}
+
+static int cg_type_set_func(Compiler* c, CgApiType* e, CfreeCgFuncSig sig,
+ CfreeCgParam* params) {
+ if (!cg_type_get(c, sig.ret)) return 0;
+ for (u32 i = 0; i < sig.nparams; ++i) {
+ if (!cg_type_get(c, sig.params[i].type)) return 0;
+ }
+ memset(&e->cg, 0, sizeof(e->cg));
+ e->cg.kind = CFREE_CG_TYPE_FUNC;
+ e->cg.size = 1;
+ e->cg.align = 1;
+ e->cg.func.ret = sig.ret;
+ e->cg.func.params = params;
+ e->cg.func.nparams = sig.nparams;
+ e->cg.func.call_conv = sig.call_conv;
+ e->cg.func.abi_variadic = sig.abi_variadic != 0;
+ e->cg.func.ret_attrs = sig.ret_attrs;
+ return 1;
+}
+
CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler* c) {
CfreeCgBuiltinTypes out;
(void)c;
@@ -267,7 +669,10 @@ CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee,
e->base = pointee;
e->address_space = address_space;
e->kind = CG_API_TYPE_PTR;
- return e->type ? id : CFREE_CG_TYPE_NONE;
+ if (!e->type || !cg_type_set_ptr(c, e, pointee, address_space)) {
+ return CFREE_CG_TYPE_NONE;
+ }
+ return id;
}
CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem,
@@ -284,7 +689,10 @@ CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem,
e->base = elem;
e->array_count = count;
e->kind = CG_API_TYPE_ARRAY;
- return e->type ? id : CFREE_CG_TYPE_NONE;
+ if (!e->type || !cg_type_set_array(c, e, elem, count)) {
+ return CFREE_CG_TYPE_NONE;
+ }
+ return id;
}
CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name,
@@ -299,7 +707,7 @@ CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name,
e->base = base;
e->name = name;
e->kind = CG_API_TYPE_ALIAS;
- return id;
+ return cg_type_set_alias(c, e, name, base) ? id : CFREE_CG_TYPE_NONE;
}
CfreeCgTypeId cfree_cg_type_record(CfreeCompiler* c, CfreeSym tag,
@@ -344,7 +752,10 @@ CfreeCgTypeId cfree_cg_type_record(CfreeCompiler* c, CfreeSym tag,
e->count = nfields;
e->fields = copied;
e->kind = CG_API_TYPE_RECORD;
- return e->type ? id : CFREE_CG_TYPE_NONE;
+ if (!e->type || !cg_type_set_record(c, e, tag, fields, nfields, 0, 0, 0)) {
+ return CFREE_CG_TYPE_NONE;
+ }
+ return id;
}
CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler* c, CfreeSym tag,
@@ -375,7 +786,10 @@ CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler* c, CfreeSym tag,
e->count = nvalues;
e->values = copied;
e->kind = CG_API_TYPE_ENUM;
- return e->type ? id : CFREE_CG_TYPE_NONE;
+ if (!e->type || !cg_type_set_enum(c, e, tag, base, copied, nvalues)) {
+ return CFREE_CG_TYPE_NONE;
+ }
+ return id;
}
CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgFuncSig sig) {
@@ -423,7 +837,10 @@ CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgFuncSig sig) {
e->call_conv = sig.call_conv;
e->abi_variadic = sig.abi_variadic != 0;
e->kind = CG_API_TYPE_FUNC;
- return e->type ? id : CFREE_CG_TYPE_NONE;
+ if (!e->type || !cg_type_set_func(c, e, sig, copied)) {
+ return CFREE_CG_TYPE_NONE;
+ }
+ return id;
}
CfreeCgTypeId cg_api_type_import(Compiler* c, const Type* ty) {
@@ -478,33 +895,84 @@ CfreeCgTypeId cg_api_type_import(Compiler* c, const Type* ty) {
case TY_PTR:
e->base = cg_api_type_import(c, ty->ptr.pointee);
e->kind = CG_API_TYPE_PTR;
+ if (!cg_type_set_ptr(c, e, e->base, 0)) return CFREE_CG_TYPE_NONE;
break;
case TY_ARRAY:
e->base = cg_api_type_import(c, ty->arr.elem);
e->array_count = ty->arr.count;
e->kind = CG_API_TYPE_ARRAY;
+ if (!cg_type_set_array(c, e, e->base, e->array_count)) {
+ return CFREE_CG_TYPE_NONE;
+ }
break;
- case TY_FUNC:
+ case TY_FUNC: {
+ CfreeCgParam* params = NULL;
+ CfreeCgFuncSig sig;
e->base = cg_api_type_import(c, ty->fn.ret);
e->count = ty->fn.nparams;
e->abi_variadic = ty->fn.variadic;
e->call_conv = CFREE_CG_CC_TARGET_C;
e->kind = CG_API_TYPE_FUNC;
+ memset(&sig, 0, sizeof(sig));
+ sig.ret = e->base;
+ sig.nparams = ty->fn.nparams;
+ sig.abi_variadic = ty->fn.variadic;
+ sig.call_conv = CFREE_CG_CC_TARGET_C;
+ if (ty->fn.nparams) {
+ params = arena_zarray(&c->global->arena, CfreeCgParam, ty->fn.nparams);
+ if (!params) return CFREE_CG_TYPE_NONE;
+ for (u32 i = 0; i < ty->fn.nparams; ++i) {
+ params[i].type = cg_api_type_import(c, ty->fn.params[i]);
+ if (params[i].type == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE;
+ }
+ }
+ sig.params = params;
+ e->params = params;
+ if (!cg_type_set_func(c, e, sig, params)) return CFREE_CG_TYPE_NONE;
break;
+ }
case TY_STRUCT:
- case TY_UNION:
+ case TY_UNION: {
+ CfreeCgField* fields = NULL;
e->name = ty->rec.tag;
e->count = ty->rec.nfields;
e->kind = CG_API_TYPE_RECORD;
+ e->cg.kind = CFREE_CG_TYPE_RECORD;
+ if (ty->rec.nfields) {
+ fields = arena_zarray(&c->global->arena, CfreeCgField, ty->rec.nfields);
+ if (!fields) return CFREE_CG_TYPE_NONE;
+ for (u32 i = 0; i < ty->rec.nfields; ++i) {
+ const Field* f = &ty->rec.fields[i];
+ fields[i].name = f->name;
+ fields[i].type = cg_api_type_import(c, f->type);
+ if (fields[i].type == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE;
+ fields[i].align_override =
+ (ty->rec.packed || f->packed) ? 1u : f->align_override;
+ }
+ }
+ e->fields = fields;
+ if (!cg_type_set_record(c, e, ty->rec.tag, fields, ty->rec.nfields,
+ ty->kind == TY_UNION, ty->rec.align_override,
+ 0)) {
+ return CFREE_CG_TYPE_NONE;
+ }
break;
+ }
case TY_ENUM:
e->name = ty->enm.tag;
e->base = cg_api_type_import(c, ty->enm.base);
e->kind = CG_API_TYPE_ENUM;
+ if (!cg_type_set_enum(c, e, ty->enm.tag, e->base, NULL, 0)) {
+ return CFREE_CG_TYPE_NONE;
+ }
break;
default:
+ {
+ CfreeCgTypeId base_id = builtin_id_from_type_kind((TypeKind)ty->kind);
e->kind = CG_API_TYPE_ALIAS;
+ if (!cg_type_set_alias(c, e, 0, base_id)) return CFREE_CG_TYPE_NONE;
break;
+ }
}
return id;
}
@@ -514,149 +982,128 @@ const Type* cg_api_type_resolve(Compiler* c, CfreeCgTypeId id) {
}
uint64_t cfree_cg_type_size(CfreeCompiler* c, CfreeCgTypeId id) {
- const Type* ty = resolve_type(c, id);
- return ty ? (uint64_t)abi_sizeof(c->abi, ty) : 0;
+ return cg_type_size(c, id);
}
uint32_t cfree_cg_type_align(CfreeCompiler* c, CfreeCgTypeId id) {
- const Type* ty = resolve_type(c, id);
- return ty ? (uint32_t)abi_alignof(c->abi, ty) : 0;
-}
-
-static CfreeCgTypeKind api_type_kind_from_type(const Type* ty) {
- if (!ty) return CFREE_CG_TYPE_VOID;
- switch (ty->kind) {
- case TY_VOID:
- return CFREE_CG_TYPE_VOID;
- case TY_BOOL:
- return CFREE_CG_TYPE_BOOL;
- case TY_FLOAT:
- case TY_DOUBLE:
- case TY_LDOUBLE:
- return CFREE_CG_TYPE_FLOAT;
- case TY_PTR:
- return CFREE_CG_TYPE_PTR;
- case TY_ARRAY:
- return CFREE_CG_TYPE_ARRAY;
- case TY_FUNC:
- return CFREE_CG_TYPE_FUNC;
- case TY_STRUCT:
- case TY_UNION:
- return CFREE_CG_TYPE_RECORD;
- case TY_ENUM:
- return CFREE_CG_TYPE_ENUM;
- default:
- return type_is_int(ty) ? CFREE_CG_TYPE_INT : CFREE_CG_TYPE_VOID;
- }
+ return cg_type_align(c, id);
}
CfreeCgTypeKind cfree_cg_type_kind(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- if (e) {
- if (e->kind == CG_API_TYPE_ALIAS) return CFREE_CG_TYPE_ALIAS;
- if (e->kind == CG_API_TYPE_PTR) return CFREE_CG_TYPE_PTR;
- if (e->kind == CG_API_TYPE_ARRAY) return CFREE_CG_TYPE_ARRAY;
- if (e->kind == CG_API_TYPE_FUNC) return CFREE_CG_TYPE_FUNC;
- if (e->kind == CG_API_TYPE_RECORD) return CFREE_CG_TYPE_RECORD;
- if (e->kind == CG_API_TYPE_ENUM) return CFREE_CG_TYPE_ENUM;
- }
- if (id == builtin_id(CFREE_CG_BUILTIN_VARARG_STATE)) {
- return CFREE_CG_TYPE_VARARG_STATE;
- }
- return api_type_kind_from_type(resolve_type(c, id));
+ const CgType* ty = cg_type_get(c, id);
+ return ty ? ty->kind : CFREE_CG_TYPE_VOID;
}
uint32_t cfree_cg_type_int_width(CfreeCompiler* c, CfreeCgTypeId id) {
- const Type* ty = resolve_type(c, id);
- return (ty && type_is_int(ty)) ? (uint32_t)abi_sizeof(c->abi, ty) * 8u : 0u;
+ const CgType* ty = cg_type_get(c, id);
+ if (!ty) return 0;
+ if (ty->kind == CFREE_CG_TYPE_INT || ty->kind == CFREE_CG_TYPE_BOOL) {
+ return ty->integer.width;
+ }
+ if (ty->kind == CFREE_CG_TYPE_ENUM) {
+ return (uint32_t)ty->size * 8u;
+ }
+ if (ty->kind == CFREE_CG_TYPE_ALIAS) {
+ return cfree_cg_type_int_width(c, ty->alias.base);
+ }
+ return 0;
}
uint32_t cfree_cg_type_float_width(CfreeCompiler* c, CfreeCgTypeId id) {
- const Type* ty = resolve_type(c, id);
+ const CgType* ty = cg_type_get(c, id);
if (!ty) return 0;
- if (ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE || ty->kind == TY_LDOUBLE) {
- return (uint32_t)abi_sizeof(c->abi, ty) * 8u;
+ if (ty->kind == CFREE_CG_TYPE_FLOAT) return ty->fp.width;
+ if (ty->kind == CFREE_CG_TYPE_ALIAS) {
+ return cfree_cg_type_float_width(c, ty->alias.base);
}
return 0;
}
CfreeCgTypeId cfree_cg_type_ptr_pointee(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_PTR) ? e->base : CFREE_CG_TYPE_NONE;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_PTR) ? ty->ptr.pointee
+ : CFREE_CG_TYPE_NONE;
}
CfreeCgTypeId cfree_cg_type_array_elem(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_ARRAY) ? e->base : CFREE_CG_TYPE_NONE;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_ARRAY) ? ty->array.elem
+ : CFREE_CG_TYPE_NONE;
}
uint32_t cfree_cg_type_ptr_address_space(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_PTR) ? e->address_space : 0u;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_PTR) ? ty->ptr.address_space : 0u;
}
uint64_t cfree_cg_type_array_count(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_ARRAY) ? e->array_count : 0u;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_ARRAY) ? ty->array.count : 0u;
}
CfreeCgTypeId cfree_cg_type_func_ret(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_FUNC) ? e->base : CFREE_CG_TYPE_NONE;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.ret
+ : CFREE_CG_TYPE_NONE;
}
uint32_t cfree_cg_type_func_nparams(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_FUNC) ? e->count : 0;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.nparams : 0;
}
CfreeCgAbiAttrs cfree_cg_type_func_ret_attrs(CfreeCompiler* c,
CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
+ const CgType* ty = cg_type_get(c, id);
CfreeCgAbiAttrs empty;
memset(&empty, 0, sizeof(empty));
- return (e && e->kind == CG_API_TYPE_FUNC) ? e->ret_attrs : empty;
+ return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.ret_attrs : empty;
}
CfreeCgParam cfree_cg_type_func_param(CfreeCompiler* c, CfreeCgTypeId id,
uint32_t index) {
- CgApiType* e = api_type_from_id(c, id);
+ const CgType* ty = cg_type_get(c, id);
CfreeCgParam empty;
memset(&empty, 0, sizeof(empty));
- if (!e || e->kind != CG_API_TYPE_FUNC || index >= e->count) return empty;
- return e->params[index];
+ if (!ty || ty->kind != CFREE_CG_TYPE_FUNC || index >= ty->func.nparams) {
+ return empty;
+ }
+ return ty->func.params[index];
}
CfreeCgCallConv cfree_cg_type_func_call_conv(CfreeCompiler* c,
CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_FUNC) ? e->call_conv
- : CFREE_CG_CC_TARGET_C;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.call_conv
+ : CFREE_CG_CC_TARGET_C;
}
int cfree_cg_type_func_is_variadic(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return e && e->kind == CG_API_TYPE_FUNC && e->abi_variadic;
+ const CgType* ty = cg_type_get(c, id);
+ return ty && ty->kind == CFREE_CG_TYPE_FUNC && ty->func.abi_variadic;
}
uint32_t cfree_cg_type_record_nfields(CfreeCompiler* c, CfreeCgTypeId id) {
- CgApiType* e = api_type_from_id(c, id);
- return (e && e->kind == CG_API_TYPE_RECORD) ? e->count : 0;
+ const CgType* ty = cg_type_get(c, id);
+ return (ty && ty->kind == CFREE_CG_TYPE_RECORD) ? ty->record.nfields : 0;
}
int cfree_cg_type_record_field(CfreeCompiler* c, CfreeCgTypeId id,
uint32_t index, CfreeCgField* out,
uint64_t* offset_out) {
- CgApiType* e = api_type_from_id(c, id);
- const ABIRecordLayout* layout;
- if (!e || e->kind != CG_API_TYPE_RECORD || index >= e->count) return 1;
- if (out) *out = e->fields[index];
- if (offset_out) {
- layout = abi_record_layout(c->abi, e->type);
- *offset_out = (layout && index < layout->nfields)
- ? (uint64_t)layout->fields[index].offset
- : 0u;
+ const CgType* ty = cg_type_get(c, id);
+ const CgTypeField* f;
+ if (!ty || ty->kind != CFREE_CG_TYPE_RECORD ||
+ index >= ty->record.nfields) {
+ return 1;
+ }
+ f = &ty->record.fields[index];
+ if (out) {
+ out->name = f->name;
+ out->type = f->type;
+ out->align_override = f->align_override;
}
+ if (offset_out) *offset_out = f->offset;
return 0;
}
diff --git a/src/api/cg_api.h b/src/api/cg_api.h
@@ -8,6 +8,7 @@
typedef struct CGTarget CGTarget;
typedef struct MCEmitter MCEmitter;
+typedef struct CgType CgType;
typedef uint32_t ObjSymId;
enum {
@@ -20,6 +21,13 @@ enum {
const Type* cg_api_type_resolve(Compiler*, CfreeCgTypeId);
CfreeCgTypeId cg_api_type_import(Compiler*, const Type*);
+const CgType* cg_type_get(Compiler*, CfreeCgTypeId);
+uint64_t cg_type_size(Compiler*, CfreeCgTypeId);
+uint32_t cg_type_align(Compiler*, CfreeCgTypeId);
+int cg_type_is_int(Compiler*, CfreeCgTypeId);
+int cg_type_is_float(Compiler*, CfreeCgTypeId);
+int cg_type_is_ptr(Compiler*, CfreeCgTypeId);
+int cg_type_is_record(Compiler*, CfreeCgTypeId);
Compiler* cfree_cg_internal_compiler(CfreeCg*);
CGTarget* cfree_cg_internal_target(CfreeCg*);
MCEmitter* cfree_cg_internal_mc(CfreeCg*);
diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c
@@ -61,14 +61,16 @@ int main(void) {
CfreeCgTypeId va_list_ty;
CfreeCgTypeId ptr_i32;
CfreeCgTypeId array_i32;
- CfreeCgTypeId params[2];
+ CfreeCgParam params[2];
+ CfreeCgFuncSig sig;
CfreeCgTypeId fn;
CfreeCgTypeId alias;
- CfreeCgTypeId qual;
CfreeCgTypeId rec;
CfreeCgTypeId enm;
CfreeCgField fields[2];
+ CfreeCgField field_out;
CfreeCgEnumValue vals[2];
+ uint64_t field_off;
memset(&target, 0, sizeof(target));
target.arch = CFREE_ARCH_ARM_64;
@@ -103,29 +105,32 @@ int main(void) {
EXPECT(va_list_ty != CFREE_CG_TYPE_NONE, "va_list builtin id is none");
EXPECT(void_ty != i32_ty && i32_ty != f64_ty, "builtin ids collide");
- ptr_i32 = cfree_cg_type_ptr(c, i32_ty);
+ ptr_i32 = cfree_cg_type_ptr(c, i32_ty, 0);
array_i32 = cfree_cg_type_array(c, i32_ty, 4);
EXPECT(ptr_i32 != CFREE_CG_TYPE_NONE, "ptr type failed");
EXPECT(array_i32 != CFREE_CG_TYPE_NONE, "array type failed");
- EXPECT(cfree_cg_type_ptr(c, i32_ty) == ptr_i32,
+ EXPECT(cfree_cg_type_ptr(c, i32_ty, 0) == ptr_i32,
"ptr type id should be interned");
EXPECT(cfree_cg_type_array(c, i32_ty, 4) == array_i32,
"array type id should be interned");
- EXPECT(cfree_cg_type_ptr(c, CFREE_CG_TYPE_NONE) == CFREE_CG_TYPE_NONE,
+ EXPECT(cfree_cg_type_ptr(c, CFREE_CG_TYPE_NONE, 0) == CFREE_CG_TYPE_NONE,
"invalid pointer pointee should fail");
+ EXPECT(cfree_cg_type_size(c, ptr_i32) == 8, "ptr size mismatch");
+ EXPECT(cfree_cg_type_align(c, ptr_i32) == 8, "ptr align mismatch");
+ EXPECT(cfree_cg_type_ptr_pointee(c, ptr_i32) == i32_ty,
+ "ptr pointee mismatch");
+ EXPECT(cfree_cg_type_array_elem(c, array_i32) == i32_ty,
+ "array elem mismatch");
+ EXPECT(cfree_cg_type_array_count(c, array_i32) == 4,
+ "array count mismatch");
alias = cfree_cg_type_alias(c, cfree_sym_intern(c, "I"), i32_ty);
- qual = cfree_cg_type_qualified(c, alias, CFREE_CG_TQ_CONST);
EXPECT(alias != CFREE_CG_TYPE_NONE && alias != i32_ty,
"alias id should be fresh");
- EXPECT(qual != CFREE_CG_TYPE_NONE && qual != alias,
- "qualified type failed");
- EXPECT(cfree_cg_type_qualified(c, alias, CFREE_CG_TQ_CONST) == qual,
- "qualified type id should be interned");
- EXPECT(cfree_cg_type_qualified(c, alias, 0) == alias,
- "zero qualifiers should return base id");
- EXPECT(cfree_cg_type_qualified(c, alias, 1u << 12) == CFREE_CG_TYPE_NONE,
- "unknown qualifier bit should fail");
+ EXPECT(cfree_cg_type_kind(c, alias) == CFREE_CG_TYPE_ALIAS,
+ "alias kind mismatch");
+ EXPECT(cfree_cg_type_size(c, alias) == cfree_cg_type_size(c, i32_ty),
+ "alias size mismatch");
fields[0].name = cfree_sym_intern(c, "a");
fields[0].type = i32_ty;
@@ -138,6 +143,15 @@ int main(void) {
EXPECT(cfree_cg_type_record(c, cfree_sym_intern(c, "Bad"), fields, 0) !=
CFREE_CG_TYPE_NONE,
"empty record type failed");
+ EXPECT(cfree_cg_type_kind(c, rec) == CFREE_CG_TYPE_RECORD,
+ "record kind mismatch");
+ EXPECT(cfree_cg_type_record_nfields(c, rec) == 2,
+ "record field count mismatch");
+ EXPECT(cfree_cg_type_record_field(c, rec, 1, &field_out, &field_off) == 0,
+ "record field query failed");
+ EXPECT(field_out.name == fields[1].name && field_out.type == ptr_i32,
+ "record field data mismatch");
+ EXPECT(field_off == 4, "record field offset mismatch");
vals[0].name = cfree_sym_intern(c, "A");
vals[0].value = 1;
@@ -147,13 +161,26 @@ int main(void) {
vals, 2);
EXPECT(enm != CFREE_CG_TYPE_NONE, "enum type failed");
- params[0] = i32_ty;
- params[1] = ptr_i32;
- fn = cfree_cg_type_func(c, i64_ty, params, 2, 1);
+ memset(params, 0, sizeof(params));
+ params[0].type = i32_ty;
+ params[1].type = ptr_i32;
+ memset(&sig, 0, sizeof(sig));
+ sig.ret = i64_ty;
+ sig.params = params;
+ sig.nparams = 2;
+ sig.abi_variadic = 1;
+ sig.call_conv = CFREE_CG_CC_TARGET_C;
+ fn = cfree_cg_type_func(c, sig);
EXPECT(fn != CFREE_CG_TYPE_NONE, "function type failed");
- EXPECT(cfree_cg_type_func(c, i64_ty, params, 2, 1) == fn,
+ EXPECT(cfree_cg_type_func(c, sig) == fn,
"function type id should be interned");
- EXPECT(cfree_cg_type_func(c, i64_ty, params, 70000, 0) == CFREE_CG_TYPE_NONE,
+ EXPECT(cfree_cg_type_func_ret(c, fn) == i64_ty, "function return mismatch");
+ EXPECT(cfree_cg_type_func_nparams(c, fn) == 2,
+ "function param count mismatch");
+ EXPECT(cfree_cg_type_func_param(c, fn, 1).type == ptr_i32,
+ "function param mismatch");
+ sig.nparams = 70000;
+ EXPECT(cfree_cg_type_func(c, sig) == CFREE_CG_TYPE_NONE,
"oversized function param list should fail");
cfree_compiler_free(c);