kit

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

commit 13cc44e82229698acad65407f1cfb9b525ac6ebd
parent e37202a809c3df4009250b2820d444be4817a61f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 12 May 2026 17:12:43 -0700

cg type allocator

Diffstat:
Minclude/cfree/cg.h | 18++++++++++++++++++
Asrc/api/cg.c | 390+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/api/cg_api.h | 20++++++++++++++++++++
Msrc/core/core.c | 5+++++
Msrc/core/core.h | 3++-
Atest/api/cg_type_test.c | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/test.mk | 10+++++++++-
7 files changed, 584 insertions(+), 2 deletions(-)

diff --git a/include/cfree/cg.h b/include/cfree/cg.h @@ -15,6 +15,24 @@ typedef uint32_t CfreeCgTypeId; #define CFREE_CG_SCOPE_NONE 0u #define CFREE_CG_TYPE_NONE 0u +typedef enum CfreeCgBuiltinType { + CFREE_CG_BUILTIN_VOID, + CFREE_CG_BUILTIN_BOOL, + CFREE_CG_BUILTIN_I8, + CFREE_CG_BUILTIN_U8, + CFREE_CG_BUILTIN_I16, + CFREE_CG_BUILTIN_U16, + CFREE_CG_BUILTIN_I32, + CFREE_CG_BUILTIN_U32, + CFREE_CG_BUILTIN_I64, + CFREE_CG_BUILTIN_U64, + CFREE_CG_BUILTIN_ISIZE, + CFREE_CG_BUILTIN_USIZE, + CFREE_CG_BUILTIN_F32, + CFREE_CG_BUILTIN_F64, + CFREE_CG_BUILTIN_COUNT, +} CfreeCgBuiltinType; + typedef struct CfreeCgBuiltinTypes { CfreeCgTypeId void_; CfreeCgTypeId bool_; diff --git a/src/api/cg.c b/src/api/cg.c @@ -0,0 +1,390 @@ +#include <cfree/cg.h> +#include <stdint.h> +#include <string.h> + +#include "api/cg_api.h" +#include "core/arena.h" +#include "core/heap.h" +#include "core/segvec.h" +#include "type/type.h" + +typedef enum CgApiTypeKind { + CG_API_TYPE_PTR, + CG_API_TYPE_ARRAY, + CG_API_TYPE_QUALIFIED, + CG_API_TYPE_ALIAS, + CG_API_TYPE_RECORD, + CG_API_TYPE_ENUM, + CG_API_TYPE_FUNC, +} CgApiTypeKind; + +typedef struct CgApiType { + const Type* type; + CfreeCgTypeId base; + CfreeSym name; + u32 count; + u32 flags; + const CfreeCgField* fields; + const CfreeCgEnumValue* values; + const CfreeCgTypeId* params; + u8 kind; + u8 is_union; + u8 pad[2]; +} CgApiType; + +SEGVEC_DEFINE(CgApiTypes, CgApiType, CG_API_TYPE_SEG_SHIFT); + +typedef struct CgApiState { + Heap* heap; + CgApiTypes types; +} CgApiState; + +static CfreeCgTypeId type_id_from_tuple(u32 seg, u32 index) { + return (CfreeCgTypeId)((seg << CG_API_TYPE_SEG_SHIFT) | + (index & CG_API_TYPE_SEG_MASK)); +} + +static CfreeCgTypeId builtin_id(CfreeCgBuiltinType t) { + return type_id_from_tuple(CG_API_TYPE_BUILTIN_SEG, (u32)t); +} + +static int decode_user_id(CfreeCgTypeId id, u32* index_out) { + u32 seg = id >> CG_API_TYPE_SEG_SHIFT; + u32 off = id & CG_API_TYPE_SEG_MASK; + if (seg < CG_API_TYPE_USER_SEG_BIAS) return 0; + *index_out = + ((seg - CG_API_TYPE_USER_SEG_BIAS) << CG_API_TYPE_SEG_SHIFT) | off; + return 1; +} + +static CfreeCgTypeId user_id_from_index(u32 index) { + u32 raw_seg = index >> CG_API_TYPE_SEG_SHIFT; + u32 off = index & CG_API_TYPE_SEG_MASK; + u32 seg_limit = UINT32_MAX >> CG_API_TYPE_SEG_SHIFT; + if (raw_seg > seg_limit - CG_API_TYPE_USER_SEG_BIAS) { + return CFREE_CG_TYPE_NONE; + } + return type_id_from_tuple(raw_seg + CG_API_TYPE_USER_SEG_BIAS, off); +} + +static const Type* builtin_type(Compiler* c, CfreeCgBuiltinType t) { + switch (t) { + case CFREE_CG_BUILTIN_VOID: + return type_void(c->global); + case CFREE_CG_BUILTIN_BOOL: + return type_prim(c->global, TY_BOOL); + case CFREE_CG_BUILTIN_I8: + return type_prim(c->global, TY_SCHAR); + case CFREE_CG_BUILTIN_U8: + return type_prim(c->global, TY_UCHAR); + case CFREE_CG_BUILTIN_I16: + return type_prim(c->global, TY_SHORT); + case CFREE_CG_BUILTIN_U16: + return type_prim(c->global, TY_USHORT); + case CFREE_CG_BUILTIN_I32: + return type_prim(c->global, TY_INT); + case CFREE_CG_BUILTIN_U32: + return type_prim(c->global, TY_UINT); + case CFREE_CG_BUILTIN_I64: + return type_prim(c->global, TY_LLONG); + case CFREE_CG_BUILTIN_U64: + return type_prim(c->global, TY_ULLONG); + case CFREE_CG_BUILTIN_ISIZE: + return c->target.ptr_size == 8 ? type_prim(c->global, TY_LLONG) + : type_prim(c->global, TY_INT); + case CFREE_CG_BUILTIN_USIZE: + return c->target.ptr_size == 8 ? type_prim(c->global, TY_ULLONG) + : type_prim(c->global, TY_UINT); + case CFREE_CG_BUILTIN_F32: + return type_prim(c->global, TY_FLOAT); + case CFREE_CG_BUILTIN_F64: + return type_prim(c->global, TY_DOUBLE); + case CFREE_CG_BUILTIN_COUNT: + return NULL; + } + return NULL; +} + +static CgApiState* cg_api_get(Compiler* c) { + Heap* h; + CgApiState* s; + if (!c) return NULL; + if (c->cg_api) return (CgApiState*)c->cg_api; + h = (Heap*)c->env->heap; + s = (CgApiState*)h->alloc(h, sizeof(*s), _Alignof(CgApiState)); + if (!s) return NULL; + memset(s, 0, sizeof(*s)); + s->heap = h; + CgApiTypes_init(&s->types, h); + c->cg_api = s; + c->cg_api_free = cg_api_fini; + return s; +} + +static CgApiType* type_alloc(Compiler* c, CfreeCgTypeId* id_out) { + CgApiState* s = cg_api_get(c); + CgApiType* e; + u32 index; + if (!s) return NULL; + e = CgApiTypes_push(&s->types, &index); + if (!e) return NULL; + *id_out = user_id_from_index(index); + if (*id_out == CFREE_CG_TYPE_NONE) return NULL; + return e; +} + +static const Type* resolve_type(Compiler* c, CfreeCgTypeId id) { + u32 seg; + u32 off; + u32 index; + 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; + return builtin_type(c, (CfreeCgBuiltinType)off); + } + if (!decode_user_id(id, &index)) return NULL; + s = (CgApiState*)c->cg_api; + if (!s) return NULL; + e = CgApiTypes_at(&s->types, index); + return e ? e->type : NULL; +} + +static u16 quals_to_internal(u32 quals) { + u16 q = 0; + if (quals & CFREE_CG_TQ_CONST) q |= Q_CONST; + if (quals & CFREE_CG_TQ_VOLATILE) q |= Q_VOLATILE; + if (quals & CFREE_CG_TQ_RESTRICT) q |= Q_RESTRICT; + return q; +} + +static CfreeCgTypeId* copy_type_ids(Compiler* c, const CfreeCgTypeId* src, + u32 n) { + CfreeCgTypeId* dst; + if (!n) return NULL; + if (!src) return NULL; + dst = arena_array(&c->global->arena, CfreeCgTypeId, n); + if (!dst) return NULL; + memcpy(dst, src, sizeof(*dst) * n); + return dst; +} + +CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler* c) { + CfreeCgBuiltinTypes out; + (void)c; + out.void_ = builtin_id(CFREE_CG_BUILTIN_VOID); + out.bool_ = builtin_id(CFREE_CG_BUILTIN_BOOL); + out.i8 = builtin_id(CFREE_CG_BUILTIN_I8); + out.u8 = builtin_id(CFREE_CG_BUILTIN_U8); + out.i16 = builtin_id(CFREE_CG_BUILTIN_I16); + out.u16 = builtin_id(CFREE_CG_BUILTIN_U16); + out.i32 = builtin_id(CFREE_CG_BUILTIN_I32); + out.u32 = builtin_id(CFREE_CG_BUILTIN_U32); + out.i64 = builtin_id(CFREE_CG_BUILTIN_I64); + out.u64 = builtin_id(CFREE_CG_BUILTIN_U64); + out.isize = builtin_id(CFREE_CG_BUILTIN_ISIZE); + out.usize = builtin_id(CFREE_CG_BUILTIN_USIZE); + out.f32 = builtin_id(CFREE_CG_BUILTIN_F32); + out.f64 = builtin_id(CFREE_CG_BUILTIN_F64); + return out; +} + +CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee) { + const Type* pty = resolve_type(c, pointee); + CfreeCgTypeId id; + CgApiType* e; + if (!pty) return CFREE_CG_TYPE_NONE; + e = type_alloc(c, &id); + if (!e) return CFREE_CG_TYPE_NONE; + e->type = type_ptr(c->global, pty); + e->base = pointee; + e->kind = CG_API_TYPE_PTR; + return e->type ? id : CFREE_CG_TYPE_NONE; +} + +CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem, + uint32_t count) { + const Type* ety = resolve_type(c, elem); + CfreeCgTypeId id; + CgApiType* e; + if (!ety) return CFREE_CG_TYPE_NONE; + e = type_alloc(c, &id); + if (!e) return CFREE_CG_TYPE_NONE; + e->type = type_array(c->global, ety, count, 0); + e->base = elem; + e->count = count; + e->kind = CG_API_TYPE_ARRAY; + return e->type ? id : CFREE_CG_TYPE_NONE; +} + +CfreeCgTypeId cfree_cg_type_qualified(CfreeCompiler* c, CfreeCgTypeId base, + uint32_t quals) { + const u32 known = + CFREE_CG_TQ_CONST | CFREE_CG_TQ_VOLATILE | CFREE_CG_TQ_RESTRICT; + const Type* bty = resolve_type(c, base); + CfreeCgTypeId id; + CgApiType* e; + if (!bty || (quals & ~known)) return CFREE_CG_TYPE_NONE; + e = type_alloc(c, &id); + if (!e) return CFREE_CG_TYPE_NONE; + e->type = type_qualified(c->global, bty, quals_to_internal(quals)); + e->base = base; + e->flags = quals; + e->kind = CG_API_TYPE_QUALIFIED; + return e->type ? id : CFREE_CG_TYPE_NONE; +} + +CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name, + CfreeCgTypeId base) { + const Type* bty = resolve_type(c, base); + CfreeCgTypeId id; + CgApiType* e; + if (!bty) return CFREE_CG_TYPE_NONE; + e = type_alloc(c, &id); + if (!e) return CFREE_CG_TYPE_NONE; + e->type = bty; + e->base = base; + e->name = name; + e->kind = CG_API_TYPE_ALIAS; + return id; +} + +CfreeCgTypeId cfree_cg_type_record(CfreeCompiler* c, CfreeSym tag, int is_union, + const CfreeCgField* fields, + uint32_t nfields) { + CfreeCgTypeId id; + CgApiType* e; + TypeRecordBuilder* b; + CfreeCgField* copied = NULL; + TagDeclKind tag_kind = is_union ? TAG_UNION : TAG_STRUCT; + TagId tag_id; + if (!c || (nfields && !fields) || nfields > UINT16_MAX) { + return CFREE_CG_TYPE_NONE; + } + if (nfields) { + copied = arena_array(&c->global->arena, CfreeCgField, nfields); + if (!copied) return CFREE_CG_TYPE_NONE; + } + tag_id = type_tag_new(c->global, tag_kind, tag, (SrcLoc){0, 0, 0}); + b = type_record_begin(c->global, is_union ? TY_UNION : TY_STRUCT, tag_id, + tag); + if (!tag_id || !b) return CFREE_CG_TYPE_NONE; + for (u32 i = 0; i < nfields; ++i) { + const Type* fty = resolve_type(c, fields[i].type); + Field f; + if (!fty) return CFREE_CG_TYPE_NONE; + copied[i] = fields[i]; + memset(&f, 0, sizeof(f)); + f.name = fields[i].name; + f.type = fty; + if (fields[i].align_override == 1u) { + f.packed = 1; + } else if (fields[i].align_override > 1u) { + if (fields[i].align_override > UINT16_MAX) return CFREE_CG_TYPE_NONE; + f.align_override = (u16)fields[i].align_override; + } + type_record_field(b, f); + } + e = type_alloc(c, &id); + if (!e) return CFREE_CG_TYPE_NONE; + e->type = type_record_end(c->global, b); + e->name = tag; + e->count = nfields; + e->fields = copied; + e->kind = CG_API_TYPE_RECORD; + e->is_union = is_union ? 1u : 0u; + return e->type ? id : CFREE_CG_TYPE_NONE; +} + +CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler* c, CfreeSym tag, + CfreeCgTypeId base, + const CfreeCgEnumValue* values, + uint32_t nvalues) { + const Type* bty; + CfreeCgEnumValue* copied = NULL; + CfreeCgTypeId id; + CgApiType* e; + TagId tag_id; + if (!c || (nvalues && !values)) return CFREE_CG_TYPE_NONE; + bty = base == CFREE_CG_TYPE_NONE ? type_prim(c->global, TY_INT) + : resolve_type(c, base); + if (!bty || !type_is_int(bty)) return CFREE_CG_TYPE_NONE; + if (nvalues) { + copied = arena_array(&c->global->arena, CfreeCgEnumValue, nvalues); + if (!copied) return CFREE_CG_TYPE_NONE; + memcpy(copied, values, sizeof(*copied) * nvalues); + } + tag_id = type_tag_new(c->global, TAG_ENUM, tag, (SrcLoc){0, 0, 0}); + if (!tag_id) return CFREE_CG_TYPE_NONE; + e = type_alloc(c, &id); + if (!e) return CFREE_CG_TYPE_NONE; + e->type = type_enum(c->global, tag_id, tag, bty); + e->base = base; + e->name = tag; + e->count = nvalues; + e->values = copied; + e->kind = CG_API_TYPE_ENUM; + return e->type ? id : CFREE_CG_TYPE_NONE; +} + +CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgTypeId ret, + const CfreeCgTypeId* params, uint32_t nparams, + int variadic) { + Heap* h; + const Type* rty = resolve_type(c, ret); + const Type** ptypes = NULL; + CfreeCgTypeId* copied = NULL; + CfreeCgTypeId id; + CgApiType* e; + if (!c || !rty || (nparams && !params) || nparams > UINT16_MAX) { + return CFREE_CG_TYPE_NONE; + } + h = (Heap*)c->env->heap; + if (nparams) { + ptypes = (const Type**)h->alloc(h, sizeof(*ptypes) * nparams, + _Alignof(const Type*)); + if (!ptypes) return CFREE_CG_TYPE_NONE; + copied = copy_type_ids(c, params, nparams); + if (!copied) { + h->free(h, ptypes, sizeof(*ptypes) * nparams); + return CFREE_CG_TYPE_NONE; + } + for (u32 i = 0; i < nparams; ++i) { + ptypes[i] = resolve_type(c, params[i]); + if (!ptypes[i]) { + h->free(h, ptypes, sizeof(*ptypes) * nparams); + return CFREE_CG_TYPE_NONE; + } + } + } + e = type_alloc(c, &id); + if (!e) { + if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * nparams); + return CFREE_CG_TYPE_NONE; + } + e->type = type_func(c->global, rty, ptypes, (u16)nparams, variadic); + if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * nparams); + e->base = ret; + e->count = nparams; + e->params = copied; + e->flags = variadic ? 1u : 0u; + e->kind = CG_API_TYPE_FUNC; + return e->type ? id : CFREE_CG_TYPE_NONE; +} + +const Type* cg_api_type_resolve(Compiler* c, CfreeCgTypeId id) { + return resolve_type(c, id); +} + +void cg_api_fini(Compiler* c) { + CgApiState* s; + if (!c || !c->cg_api) return; + s = (CgApiState*)c->cg_api; + CgApiTypes_fini(&s->types); + s->heap->free(s->heap, s, sizeof(*s)); + c->cg_api = NULL; + c->cg_api_free = NULL; +} diff --git a/src/api/cg_api.h b/src/api/cg_api.h @@ -0,0 +1,20 @@ +#ifndef CFREE_API_CG_API_H +#define CFREE_API_CG_API_H + +#include <cfree/cg.h> + +#include "core/core.h" +#include "type/type.h" + +enum { + CG_API_TYPE_SEG_SHIFT = 6, + CG_API_TYPE_SEG_SIZE = 1u << CG_API_TYPE_SEG_SHIFT, + CG_API_TYPE_SEG_MASK = CG_API_TYPE_SEG_SIZE - 1u, + CG_API_TYPE_BUILTIN_SEG = 1u, + CG_API_TYPE_USER_SEG_BIAS = 2u, +}; + +const Type* cg_api_type_resolve(Compiler*, CfreeCgTypeId); +void cg_api_fini(Compiler*); + +#endif diff --git a/src/core/core.c b/src/core/core.c @@ -66,6 +66,11 @@ void compiler_fini(Compiler* c) { * Run the stack defensively so memory still gets released. */ compiler_run_cleanups(c); + if (c->cg_api_free) { + c->cg_api_free(c); + c->cg_api_free = NULL; + } + if (c->abi) { abi_free(c->abi); c->abi = NULL; diff --git a/src/core/core.h b/src/core/core.h @@ -126,7 +126,8 @@ struct CfreeCompiler { Target target; CompilerCleanup* cleanup; /* top of LIFO cleanup stack */ CfreeCompileFn frontends[CFREE_LANG_COUNT]; - void* reserved; + void* cg_api; /* public cfree/cg.h adapter state */ + void (*cg_api_free)(Compiler*); }; void compiler_init(Compiler*, Target, const CfreeEnv*); diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -0,0 +1,140 @@ +#include <cfree.h> +#include <cfree/cg.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void* h_alloc(CfreeHeap* h, size_t n, size_t a) { + (void)h; + (void)a; + return n ? malloc(n) : NULL; +} + +static void* h_realloc(CfreeHeap* h, void* p, size_t o, size_t n, size_t a) { + (void)h; + (void)o; + (void)a; + return realloc(p, n); +} + +static void h_free(CfreeHeap* h, void* p, size_t n) { + (void)h; + (void)n; + free(p); +} + +static CfreeHeap g_heap = {h_alloc, h_realloc, h_free, NULL}; + +static void diag_emit(CfreeDiagSink* s, CfreeDiagKind k, CfreeSrcLoc loc, + const char* fmt, va_list ap) { + (void)s; + (void)loc; + fprintf(stderr, "diag %d: ", (int)k); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); +} + +static CfreeDiagSink g_diag = {diag_emit, NULL, 0, 0}; + +static int g_fail; + +#define EXPECT(cond, ...) \ + do { \ + if (!(cond)) { \ + ++g_fail; \ + fprintf(stderr, "FAIL %s:%d: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fputc('\n', stderr); \ + } \ + } while (0) + +int main(void) { + CfreeTarget target; + CfreeEnv env; + CfreeCompiler* c; + CfreeCgBuiltinTypes bi; + CfreeCgTypeId ptr_i32; + CfreeCgTypeId array_i32; + CfreeCgTypeId params[2]; + CfreeCgTypeId fn; + CfreeCgTypeId alias; + CfreeCgTypeId qual; + CfreeCgTypeId rec; + CfreeCgTypeId enm; + CfreeCgField fields[2]; + CfreeCgEnumValue vals[2]; + + memset(&target, 0, sizeof(target)); + target.arch = CFREE_ARCH_ARM_64; + target.os = CFREE_OS_LINUX; + target.obj = CFREE_OBJ_ELF; + target.ptr_size = 8; + target.ptr_align = 8; + + env.heap = &g_heap; + env.file_io = NULL; + env.diag = &g_diag; + env.execmem = NULL; + env.dbg_os = NULL; + env.jit_tls = NULL; + env.now = 0; + + c = cfree_compiler_new(target, &env); + if (!c) { + fprintf(stderr, "compiler_new failed\n"); + return 2; + } + + bi = cfree_cg_builtin_types(c); + EXPECT(bi.void_ != CFREE_CG_TYPE_NONE, "void builtin id is none"); + EXPECT(bi.i32 != CFREE_CG_TYPE_NONE, "i32 builtin id is none"); + EXPECT(bi.f64 != CFREE_CG_TYPE_NONE, "f64 builtin id is none"); + EXPECT(bi.void_ != bi.i32 && bi.i32 != bi.f64, "builtin ids collide"); + + ptr_i32 = cfree_cg_type_ptr(c, bi.i32); + array_i32 = cfree_cg_type_array(c, bi.i32, 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, CFREE_CG_TYPE_NONE) == CFREE_CG_TYPE_NONE, + "invalid pointer pointee should fail"); + + alias = cfree_cg_type_alias(c, cfree_sym_intern(c, "I"), bi.i32); + qual = cfree_cg_type_qualified(c, alias, CFREE_CG_TQ_CONST); + EXPECT(alias != CFREE_CG_TYPE_NONE && alias != bi.i32, + "alias id should be fresh"); + EXPECT(qual != CFREE_CG_TYPE_NONE && qual != alias, + "qualified id should be fresh"); + EXPECT(cfree_cg_type_qualified(c, alias, 1u << 12) == CFREE_CG_TYPE_NONE, + "unknown qualifier bit should fail"); + + fields[0].name = cfree_sym_intern(c, "a"); + fields[0].type = bi.i32; + fields[0].align_override = 0; + fields[1].name = cfree_sym_intern(c, "b"); + fields[1].type = ptr_i32; + fields[1].align_override = 1; + rec = cfree_cg_type_record(c, cfree_sym_intern(c, "R"), 0, fields, 2); + EXPECT(rec != CFREE_CG_TYPE_NONE, "record type failed"); + EXPECT(cfree_cg_type_record(c, cfree_sym_intern(c, "Bad"), 0, fields, 0) != + CFREE_CG_TYPE_NONE, + "empty record type failed"); + + vals[0].name = cfree_sym_intern(c, "A"); + vals[0].value = 1; + vals[1].name = cfree_sym_intern(c, "B"); + vals[1].value = 2; + enm = cfree_cg_type_enum(c, cfree_sym_intern(c, "E"), CFREE_CG_TYPE_NONE, + vals, 2); + EXPECT(enm != CFREE_CG_TYPE_NONE, "enum type failed"); + + params[0] = bi.i32; + params[1] = ptr_i32; + fn = cfree_cg_type_func(c, bi.i64, params, 2, 1); + EXPECT(fn != CFREE_CG_TYPE_NONE, "function type failed"); + EXPECT(cfree_cg_type_func(c, bi.i64, params, 70000, 0) == CFREE_CG_TYPE_NONE, + "oversized function param list should fail"); + + cfree_compiler_free(c); + return g_fail ? 1 : 0; +} diff --git a/test/test.mk b/test/test.mk @@ -29,7 +29,7 @@ # parse_asm / cfree_disasm_iter_* are still stubs; the harness builds # and runs end-to-end so the wiring stays exercised. See doc/ASM.md. -.PHONY: test test-lex test-pp test-pp-err test-elf test-ar test-ar-driver test-link test-cg test-cg-binder test-opt test-dwarf test-debug test-parse test-parse-err test-asm test-isa test-aa64-inline test-libc test-musl test-glibc test-lib-deps test-smoke-x64 test-smoke-rv64 +.PHONY: test test-lex test-pp test-pp-err test-elf test-ar test-ar-driver test-link test-cg test-cg-api test-cg-binder test-opt test-dwarf test-debug test-parse test-parse-err test-asm test-isa test-aa64-inline test-libc test-musl test-glibc test-lib-deps test-smoke-x64 test-smoke-rv64 test: test-lex test-pp test-pp-err test-elf test-ar test-ar-driver test-link test-cg test-cg-binder test-dwarf test-debug test-parse test-parse-err test-asm test-isa test-aa64-inline test-lib-deps @@ -109,6 +109,14 @@ $(AA64_ISA_TEST_BIN): test/arch/aa64_isa_test.c $(LIB_AR) # clobber spill behaviour, register-name passthrough, and "cc" no-op. # Internal cg/ + arch/ surface — needs -Isrc. CG_BINDER_TEST_BIN = build/test/cg_binder_test +CG_API_TEST_BIN = build/test/cg_api_test + +test-cg-api: $(CG_API_TEST_BIN) + $(CG_API_TEST_BIN) + +$(CG_API_TEST_BIN): test/api/cg_type_test.c $(LIB_AR) + @mkdir -p $(dir $@) + $(CC) $(DRIVER_CFLAGS) test/api/cg_type_test.c $(LIB_AR) -o $@ test-cg-binder: $(CG_BINDER_TEST_BIN) $(CG_BINDER_TEST_BIN)