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:
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(¶m_desc, 0, sizeof(param_desc));
+ param_desc.type = i32_ty;
+ memset(&sig, 0, sizeof(sig));
+ sig.ret = i32_ty;
+ sig.params = ¶m_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