kit

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

commit 89b2feab45e6fd2e256d7f6ea889d6383777149e
parent f500bfdc04a79ef0ef3c4b10958be34fa3a3c327
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 15 May 2026 11:07:19 -0700

cg: replace public frame slots with local handles

Diffstat:
Minclude/cfree/cg.h | 46+++++++++++++++++++++++++---------------------
Mlang/c/parse/cg_adapter.c | 12++++++------
Mlang/c/parse/cg_public_compat.h | 4++--
Mlang/c/parse/parse_priv.h | 2+-
Mlang/c/type/type.c | 4++--
Mlang/toy/toy.c | 63+++++++++++++++++++++++++++++++++------------------------------
Msrc/api/cg.c | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/api/cg_type.h | 2+-
Mtest/api/cg_type_test.c | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtest/test.mk | 2+-
10 files changed, 294 insertions(+), 133 deletions(-)

diff --git a/include/cfree/cg.h b/include/cfree/cg.h @@ -10,14 +10,14 @@ typedef struct CfreeCg CfreeCg; typedef uint32_t CfreeCgLabel; +typedef uint32_t CfreeCgLocal; typedef uint32_t CfreeCgScope; -typedef uint32_t CfreeCgSlot; typedef uint32_t CfreeCgSym; typedef uint32_t CfreeCgTypeId; #define CFREE_CG_LABEL_NONE 0u +#define CFREE_CG_LOCAL_NONE 0u #define CFREE_CG_SCOPE_NONE 0u -#define CFREE_CG_SLOT_NONE 0u #define CFREE_CG_SYM_NONE 0u #define CFREE_CG_TYPE_NONE 0u @@ -91,15 +91,15 @@ typedef struct CfreeCgAbiAttrs { uint64_t dereferenceable_size; } CfreeCgAbiAttrs; -typedef struct CfreeCgParam { +typedef struct CfreeCgFuncParam { CfreeCgTypeId type; CfreeCgAbiAttrs attrs; -} CfreeCgParam; +} CfreeCgFuncParam; typedef struct CfreeCgFuncSig { CfreeCgTypeId ret; CfreeCgAbiAttrs ret_attrs; - const CfreeCgParam* params; + const CfreeCgFuncParam* params; uint32_t nparams; CfreeCgCallConv call_conv; int abi_variadic; @@ -168,7 +168,7 @@ uint64_t cfree_cg_type_array_count(CfreeCompiler*, CfreeCgTypeId); CfreeCgTypeId cfree_cg_type_func_ret(CfreeCompiler*, CfreeCgTypeId); CfreeCgAbiAttrs cfree_cg_type_func_ret_attrs(CfreeCompiler*, CfreeCgTypeId); uint32_t cfree_cg_type_func_nparams(CfreeCompiler*, CfreeCgTypeId); -CfreeCgParam cfree_cg_type_func_param(CfreeCompiler*, CfreeCgTypeId, +CfreeCgFuncParam cfree_cg_type_func_param(CfreeCompiler*, CfreeCgTypeId, uint32_t index); CfreeCgCallConv cfree_cg_type_func_call_conv(CfreeCompiler*, CfreeCgTypeId); int cfree_cg_type_func_is_variadic(CfreeCompiler*, CfreeCgTypeId); @@ -373,24 +373,27 @@ void cfree_cg_set_loc(CfreeCg*, CfreeSrcLoc); void cfree_cg_func_begin(CfreeCg*, CfreeCgSym sym); void cfree_cg_func_end(CfreeCg*); -typedef enum CfreeCgSlotFlag { - CFREE_CG_SLOTFLAG_NONE = 0, - CFREE_CG_SLOT_ADDRESS_TAKEN = 1u << 0, - CFREE_CG_SLOT_ARTIFICIAL = 1u << 1, - CFREE_CG_SLOT_OPTIMIZED_OUT = 1u << 2, - CFREE_CG_SLOT_COMPILER_TEMP = 1u << 3, -} CfreeCgSlotFlag; +typedef enum CfreeCgLocalFlag { + CFREE_CG_LOCALFLAG_NONE = 0, + CFREE_CG_LOCAL_ADDRESS_TAKEN = 1u << 0, + CFREE_CG_LOCAL_ARTIFICIAL = 1u << 1, + CFREE_CG_LOCAL_OPTIMIZED_OUT = 1u << 2, + CFREE_CG_LOCAL_COMPILER_TEMP = 1u << 3, +} CfreeCgLocalFlag; -typedef struct CfreeCgSlotAttrs { +typedef struct CfreeCgLocalAttrs { CfreeSym name; uint32_t align; /* 0 = natural */ - uint32_t flags; /* CfreeCgSlotFlag */ -} CfreeCgSlotAttrs; + uint32_t flags; /* CfreeCgLocalFlag */ +} CfreeCgLocalAttrs; -CfreeCgSlot cfree_cg_local_slot(CfreeCg*, CfreeCgTypeId type, - CfreeCgSlotAttrs attrs); -CfreeCgSlot cfree_cg_param_slot(CfreeCg*, uint32_t index, CfreeCgTypeId type, - CfreeCgSlotAttrs attrs); +CfreeCgLocal cfree_cg_local(CfreeCg*, CfreeCgTypeId type, + CfreeCgLocalAttrs attrs); +/* Declares a source parameter as a local handle. Parameters must be declared + * in order before ordinary locals; therefore the first n parameter handles in + * a function are also the first n local ids. */ +CfreeCgLocal cfree_cg_param(CfreeCg*, uint32_t index, CfreeCgTypeId type, + CfreeCgLocalAttrs attrs); /* Pops a byte size and pushes a pointer to stack storage with at least align * alignment. The allocation lifetime is the current function activation. */ @@ -483,7 +486,8 @@ void cfree_cg_rot3(CfreeCg*); /* [..., a, b, c] -> [..., b, c, a] */ void cfree_cg_push_int(CfreeCg*, uint64_t value, CfreeCgTypeId type); void cfree_cg_push_float(CfreeCg*, double value, CfreeCgTypeId type); void cfree_cg_push_null(CfreeCg*, CfreeCgTypeId ptr_type); -void cfree_cg_push_local(CfreeCg*, CfreeCgSlot slot); +void cfree_cg_push_local(CfreeCg*, CfreeCgLocal local); +void cfree_cg_push_local_addr(CfreeCg*, CfreeCgLocal local); /* Anonymous immutable data. Returns a local readonly object symbol; callers * can materialize its address with push_symbol_addr. pointee_type describes diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -218,21 +218,21 @@ CfreeCgAtomicOp pcg_atomic_op(AtomicOp op) { CfreeCgMemOrder pcg_mem_order(MemOrder ord) { return (CfreeCgMemOrder)ord; } FrameSlot pcg_local(Parser* p, const FrameSlotDesc* fsd) { - CfreeCgSlotAttrs attrs; + CfreeCgLocalAttrs attrs; memset(&attrs, 0, sizeof attrs); attrs.name = fsd->name; attrs.align = fsd->align; - if (fsd->flags & FSF_ADDR_TAKEN) attrs.flags |= CFREE_CG_SLOT_ADDRESS_TAKEN; - return cfree_cg_local_slot(p->cg, pcg_tid(p->c, fsd->type), attrs); + if (fsd->flags & FSF_ADDR_TAKEN) attrs.flags |= CFREE_CG_LOCAL_ADDRESS_TAKEN; + return cfree_cg_local(p->cg, pcg_tid(p->c, fsd->type), attrs); } FrameSlot pcg_param_slot(Parser* p, u32 index, const FrameSlotDesc* fsd) { - CfreeCgSlotAttrs attrs; + CfreeCgLocalAttrs attrs; memset(&attrs, 0, sizeof attrs); attrs.name = fsd->name; attrs.align = fsd->align; - if (fsd->flags & FSF_ADDR_TAKEN) attrs.flags |= CFREE_CG_SLOT_ADDRESS_TAKEN; - return cfree_cg_param_slot(p->cg, index, pcg_tid(p->c, fsd->type), attrs); + if (fsd->flags & FSF_ADDR_TAKEN) attrs.flags |= CFREE_CG_LOCAL_ADDRESS_TAKEN; + return cfree_cg_param(p->cg, index, pcg_tid(p->c, fsd->type), attrs); } void pcg_param(Parser* p, const CGParamDesc* pd) { diff --git a/lang/c/parse/cg_public_compat.h b/lang/c/parse/cg_public_compat.h @@ -9,9 +9,9 @@ typedef CfreeCg CG; typedef CfreeCgLabel CGLabel; typedef CfreeCgScope CGScope; -typedef CfreeCgSlot FrameSlot; +typedef CfreeCgLocal FrameSlot; -#define FRAME_SLOT_NONE CFREE_CG_SLOT_NONE +#define FRAME_SLOT_NONE CFREE_CG_LOCAL_NONE #define OBJ_GROUP_NONE 0u typedef enum BinOp { diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h @@ -77,7 +77,7 @@ typedef enum CKw { * ============================================================ */ typedef enum SymEntryKind { - SEK_LOCAL, /* local variable, OPK_LOCAL via FrameSlot */ + SEK_LOCAL, /* local variable or parameter source handle */ SEK_GLOBAL, /* global var, OPK_GLOBAL via ObjSymId */ SEK_FUNC, /* function decl, OPK_GLOBAL via ObjSymId */ SEK_TYPEDEF, /* typedef name */ diff --git a/lang/c/type/type.c b/lang/c/type/type.c @@ -399,7 +399,7 @@ static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, Pool* p, const Type* t, return cfree_cg_type_array( c, type_cg_id_walk(c, p, t->arr.elem, pending_record), t->arr.count); case TY_FUNC: { - CfreeCgParam* params = NULL; + CfreeCgFuncParam* params = NULL; CfreeCgFuncSig sig; memset(&sig, 0, sizeof sig); sig.ret = type_cg_id_walk(c, p, t->fn.ret, pending_record); @@ -407,7 +407,7 @@ static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, Pool* p, const Type* t, sig.abi_variadic = t->fn.variadic; sig.call_conv = CFREE_CG_CC_TARGET_C; if (t->fn.nparams) { - params = arena_zarray(p->arena, CfreeCgParam, t->fn.nparams); + params = arena_zarray(p->arena, CfreeCgFuncParam, t->fn.nparams); for (u32 i = 0; i < t->fn.nparams; ++i) { params[i].type = type_cg_id_walk(c, p, t->fn.params[i], pending_record); diff --git a/lang/toy/toy.c b/lang/toy/toy.c @@ -345,8 +345,7 @@ static ToyToken toy_lexer_peek(const ToyLexer* lex) { typedef struct ToyVar { CfreeSym name; CfreeCgTypeId type; - CfreeCgSlot slot; - int is_param; + CfreeCgLocal local; } ToyVar; typedef struct ToyFn { @@ -507,6 +506,14 @@ static ToyGlobal* toy_find_global(ToyParser* p, CfreeSym name) { return NULL; } +static void toy_push_var_lvalue(ToyParser* p, const ToyVar* v) { + cfree_cg_push_local(p->cg, v->local); +} + +static void toy_push_var_addr(ToyParser* p, const ToyVar* v) { + cfree_cg_push_local_addr(p->cg, v->local); +} + static CfreeCgSym toy_find_decl_sym(ToyParser* p, CfreeSym name) { ToyGlobal* g = toy_find_global(p, name); if (g) return g->sym; @@ -745,8 +752,8 @@ static int toy_parse_atomic_op(ToyParser* p, CfreeCgAtomicOp* out) { return 1; } -static CfreeCgSlotAttrs toy_slot_attrs(CfreeSym name) { - CfreeCgSlotAttrs attrs; +static CfreeCgLocalAttrs toy_slot_attrs(CfreeSym name) { + CfreeCgLocalAttrs attrs; memset(&attrs, 0, sizeof attrs); attrs.name = name; return attrs; @@ -909,8 +916,7 @@ static int toy_parse_arch_string(ToyParser* p, CfreeSym* out, static int toy_emit_var_addr(ToyParser* p, CfreeSym name) { ToyVar* v = toy_find_var(p, name); if (v) { - cfree_cg_push_local(p->cg, v->slot); - cfree_cg_addr(p->cg); + toy_push_var_addr(p, v); return 1; } { @@ -926,7 +932,7 @@ static int toy_emit_var_addr(ToyParser* p, CfreeSym name) { static CfreeCgTypeId toy_emit_var_lvalue(ToyParser* p, CfreeSym name) { ToyVar* v = toy_find_var(p, name); if (v) { - cfree_cg_push_local(p->cg, v->slot); + toy_push_var_lvalue(p, v); return v->type; } { @@ -1041,7 +1047,7 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (toy_sym_is(p, name, "bitset")) { CfreeCgTypeId dst_ty, src_ty; int64_t lo, width; - CfreeCgSlot dst_slot, src_slot; + CfreeCgLocal dst_slot, src_slot; uint64_t src_mask, field_mask, clear_mask; toy_parser_advance(p); dst_ty = toy_parse_expr(p); @@ -1058,8 +1064,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, src_mask = (1ULL << (uint32_t)width) - 1u; field_mask = src_mask << (uint32_t)lo; clear_mask = ~field_mask; - src_slot = cfree_cg_local_slot(p->cg, src_ty, toy_slot_attrs(0)); - dst_slot = cfree_cg_local_slot(p->cg, dst_ty, toy_slot_attrs(0)); + src_slot = cfree_cg_local(p->cg, src_ty, toy_slot_attrs(0)); + dst_slot = cfree_cg_local(p->cg, dst_ty, toy_slot_attrs(0)); cfree_cg_push_local(p->cg, src_slot); cfree_cg_swap(p->cg); cfree_cg_store(p->cg, toy_mem_access(p, src_ty)); @@ -1266,14 +1272,14 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (toy_sym_is(p, name, "fieldtest")) { uint64_t sz = cfree_cg_type_size(p->c, p->pair_type); - CfreeCgSlot slot; + CfreeCgLocal slot; if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; if (sz == 0) { toy_error(p, p->cur.loc, "invalid Pair layout"); return CFREE_CG_TYPE_NONE; } - slot = cfree_cg_local_slot(p->cg, p->pair_type, toy_slot_attrs(0)); + slot = cfree_cg_local(p->cg, p->pair_type, toy_slot_attrs(0)); cfree_cg_push_local(p->cg, slot); cfree_cg_addr(p->cg); cfree_cg_dup(p->cg); @@ -1523,10 +1529,10 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (toy_sym_is(p, name, "typecheck")) { CfreeCgTypeId arr, alias, enm, fnty; CfreeCgEnumValue ev; - CfreeCgParam fn_params[1]; + CfreeCgFuncParam fn_params[1]; CfreeCgFuncSig sig; CfreeCgField field; - CfreeCgParam first_param; + CfreeCgFuncParam first_param; int ok = 1; if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; @@ -1798,7 +1804,7 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { /* Variable reference */ ToyVar* v = toy_find_var(p, name); if (v) { - cfree_cg_push_local(p->cg, v->slot); + toy_push_var_lvalue(p, v); cfree_cg_load(p->cg, toy_mem_access(p, v->type)); return v->type; } @@ -1876,8 +1882,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { ToyVar* v = toy_find_var(p, name); toy_parser_advance(p); if (v) { - cfree_cg_push_local(p->cg, v->slot); - cfree_cg_addr(p->cg); + toy_push_var_addr(p, v); return cfree_cg_type_ptr(p->c, v->type, 0); } else { ToyGlobal* g = toy_find_global(p, name); @@ -2131,11 +2136,11 @@ static CfreeCgTypeId toy_parse_expr_and(ToyParser* p) { while (p->cur.kind == TOK_ANDAND) { CfreeCgLabel false_label; CfreeCgLabel end_label; - CfreeCgSlot result_slot; + CfreeCgLocal result_slot; toy_parser_advance(p); false_label = cfree_cg_label_new(p->cg); end_label = cfree_cg_label_new(p->cg); - result_slot = cfree_cg_local_slot(p->cg, p->int_type, toy_slot_attrs(0)); + result_slot = cfree_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); if (!toy_emit_truthy(p, ty)) return CFREE_CG_TYPE_NONE; cfree_cg_branch_false(p->cg, false_label); ty = toy_parse_expr_bor(p); @@ -2164,11 +2169,11 @@ static CfreeCgTypeId toy_parse_expr_or(ToyParser* p) { while (p->cur.kind == TOK_PIPEPIPE) { CfreeCgLabel true_label; CfreeCgLabel end_label; - CfreeCgSlot result_slot; + CfreeCgLocal result_slot; toy_parser_advance(p); true_label = cfree_cg_label_new(p->cg); end_label = cfree_cg_label_new(p->cg); - result_slot = cfree_cg_local_slot(p->cg, p->int_type, toy_slot_attrs(0)); + result_slot = cfree_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); if (!toy_emit_truthy(p, ty)) return CFREE_CG_TYPE_NONE; cfree_cg_branch_true(p->cg, true_label); ty = toy_parse_expr_and(p); @@ -2226,7 +2231,7 @@ static int toy_parse_block(ToyParser* p) { static int toy_parse_let_stmt(ToyParser* p) { CfreeSym name; CfreeCgTypeId ty; - CfreeCgSlot slot; + CfreeCgLocal slot; toy_parser_advance(p); /* let */ if (p->cur.kind != TOK_IDENT) { toy_error(p, p->cur.loc, "expected identifier after 'let'"); @@ -2240,15 +2245,14 @@ static int toy_parse_let_stmt(ToyParser* p) { } ty = toy_parse_type(p); if (ty == CFREE_CG_TYPE_NONE) return 0; - slot = cfree_cg_local_slot(p->cg, ty, toy_slot_attrs(name)); + slot = cfree_cg_local(p->cg, ty, toy_slot_attrs(name)); if (p->nvars >= TOY_MAX_VARS) { toy_error(p, p->cur.loc, "too many locals"); return 0; } p->vars[p->nvars].name = name; p->vars[p->nvars].type = ty; - p->vars[p->nvars].slot = slot; - p->vars[p->nvars].is_param = 0; + p->vars[p->nvars].local = slot; p->nvars++; if (toy_parser_match(p, TOK_EQ)) { @@ -2463,7 +2467,7 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "type mismatch in assignment"); return 0; } - cfree_cg_push_local(p->cg, v->slot); + toy_push_var_lvalue(p, v); cfree_cg_swap(p->cg); cfree_cg_store(p->cg, toy_mem_access(p, v->type)); } else { @@ -2532,7 +2536,7 @@ static int toy_parse_fn(ToyParser* p) { CfreeSym name; CfreeCgTypeId ret_type; CfreeCgTypeId param_types[TOY_MAX_PARAMS]; - CfreeCgParam sig_params[TOY_MAX_PARAMS]; + CfreeCgFuncParam sig_params[TOY_MAX_PARAMS]; CfreeSym param_names[TOY_MAX_PARAMS]; size_t nparams = 0; int variadic = 0; @@ -2653,7 +2657,7 @@ static int toy_parse_fn(ToyParser* p) { p->nvars = 0; p->cur_fn_ret = ret_type; for (i = 0; i < nparams; i++) { - CfreeCgSlot slot = cfree_cg_param_slot( + CfreeCgLocal param = cfree_cg_param( p->cg, (uint32_t)i, param_types[i], toy_slot_attrs(param_names[i])); if (p->nvars >= TOY_MAX_VARS) { toy_error(p, p->cur.loc, "too many vars"); @@ -2661,8 +2665,7 @@ static int toy_parse_fn(ToyParser* p) { } p->vars[p->nvars].name = param_names[i]; p->vars[p->nvars].type = param_types[i]; - p->vars[p->nvars].slot = slot; - p->vars[p->nvars].is_param = 1; + p->vars[p->nvars].local = param; p->nvars++; } diff --git a/src/api/cg.c b/src/api/cg.c @@ -36,7 +36,7 @@ typedef struct CgApiType { u64 array_count; const CfreeCgField *fields; const CfreeCgEnumValue *values; - const CfreeCgParam *params; + const CfreeCgFuncParam *params; CfreeCgAbiAttrs ret_attrs; CfreeCgCallConv call_conv; u8 kind; @@ -347,7 +347,7 @@ static CfreeCgTypeId find_array_type_id(Compiler *c, CfreeCgTypeId elem, return CFREE_CG_TYPE_NONE; } -static int cg_params_eq(const CfreeCgParam *a, const CfreeCgParam *b, u32 n) { +static int cg_params_eq(const CfreeCgFuncParam *a, const CfreeCgFuncParam *b, u32 n) { for (u32 i = 0; i < n; ++i) if (a[i].type != b[i].type || memcmp(&a[i].attrs, &b[i].attrs, sizeof(a[i].attrs)) != 0) { @@ -405,14 +405,14 @@ static CfreeCgTypeId resolve_type(Compiler *c, CfreeCgTypeId id) { return cg_type_get(c, id) ? id : CFREE_CG_TYPE_NONE; } -static CfreeCgParam *copy_cg_params(Compiler *c, const CfreeCgParam *src, +static CfreeCgFuncParam *copy_cg_params(Compiler *c, const CfreeCgFuncParam *src, u32 n) { - CfreeCgParam *dst; + CfreeCgFuncParam *dst; if (!n) return NULL; if (!src) return NULL; - dst = arena_array(&c->global->arena, CfreeCgParam, n); + dst = arena_array(&c->global->arena, CfreeCgFuncParam, n); if (!dst) return NULL; memcpy(dst, src, sizeof(*dst) * n); @@ -577,7 +577,7 @@ static int cg_type_set_enum(Compiler *c, CgApiType *e, CfreeSym tag, } static int cg_type_set_func(Compiler *c, CgApiType *e, CfreeCgFuncSig sig, - CfreeCgParam *params) { + CfreeCgFuncParam *params) { if (!cg_type_get(c, sig.ret)) return 0; for (u32 i = 0; i < sig.nparams; ++i) { @@ -743,7 +743,7 @@ CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler *c, CfreeSym tag, } CfreeCgTypeId cfree_cg_type_func(CfreeCompiler *c, CfreeCgFuncSig sig) { - CfreeCgParam *copied = NULL; + CfreeCgFuncParam *copied = NULL; CfreeCgTypeId id; CgApiType *e; if (!c || !cg_type_get(c, sig.ret) || (sig.nparams && !sig.params) || @@ -860,10 +860,10 @@ CfreeCgAbiAttrs cfree_cg_type_func_ret_attrs(CfreeCompiler *c, return (ty && ty->kind == CFREE_CG_TYPE_FUNC) ? ty->func.ret_attrs : empty; } -CfreeCgParam cfree_cg_type_func_param(CfreeCompiler *c, CfreeCgTypeId id, +CfreeCgFuncParam cfree_cg_type_func_param(CfreeCompiler *c, CfreeCgTypeId id, uint32_t index) { const CgType *ty = cg_type_get(c, id); - CfreeCgParam empty; + CfreeCgFuncParam empty; memset(&empty, 0, sizeof(empty)); if (!ty || ty->kind != CFREE_CG_TYPE_FUNC || index >= ty->func.nparams) { return empty; @@ -1026,6 +1026,22 @@ typedef struct ApiCgScope { #define API_CG_MAX_SCOPES 64 +typedef enum ApiSourceLocalKind { + API_SOURCE_LOCAL_AUTO, + API_SOURCE_LOCAL_PARAM, +} ApiSourceLocalKind; + +typedef struct ApiSourceLocal { + CfreeCgTypeId type; + CfreeSym name; + CfreeCgLocalAttrs attrs; + SrcLoc loc; + FrameSlot slot; + u32 param_index; + u8 kind; + u8 pad[3]; +} ApiSourceLocal; + struct CfreeCg { Compiler *c; ObjBuilder *obj; @@ -1038,8 +1054,9 @@ struct CfreeCg { u32 sp; u32 cap; - CfreeCgTypeId *slot_types; - u32 slot_types_cap; + ApiSourceLocal *locals; + u32 nlocals; + u32 locals_cap; struct { FrameSlot *free; @@ -1313,40 +1330,6 @@ static ApiSValue api_pop(CfreeCg *g) { return g->stack[--g->sp]; } -static void api_remember_slot_type(CfreeCg *g, FrameSlot slot, - CfreeCgTypeId ty) { - Heap *h = g->c->env->heap; - CfreeCgTypeId *nb; - u32 cap; - if (slot == FRAME_SLOT_NONE) - return; - if (slot < g->slot_types_cap) { - g->slot_types[slot] = ty; - return; - } - cap = g->slot_types_cap ? g->slot_types_cap : 16; - while (cap <= slot) - cap *= 2u; - nb = (CfreeCgTypeId *)h->alloc(h, sizeof(*nb) * cap, _Alignof(CfreeCgTypeId)); - if (!nb) - return; - memset(nb, 0, sizeof(*nb) * cap); - if (g->slot_types) { - memcpy(nb, g->slot_types, sizeof(*nb) * g->slot_types_cap); - h->free(h, g->slot_types, sizeof(*g->slot_types) * g->slot_types_cap); - } - g->slot_types = nb; - g->slot_types_cap = cap; - g->slot_types[slot] = ty; -} - -static CfreeCgTypeId api_slot_type(CfreeCg *g, FrameSlot slot) { - if (slot == FRAME_SLOT_NONE || slot >= g->slot_types_cap) { - return CFREE_CG_TYPE_NONE; - } - return g->slot_types[slot]; -} - /* ---- register class helpers ---- */ static u8 api_class_of_sv(const ApiSValue *sv) { @@ -2151,8 +2134,8 @@ void cfree_cg_free(CfreeCg *g) { h = g->c->env->heap; if (g->stack) h->free(h, g->stack, sizeof(ApiSValue) * g->cap); - if (g->slot_types) { - h->free(h, g->slot_types, sizeof(*g->slot_types) * g->slot_types_cap); + if (g->locals) { + h->free(h, g->locals, sizeof(*g->locals) * g->locals_cap); } if (g->sym_types) { h->free(h, g->sym_types, sizeof(*g->sym_types) * g->sym_cap); @@ -2282,6 +2265,7 @@ void cfree_cg_func_begin(CfreeCg *g, CfreeCgSym cg_sym) { g->fn_ret_type = cg_type_func_ret_id(c, fty); g->fn_abi = abi; + g->nlocals = 0; g->sp = 0; for (u32 i = 0; i < 3; ++i) g->slot_pools[i].n = 0; @@ -2311,19 +2295,69 @@ void cfree_cg_func_end(CfreeCg *g) { } /* ============================================================ - * Local / param slots + * Locals and params * ============================================================ */ -CfreeCgSlot cfree_cg_local_slot(CfreeCg *g, CfreeCgTypeId type, - CfreeCgSlotAttrs attrs) { +static int api_source_flags_addr_taken(u32 flags) { + return (flags & CFREE_CG_LOCAL_ADDRESS_TAKEN) != 0; +} + +static CfreeCgLocal api_local_handle(u32 index) { + u32 raw = index + 1u; + if (!raw) + return CFREE_CG_LOCAL_NONE; + return raw; +} + +static int api_grow_locals(CfreeCg *g, u32 want) { + Heap *h = g->c->env->heap; + ApiSourceLocal *nb; + u32 cap; + if (g->locals_cap >= want) + return 1; + cap = g->locals_cap ? g->locals_cap : 16u; + while (cap < want) + cap *= 2u; + nb = (ApiSourceLocal *)h->alloc(h, sizeof(*nb) * cap, + _Alignof(ApiSourceLocal)); + if (!nb) + return 0; + memset(nb, 0, sizeof(*nb) * cap); + if (g->locals) { + memcpy(nb, g->locals, sizeof(*nb) * g->nlocals); + h->free(h, g->locals, sizeof(*g->locals) * g->locals_cap); + } + g->locals = nb; + g->locals_cap = cap; + return 1; +} + +static ApiSourceLocal *api_local_from_handle(CfreeCg *g, CfreeCgLocal local) { + u32 index; + if (local == CFREE_CG_LOCAL_NONE) + return NULL; + index = local - 1u; + if (index >= g->nlocals) { + return NULL; + } + return &g->locals[index]; +} + +CfreeCgLocal cfree_cg_local(CfreeCg *g, CfreeCgTypeId type, + CfreeCgLocalAttrs attrs) { CfreeCgTypeId ty; FrameSlotDesc fsd; FrameSlot slot; + ApiSourceLocal *rec; + CfreeCgLocal handle; if (!g) - return 0; + return CFREE_CG_LOCAL_NONE; ty = resolve_type(g->c, type); if (!ty) - return 0; + return CFREE_CG_LOCAL_NONE; + handle = api_local_handle(g->nlocals); + if (handle == CFREE_CG_LOCAL_NONE || !api_grow_locals(g, g->nlocals + 1u)) + return CFREE_CG_LOCAL_NONE; memset(&fsd, 0, sizeof fsd); fsd.type = ty; fsd.name = (Sym)attrs.name; @@ -2331,24 +2365,38 @@ CfreeCgSlot cfree_cg_local_slot(CfreeCg *g, CfreeCgTypeId type, fsd.size = abi_cg_sizeof(g->c->abi, type); fsd.align = attrs.align ? attrs.align : abi_cg_alignof(g->c->abi, type); fsd.kind = FS_LOCAL; - if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) + if (api_source_flags_addr_taken(attrs.flags)) fsd.flags |= FSF_ADDR_TAKEN; slot = g->target->frame_slot(g->target, &fsd); - api_remember_slot_type(g, slot, ty); - return (CfreeCgSlot)slot; -} - -CfreeCgSlot cfree_cg_param_slot(CfreeCg *g, uint32_t index, CfreeCgTypeId type, - CfreeCgSlotAttrs attrs) { + rec = &g->locals[g->nlocals++]; + rec->type = ty; + rec->name = attrs.name; + rec->attrs = attrs; + rec->loc = g->cur_loc; + rec->slot = slot; + rec->param_index = 0; + rec->kind = API_SOURCE_LOCAL_AUTO; + return handle; +} + +CfreeCgLocal cfree_cg_param(CfreeCg *g, uint32_t index, CfreeCgTypeId type, + CfreeCgLocalAttrs attrs) { CfreeCgTypeId ty; FrameSlot slot; CGParamDesc pd; FrameSlotDesc fsd; + ApiSourceLocal *rec; + CfreeCgLocal handle; if (!g) - return 0; + return CFREE_CG_LOCAL_NONE; ty = resolve_type(g->c, type); if (!ty) - return 0; + return CFREE_CG_LOCAL_NONE; + if (index != g->nlocals) + return CFREE_CG_LOCAL_NONE; + handle = api_local_handle(g->nlocals); + if (handle == CFREE_CG_LOCAL_NONE || !api_grow_locals(g, g->nlocals + 1u)) + return CFREE_CG_LOCAL_NONE; memset(&fsd, 0, sizeof fsd); fsd.type = ty; @@ -2357,10 +2405,9 @@ CfreeCgSlot cfree_cg_param_slot(CfreeCg *g, uint32_t index, CfreeCgTypeId type, fsd.size = abi_cg_sizeof(g->c->abi, type); fsd.align = attrs.align ? attrs.align : abi_cg_alignof(g->c->abi, type); fsd.kind = FS_PARAM; - if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) + if (api_source_flags_addr_taken(attrs.flags)) fsd.flags |= FSF_ADDR_TAKEN; slot = g->target->frame_slot(g->target, &fsd); - api_remember_slot_type(g, slot, ty); memset(&pd, 0, sizeof pd); pd.index = index; @@ -2373,7 +2420,15 @@ CfreeCgSlot cfree_cg_param_slot(CfreeCg *g, uint32_t index, CfreeCgTypeId type, pd.loc = g->cur_loc; g->target->param(g->target, &pd); - return (CfreeCgSlot)slot; + rec = &g->locals[g->nlocals++]; + rec->type = ty; + rec->name = attrs.name; + rec->attrs = attrs; + rec->loc = g->cur_loc; + rec->slot = slot; + rec->param_index = index; + rec->kind = API_SOURCE_LOCAL_PARAM; + return handle; } /* ============================================================ @@ -2468,12 +2523,26 @@ CfreeCgSym cfree_cg_const_data(CfreeCg *g, const uint8_t *data, size_t len, return (CfreeCgSym)sym; } -void cfree_cg_push_local(CfreeCg *g, CfreeCgSlot slot) { - CfreeCgTypeId ty; +static void api_push_frame_lvalue(CfreeCg *g, FrameSlot slot, + CfreeCgTypeId type) { if (!g) return; - ty = api_slot_type(g, (FrameSlot)slot); - api_push(g, api_make_lv(api_op_local((FrameSlot)slot, ty), ty)); + api_push(g, api_make_lv(api_op_local(slot, type), type)); +} + +void cfree_cg_push_local(CfreeCg *g, CfreeCgLocal local) { + ApiSourceLocal *rec; + if (!g) + return; + rec = api_local_from_handle(g, local); + if (!rec) + return; + api_push_frame_lvalue(g, rec->slot, rec->type); +} + +void cfree_cg_push_local_addr(CfreeCg *g, CfreeCgLocal local) { + cfree_cg_push_local(g, local); + cfree_cg_addr(g); } void cfree_cg_push_symbol_addr(CfreeCg *g, CfreeCgSym sym, int64_t addend) { diff --git a/src/api/cg_type.h b/src/api/cg_type.h @@ -34,7 +34,7 @@ typedef struct CgType { } array; struct { CfreeCgTypeId ret; - CfreeCgParam* params; + CfreeCgFuncParam* params; u32 nparams; CfreeCgCallConv call_conv; int abi_variadic; diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -5,6 +5,8 @@ #include <stdlib.h> #include <string.h> +#include "obj/obj.h" + static void* h_alloc(CfreeHeap* h, size_t n, size_t a) { (void)h; (void)a; @@ -49,6 +51,85 @@ static int g_fail; } \ } while (0) +static void exercise_cg_handles(CfreeCompiler* c, CfreeCgTypeId i32_ty, + int opt_level) { + char name_buf[32]; + CfreeCompileOptions opts; + CfreeObjBuilder* ob; + CfreeCg* cg; + CfreeCgFuncParam param_desc; + CfreeCgFuncSig sig; + CfreeCgDecl decl; + CfreeCgSym sym; + CfreeCgLocalAttrs attrs; + CfreeCgLocal local; + CfreeCgLocal param; + CfreeCgMemAccess mem; + + memset(&opts, 0, sizeof(opts)); + opts.opt_level = opt_level; + ob = (CfreeObjBuilder*)obj_new((Compiler*)c); + EXPECT(ob != NULL, "obj builder allocation failed"); + if (!ob) return; + cg = cfree_cg_new(c, ob, &opts); + EXPECT(cg != NULL, "cg allocation failed"); + if (!cg) { + obj_free((ObjBuilder*)ob); + return; + } + + memset(&param_desc, 0, sizeof(param_desc)); + param_desc.type = i32_ty; + memset(&sig, 0, sizeof(sig)); + sig.ret = i32_ty; + sig.params = &param_desc; + sig.nparams = 1; + sig.call_conv = CFREE_CG_CC_TARGET_C; + + snprintf(name_buf, sizeof(name_buf), "cg_handles_o%d", opt_level); + memset(&decl, 0, sizeof(decl)); + decl.kind = CFREE_CG_DECL_FUNC; + decl.linkage_name = cfree_sym_intern(c, name_buf); + decl.display_name = decl.linkage_name; + decl.type = cfree_cg_type_func(c, sig); + decl.sym.bind = CFREE_SB_GLOBAL; + decl.sym.visibility = CFREE_CG_VIS_DEFAULT; + sym = cfree_cg_decl(cg, decl); + EXPECT(sym != CFREE_CG_SYM_NONE, "function decl failed"); + + cfree_cg_func_begin(cg, sym); + memset(&attrs, 0, sizeof(attrs)); + attrs.name = cfree_sym_intern(c, "p"); + attrs.flags = CFREE_CG_LOCAL_ADDRESS_TAKEN; + param = cfree_cg_param(cg, 0, i32_ty, attrs); + attrs.name = cfree_sym_intern(c, "x"); + local = cfree_cg_local(cg, i32_ty, attrs); + EXPECT(local != CFREE_CG_LOCAL_NONE, "local handle is none"); + EXPECT(param != CFREE_CG_LOCAL_NONE, "param handle is none"); + EXPECT((uint32_t)param == 1u, "first local id should be param"); + EXPECT((uint32_t)local == 2u, "local id should follow param"); + EXPECT((uint32_t)local != (uint32_t)param, "local and param handles collide"); + + memset(&mem, 0, sizeof(mem)); + mem.type = i32_ty; + mem.align = cfree_cg_type_align(c, i32_ty); + + cfree_cg_push_local(cg, local); + cfree_cg_push_local_addr(cg, param); + cfree_cg_indirect(cg); + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); + + cfree_cg_push_local_addr(cg, local); + cfree_cg_indirect(cg); + cfree_cg_load(cg, mem); + cfree_cg_ret(cg); + cfree_cg_func_end(cg); + + cfree_cg_free(cg); + obj_free((ObjBuilder*)ob); +} + int main(void) { CfreeTarget target; CfreeEnv env; @@ -61,7 +142,7 @@ int main(void) { CfreeCgTypeId va_list_ty; CfreeCgTypeId ptr_i32; CfreeCgTypeId array_i32; - CfreeCgParam params[2]; + CfreeCgFuncParam params[2]; CfreeCgFuncSig sig; CfreeCgTypeId fn; CfreeCgTypeId alias; @@ -81,6 +162,7 @@ int main(void) { target.ptr_size = 8; target.ptr_align = 8; + memset(&env, 0, sizeof(env)); env.heap = &g_heap; env.file_io = NULL; env.diag = &g_diag; @@ -200,6 +282,9 @@ int main(void) { EXPECT(cfree_cg_type_func(c, sig) == CFREE_CG_TYPE_NONE, "oversized function param list should fail"); + exercise_cg_handles(c, i32_ty, 0); + exercise_cg_handles(c, i32_ty, 1); + cfree_compiler_free(c); return g_fail ? 1 : 0; } diff --git a/test/test.mk b/test/test.mk @@ -105,7 +105,7 @@ test-cg-api: $(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 $@ + $(CC) $(DRIVER_CFLAGS) -Isrc test/api/cg_type_test.c $(LIB_AR) -o $@ test-toy: bin @CFREE=$(abspath $(BIN)) test/toy/run.sh