kit

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

commit cf6f708e3c566f50f7f625d7e08d6718f0e2fdda
parent 0b6eaea8eb3bdcdbc9a6ce0e51d95c3da1385ff3
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 12 May 2026 20:58:19 -0700

Implement CfreeCg public codegen API driving CGTarget directly

Add full value-stack-based codegen implementation (CfreeCg) that drives
CGTarget vtable calls directly, bypassing the internal CG layer. Covers
function lifecycle with C-symbol mangling, local/param slots, push ops,
load/addr/store (with toy frontend stack convention), stack manipulation,
arithmetic/compare/convert with public-to-internal enum mapping, labels
and conditional branches, structured scopes with break/continue, and
ABI-classified call/return. Remaining APIs (float, bytes, alloca, va_*,
atomics, intrinsics, inline asm, data defs, memcpy/memset, index,
field_addr, tail_call) are stubbed for future extension.

Diffstat:
Mlang/toy/toy.c | 12+++++++-----
Msrc/api/cg.c | 1405+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 1412 insertions(+), 5 deletions(-)

diff --git a/lang/toy/toy.c b/lang/toy/toy.c @@ -9,16 +9,18 @@ /* ============================================================ * CG API coverage checklist — APIs NOT yet exercised by toy: * - * Types: + * Types (query): + * cfree_cg_type_is_ptr / ptr_pointee + * cfree_cg_type_is_func / func_ret / func_nparams / func_param + * cfree_cg_type_is_record / record_nfields / record_field + * cfree_cg_type_size / type_align + * + * Types (constructors): * cfree_cg_type_array * cfree_cg_type_qualified * cfree_cg_type_alias * cfree_cg_type_record * cfree_cg_type_enum - * cfree_cg_type_is_ptr / ptr_pointee - * cfree_cg_type_is_func / func_ret / func_nparams / func_param - * cfree_cg_type_is_record / record_nfields / record_field - * cfree_cg_type_size / type_align * * Functions & data: * cfree_cg_func_decl diff --git a/src/api/cg.c b/src/api/cg.c @@ -4,9 +4,11 @@ #include "api/cg_api.h" #include "abi/abi.h" +#include "arch/arch.h" #include "core/arena.h" #include "core/heap.h" #include "core/segvec.h" +#include "obj/obj.h" #include "type/type.h" typedef enum CgApiTypeKind { @@ -462,3 +464,1406 @@ void cg_api_fini(Compiler* c) { c->cg_api = NULL; c->cg_api_free = NULL; } + +/* ============================================================ + * CfreeCg: public codegen API implementation + * + * Drives CGTarget directly with its own value stack, mirroring + * the internal CG in src/cg/cg.c but without depending on it. + * ============================================================ */ + +typedef enum SResidency { + RES_INHERENT, + RES_REG, + RES_SPILLED, +} SResidency; + +typedef struct ApiSValue { + Operand op; + const Type* type; + u8 res; + u8 pinned; + u8 pad[2]; + FrameSlot spill_slot; +} ApiSValue; + +#define API_CG_STACK_INITIAL 16u + +typedef struct ApiCgScope { + Label break_lbl; + Label continue_lbl; + const Type* result_type; +} ApiCgScope; + +#define API_CG_MAX_SCOPES 64 + +struct CfreeCg { + Compiler* c; + ObjBuilder* obj; + CGTarget* target; + MCEmitter* mc; + + ApiSValue* stack; + u32 sp; + u32 cap; + + struct { + FrameSlot* free; + u32 n; + u32 cap; + } slot_pools[3]; + + CGABIValue* avs_in_flight; + u32 avs_in_flight_n; + + const Type* fn_ret_type; + const ABIFuncInfo* fn_abi; + SrcLoc cur_loc; + + CGFuncDesc fn_desc; + CGParamDesc fn_params[64]; + + ApiCgScope scopes[API_CG_MAX_SCOPES]; + u32 nscopes; +}; + +/* ---- value stack helpers ---- */ + +static u8 api_type_class(const Type* ty) { + if (ty && (ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE || + ty->kind == TY_LDOUBLE)) { + return RC_FP; + } + return RC_INT; +} + +static Operand api_op_imm(i64 v, const Type* ty) { + Operand o; + memset(&o, 0, sizeof o); + o.kind = OPK_IMM; + o.cls = api_type_class(ty); + o.type = ty; + o.v.imm = v; + return o; +} + +static Operand api_op_reg(Reg r, const Type* ty) { + Operand o; + memset(&o, 0, sizeof o); + o.kind = OPK_REG; + o.cls = api_type_class(ty); + o.type = ty; + o.v.reg = r; + return o; +} + +static Operand api_op_local(FrameSlot s, const Type* ty) { + Operand o; + memset(&o, 0, sizeof o); + o.kind = OPK_LOCAL; + o.cls = RC_INT; + o.type = ty; + o.v.frame_slot = s; + return o; +} + +static Operand api_op_global(ObjSymId sym, i64 addend, const Type* ty) { + Operand o; + memset(&o, 0, sizeof o); + o.kind = OPK_GLOBAL; + o.cls = RC_INT; + o.type = ty; + o.v.global.sym = sym; + o.v.global.addend = addend; + return o; +} + +static u8 api_residency_for(const Operand* o) { + if (o->kind == OPK_REG || o->kind == OPK_INDIRECT) return RES_REG; + return RES_INHERENT; +} + +static ApiSValue api_make_sv(Operand op, const Type* ty) { + ApiSValue sv; + memset(&sv, 0, sizeof sv); + sv.op = op; + sv.type = ty; + sv.res = api_residency_for(&op); + sv.spill_slot = FRAME_SLOT_NONE; + return sv; +} + +static const Type* api_sv_type(const ApiSValue* sv) { + return sv->type ? sv->type : sv->op.type; +} + +static int api_is_lvalue(const Operand* o) { + return o->kind == OPK_LOCAL || o->kind == OPK_GLOBAL || + o->kind == OPK_INDIRECT; +} + +static void api_stack_grow(CfreeCg* g, u32 want) { + Heap* h = g->c->env->heap; + u32 cap = g->cap; + ApiSValue* nb; + if (cap >= want) return; + while (cap < want) cap = cap ? cap * 2u : API_CG_STACK_INITIAL; + nb = (ApiSValue*)h->alloc(h, sizeof(ApiSValue) * cap, _Alignof(ApiSValue)); + if (g->stack) { + memcpy(nb, g->stack, sizeof(ApiSValue) * g->sp); + h->free(h, g->stack, sizeof(ApiSValue) * g->cap); + } + g->stack = nb; + g->cap = cap; +} + +static void api_push(CfreeCg* g, ApiSValue v) { + api_stack_grow(g, g->sp + 1); + g->stack[g->sp++] = v; +} + +static ApiSValue api_pop(CfreeCg* g) { + if (g->sp == 0) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: stack underflow"); + } + return g->stack[--g->sp]; +} + +/* ---- register class helpers ---- */ + +static u8 api_class_of_sv(const ApiSValue* sv) { + if (sv->op.kind == OPK_IMM || sv->op.kind == OPK_REG) + return sv->op.cls; + return RC_INT; +} + +static Reg api_reg_of_sv(const ApiSValue* sv) { + if (sv->op.kind == OPK_REG) return sv->op.v.reg; + if (sv->op.kind == OPK_INDIRECT) return sv->op.v.ind.base; + return (Reg)REG_NONE; +} + +static void api_set_owned_reg(ApiSValue* sv, Reg r) { + if (sv->op.kind == OPK_REG) sv->op.v.reg = r; + else if (sv->op.kind == OPK_INDIRECT) sv->op.v.ind.base = r; +} + +/* ---- spill slot management ---- */ + +static void api_take_spill_slot_alloc(CfreeCg* g, u8 cls, FrameSlot* out) { + CGTarget* T = g->target; + FrameSlotDesc fsd; + memset(&fsd, 0, sizeof fsd); + fsd.kind = FS_SPILL; + fsd.size = (cls == RC_FP) ? 8 : 8; + fsd.align = (cls == RC_FP) ? 8 : 8; + *out = T->frame_slot(T, &fsd); +} + +static FrameSlot api_take_spill_slot(CfreeCg* g, u8 cls) { + if (cls < 3 && g->slot_pools[cls].n > 0) { + return g->slot_pools[cls].free[--g->slot_pools[cls].n]; + } + FrameSlot s; + api_take_spill_slot_alloc(g, cls, &s); + return s; +} + +static void api_return_spill_slot(CfreeCg* g, FrameSlot s, u8 cls) { + Heap* h; + if (cls >= 3) return; + h = g->c->env->heap; + if (g->slot_pools[cls].n >= g->slot_pools[cls].cap) { + u32 new_cap = g->slot_pools[cls].cap ? g->slot_pools[cls].cap * 2 : 8; + FrameSlot* nb = (FrameSlot*)h->alloc(h, sizeof(FrameSlot) * new_cap, _Alignof(FrameSlot)); + if (g->slot_pools[cls].free) { + memcpy(nb, g->slot_pools[cls].free, sizeof(FrameSlot) * g->slot_pools[cls].n); + h->free(h, g->slot_pools[cls].free, sizeof(FrameSlot) * g->slot_pools[cls].cap); + } + g->slot_pools[cls].free = nb; + g->slot_pools[cls].cap = new_cap; + } + g->slot_pools[cls].free[g->slot_pools[cls].n++] = s; +} + +/* ---- register allocation / spill ---- */ + +static ApiSValue* api_pick_victim(CfreeCg* g, u8 cls) { + for (u32 i = 0; i < g->sp; ++i) { + ApiSValue* sv = &g->stack[i]; + if (sv->res != RES_REG || sv->pinned) continue; + if (api_class_of_sv(sv) != cls) continue; + return sv; + } + return NULL; +} + +static int api_spill_avs_victim(CfreeCg* g, u8 cls) { + CGTarget* T = g->target; + for (u32 i = 0; i < g->avs_in_flight_n; ++i) { + CGABIValue* av = &g->avs_in_flight[i]; + if (av->storage.kind != OPK_REG) continue; + if (av->storage.cls != cls) continue; + FrameSlot slot = api_take_spill_slot(g, cls); + MemAccess ma; + memset(&ma, 0, sizeof ma); + ma.type = av->type; + ma.size = av->type ? abi_sizeof(g->c->abi, av->type) : 8; + ma.align = av->type ? abi_alignof(g->c->abi, av->type) : 8; + T->spill_reg(T, av->storage, slot, ma); + Operand local = api_op_local(slot, av->type); + local.cls = cls; + av->storage = local; + return 1; + } + return 0; +} + +static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, const Type* ty) { + MemAccess m; + memset(&m, 0, sizeof m); + m.type = ty; + m.size = ty ? abi_sizeof(g->c->abi, ty) : 0; + m.align = ty ? abi_alignof(g->c->abi, ty) : 0; + m.flags = MF_NONE; + if (ty && (ty->qual & Q_VOLATILE)) m.flags |= MF_VOLATILE; + if (lv->kind == OPK_LOCAL) { + m.alias.kind = (u8)ALIAS_LOCAL; + m.alias.v.local_id = (i32)lv->v.frame_slot; + } else if (lv->kind == OPK_GLOBAL) { + m.alias.kind = (u8)ALIAS_GLOBAL; + } else { + m.alias.kind = (u8)ALIAS_UNKNOWN; + } + return m; +} + +static MemAccess api_mem_for_spill(CfreeCg* g, const ApiSValue* sv) { + const Type* ty = api_sv_type(sv); + MemAccess m; + memset(&m, 0, sizeof m); + m.type = ty; + m.size = ty ? abi_sizeof(g->c->abi, ty) : 8; + m.align = ty ? abi_alignof(g->c->abi, ty) : 8; + m.alias.kind = (u8)ALIAS_UNKNOWN; + return m; +} + +static Reg api_alloc_reg_or_spill(CfreeCg* g, u8 cls, const Type* ty) { + CGTarget* T = g->target; + Reg r = T->alloc_reg(T, cls, ty); + if (r != (Reg)REG_NONE) return r; + + ApiSValue* victim = api_pick_victim(g, cls); + if (victim) { + FrameSlot slot = api_take_spill_slot(g, cls); + Operand victim_reg = api_op_reg((Reg)api_reg_of_sv(victim), victim->type); + T->spill_reg(T, victim_reg, slot, api_mem_for_spill(g, victim)); + victim->spill_slot = slot; + victim->res = RES_SPILLED; + api_set_owned_reg(victim, (Reg)REG_NONE); + } else if (!api_spill_avs_victim(g, cls)) { + compiler_panic(g->c, g->cur_loc, + "CfreeCg: regalloc - no spillable victim (class %u)", + (unsigned)cls); + } + + r = T->alloc_reg(T, cls, ty); + if (r == (Reg)REG_NONE) { + compiler_panic(g->c, g->cur_loc, + "CfreeCg: regalloc - class %u still empty after spill", + (unsigned)cls); + } + return r; +} + +static void api_ensure_reg(CfreeCg* g, ApiSValue* sv) { + if (sv->res != RES_SPILLED) return; + CGTarget* T = g->target; + u8 cls = api_class_of_sv(sv); + const Type* ty = api_sv_type(sv); + Reg r = api_alloc_reg_or_spill(g, cls, ty ? ty : type_prim(g->c->global, TY_INT)); + T->reload_reg(T, api_op_reg(r, ty), sv->spill_slot, api_mem_for_spill(g, sv)); + api_return_spill_slot(g, sv->spill_slot, cls); + sv->spill_slot = FRAME_SLOT_NONE; + if (sv->op.kind == OPK_INDIRECT) { + sv->op.v.ind.base = r; + } else { + sv->op = api_op_reg(r, api_sv_type(sv)); + } + sv->res = RES_REG; +} + +static Operand api_force_reg(CfreeCg* g, ApiSValue* v, const Type* ty) { + CGTarget* T = g->target; + api_ensure_reg(g, v); + if (v->op.kind == OPK_REG) return v->op; + Reg r = api_alloc_reg_or_spill(g, api_type_class(ty), ty); + Operand dst = api_op_reg(r, ty); + if (v->op.kind == OPK_IMM) { + T->load_imm(T, dst, v->op.v.imm); + } else if (api_is_lvalue(&v->op)) { + T->load(T, dst, v->op, api_mem_for_lvalue(g, &v->op, ty)); + if (v->op.kind == OPK_INDIRECT) { + T->free_reg(T, v->op.v.ind.base, RC_INT); + } + } else { + compiler_panic(g->c, g->cur_loc, "CfreeCg: cannot force operand to register"); + } + v->op = dst; + v->res = RES_REG; + return dst; +} + +static Operand api_force_reg_unless_imm(CfreeCg* g, ApiSValue* v, const Type* ty) { + if (v->op.kind == OPK_IMM) return v->op; + return api_force_reg(g, v, ty); +} + +static void api_release(CfreeCg* g, ApiSValue* sv) { + if (sv->res == RES_REG) { + g->target->free_reg(g->target, (Reg)api_reg_of_sv(sv), api_class_of_sv(sv)); + } else if (sv->res == RES_SPILLED) { + api_return_spill_slot(g, sv->spill_slot, api_class_of_sv(sv)); + sv->spill_slot = FRAME_SLOT_NONE; + } + sv->res = RES_INHERENT; +} + +static void api_release_arg_storage(CfreeCg* g, Operand* storage) { + if (storage->kind == OPK_REG) { + g->target->free_reg(g->target, storage->v.reg, storage->cls); + } else if (storage->kind == OPK_LOCAL && storage->cls < 3) { + api_return_spill_slot(g, storage->v.frame_slot, storage->cls); + } +} + +/* ---- BinOp / UnOp / CmpOp mapping ---- */ + +static BinOp api_map_binop(CfreeCgBinOp op) { + switch (op) { + case CFREE_CG_ADD: return BO_IADD; + case CFREE_CG_SUB: return BO_ISUB; + case CFREE_CG_MUL: return BO_IMUL; + case CFREE_CG_SDIV: return BO_SDIV; + case CFREE_CG_UDIV: return BO_UDIV; + case CFREE_CG_SREM: return BO_SREM; + case CFREE_CG_UREM: return BO_UREM; + case CFREE_CG_AND: return BO_AND; + case CFREE_CG_OR: return BO_OR; + case CFREE_CG_XOR: return BO_XOR; + case CFREE_CG_SHL: return BO_SHL; + case CFREE_CG_SHR_S: return BO_SHR_S; + case CFREE_CG_SHR_U: return BO_SHR_U; + } + return BO_IADD; +} + +static UnOp api_map_unop(CfreeCgUnOp op) { + switch (op) { + case CFREE_CG_NEG: return UO_NEG; + case CFREE_CG_NOT: return UO_NOT; + case CFREE_CG_BNOT: return UO_BNOT; + } + return UO_NEG; +} + +static CmpOp api_map_cmp(CfreeCgCmpOp op) { + switch (op) { + case CFREE_CG_EQ: return CMP_EQ; + case CFREE_CG_NE: return CMP_NE; + case CFREE_CG_LT_S: return CMP_LT_S; + case CFREE_CG_LE_S: return CMP_LE_S; + case CFREE_CG_GT_S: return CMP_GT_S; + case CFREE_CG_GE_S: return CMP_GE_S; + case CFREE_CG_LT_U: return CMP_LT_U; + case CFREE_CG_LE_U: return CMP_LE_U; + case CFREE_CG_GT_U: return CMP_GT_U; + case CFREE_CG_GE_U: return CMP_GE_U; + } + return CMP_EQ; +} + +/* ---- C-symbol mangling ---- */ + +static Sym api_c_mangle(Compiler* c, CfreeSym name) { + size_t len; + const char* str = pool_str(c->global, (Sym)name, &len); + if (!str) return 0; + return obj_format_c_mangle(c, str); +} + +static SymBind api_map_bind(CfreeSymBind b) { + switch (b) { + case CFREE_SB_LOCAL: return SB_LOCAL; + case CFREE_SB_GLOBAL: return SB_GLOBAL; + case CFREE_SB_WEAK: return SB_WEAK; + } + return SB_LOCAL; +} + +/* ============================================================ + * Public API: CfreeCg lifecycle + * ============================================================ */ + +CfreeCg* cfree_cg_new(CfreeCompiler* c, CfreeObjBuilder* out) { + Heap* h; + CfreeCg* g; + MCEmitter* mc; + CGTarget* target; + if (!c || !out) return NULL; + h = (Heap*)c->env->heap; + mc = mc_new((Compiler*)c, (ObjBuilder*)out); + if (!mc) return NULL; + target = cgtarget_new((Compiler*)c, (ObjBuilder*)out, mc); + if (!target) { + mc_free(mc); + return NULL; + } + g = (CfreeCg*)h->alloc(h, sizeof(CfreeCg), _Alignof(CfreeCg)); + if (!g) { + cgtarget_free(target); + mc_free(mc); + return NULL; + } + memset(g, 0, sizeof *g); + g->c = (Compiler*)c; + g->obj = (ObjBuilder*)out; + g->target = target; + g->mc = mc; + return g; +} + +void cfree_cg_free(CfreeCg* g) { + Heap* h; + if (!g) return; + cgtarget_finalize(g->target); + cgtarget_free(g->target); + mc_free(g->mc); + h = g->c->env->heap; + if (g->stack) h->free(h, g->stack, sizeof(ApiSValue) * g->cap); + for (u32 c = 0; c < 3; ++c) { + if (g->slot_pools[c].free) { + h->free(h, g->slot_pools[c].free, sizeof(FrameSlot) * g->slot_pools[c].cap); + } + } + h->free(h, g, sizeof *g); +} + +/* ============================================================ + * Source location + * ============================================================ */ + +void cfree_cg_set_loc(CfreeCg* g, CfreeSrcLoc loc) { + if (!g) return; + g->cur_loc = *(SrcLoc*)&loc; + if (g->target->set_loc) g->target->set_loc(g->target, *(SrcLoc*)&loc); +} + +/* ============================================================ + * Function lifecycle + * ============================================================ */ + +void cfree_cg_func_decl(CfreeCg* g, CfreeSym name, CfreeCgTypeId fn_type, + CfreeCgDeclAttrs attrs) { + Compiler* c; + ObjBuilder* ob; + Sym mangled; + ObjSymId sym; + const Type* fty; + if (!g) return; + c = g->c; + ob = g->obj; + fty = resolve_type(c, fn_type); + if (!fty) return; + mangled = api_c_mangle(c, name); + sym = obj_symbol_find(ob, mangled); + if (sym == OBJ_SYM_NONE) { + sym = obj_symbol(ob, mangled, api_map_bind(attrs.bind), SK_FUNC, + OBJ_SEC_NONE, 0, 0); + } + if (attrs.flags & CFREE_CG_DECL_DEFINED) { + ObjSecId text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), + SEC_TEXT, SF_EXEC | SF_ALLOC, 4); + obj_symbol_define(ob, sym, text_sec, 0, 0); + } + (void)fn_type; +} + +void cfree_cg_func_begin(CfreeCg* g, CfreeSym name, CfreeCgTypeId fn_type, + CfreeCgDeclAttrs attrs) { + Compiler* c; + ObjBuilder* ob; + CGTarget* T; + Sym mangled; + ObjSymId sym; + ObjSecId text_sec; + const Type* fty; + const ABIFuncInfo* abi; + if (!g) return; + c = g->c; + ob = g->obj; + T = g->target; + fty = resolve_type(c, fn_type); + if (!fty) return; + abi = abi_func_info(c->abi, fty); + + mangled = api_c_mangle(c, name); + sym = obj_symbol_find(ob, mangled); + text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), + SEC_TEXT, SF_EXEC | SF_ALLOC, 4); + + if (sym == OBJ_SYM_NONE) { + sym = obj_symbol(ob, mangled, api_map_bind(attrs.bind), SK_FUNC, + text_sec, 0, 0); + } else { + obj_symbol_define(ob, sym, text_sec, 0, 0); + } + + memset(&g->fn_desc, 0, sizeof g->fn_desc); + g->fn_desc.sym = sym; + g->fn_desc.text_section_id = text_sec; + g->fn_desc.group_id = OBJ_GROUP_NONE; + g->fn_desc.fn_type = fty; + g->fn_desc.abi = abi; + g->fn_desc.loc = g->cur_loc; + if (attrs.flags & CFREE_CG_DECL_NORETURN) g->fn_desc.flags |= CGFD_NORETURN; + + g->fn_ret_type = fty->fn.ret; + g->fn_abi = abi; + g->sp = 0; + for (u32 i = 0; i < 3; ++i) g->slot_pools[i].n = 0; + g->avs_in_flight = NULL; + g->avs_in_flight_n = 0; + + T->func_begin(T, &g->fn_desc); +} + +void cfree_cg_func_end(CfreeCg* g) { + if (!g) return; + g->target->func_end(g->target); + g->fn_abi = NULL; + g->fn_ret_type = NULL; +} + +/* ============================================================ + * Local / param slots + * ============================================================ */ + +CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, CfreeSym name) { + const Type* ty; + FrameSlotDesc fsd; + if (!g) return 0; + ty = resolve_type(g->c, type); + if (!ty) return 0; + memset(&fsd, 0, sizeof fsd); + fsd.type = ty; + fsd.name = (Sym)name; + fsd.loc = g->cur_loc; + fsd.size = abi_sizeof(g->c->abi, ty); + fsd.align = abi_alignof(g->c->abi, ty); + fsd.kind = FS_LOCAL; + return (CfreeCgSlot)g->target->frame_slot(g->target, &fsd); +} + +CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, + CfreeSym name) { + const Type* ty; + FrameSlot slot; + CGParamDesc pd; + FrameSlotDesc fsd; + if (!g) return 0; + ty = resolve_type(g->c, type); + if (!ty) return 0; + + memset(&fsd, 0, sizeof fsd); + fsd.type = ty; + fsd.name = (Sym)name; + fsd.loc = g->cur_loc; + fsd.size = abi_sizeof(g->c->abi, ty); + fsd.align = abi_alignof(g->c->abi, ty); + fsd.kind = FS_PARAM; + slot = g->target->frame_slot(g->target, &fsd); + + memset(&pd, 0, sizeof pd); + pd.index = index; + pd.name = (Sym)name; + pd.type = ty; + pd.slot = slot; + if (g->fn_abi && index < g->fn_abi->nparams) { + pd.abi = &g->fn_abi->params[index]; + } + pd.loc = g->cur_loc; + g->target->param(g->target, &pd); + + return (CfreeCgSlot)slot; +} + +/* ============================================================ + * Push operations + * ============================================================ */ + +void cfree_cg_push_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { + const Type* ty; + if (!g) return; + ty = resolve_type(g->c, type); + if (!ty) return; + api_push(g, api_make_sv(api_op_imm((i64)value, ty), ty)); +} + +void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { + (void)g; (void)value; (void)type; +} + +void cfree_cg_push_bytes(CfreeCg* g, const uint8_t* str, size_t len, + CfreeCgTypeId pointee_type) { + (void)g; (void)str; (void)len; (void)pointee_type; +} + +void cfree_cg_push_local(CfreeCg* g, CfreeCgSlot slot) { + if (!g) return; + api_push(g, api_make_sv(api_op_local((FrameSlot)slot, NULL), NULL)); +} + +void cfree_cg_push_symbol(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, + CfreeCgSymbolRefKind kind, int64_t addend) { + Sym mangled; + ObjSymId sym; + const Type* ty; + if (!g) return; + ty = resolve_type(g->c, type); + if (!ty) return; + mangled = api_c_mangle(g->c, name); + sym = obj_symbol_find(g->obj, mangled); + if (sym == OBJ_SYM_NONE) { + sym = obj_symbol(g->obj, mangled, SB_GLOBAL, SK_FUNC, + OBJ_SEC_NONE, 0, 0); + } + (void)kind; + api_push(g, api_make_sv(api_op_global(sym, addend, ty), ty)); +} + +/* ============================================================ + * Load / addr / store + * ============================================================ */ + +void cfree_cg_load(CfreeCg* g) { + ApiSValue v; + const Type* ty; + Operand dst; + if (!g) return; + v = api_pop(g); + api_ensure_reg(g, &v); + if (!api_is_lvalue(&v.op)) { + api_push(g, v); + return; + } + ty = api_sv_type(&v); + dst = api_force_reg(g, &v, ty); + api_push(g, api_make_sv(dst, ty)); +} + +void cfree_cg_addr(CfreeCg* g) { + ApiSValue v; + CGTarget* T; + const Type* pty; + Reg r; + Operand dst; + if (!g) return; + T = g->target; + v = api_pop(g); + api_ensure_reg(g, &v); + if (!api_is_lvalue(&v.op)) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: addr operand is not an lvalue"); + return; + } + pty = type_ptr(g->c->global, api_sv_type(&v)); + r = api_alloc_reg_or_spill(g, RC_INT, pty); + dst = api_op_reg(r, pty); + T->addr_of(T, dst, v.op); + api_release(g, &v); + api_push(g, api_make_sv(dst, pty)); +} + +void cfree_cg_store(CfreeCg* g) { + ApiSValue lv, rv; + CGTarget* T; + const Type* ty; + Operand src; + if (!g) return; + T = g->target; + /* Toy frontend pushes rvalue then lvalue: stack is [..., rv, lv]. + * Pop lv first (TOS), then rv. */ + lv = api_pop(g); + rv = api_pop(g); + api_ensure_reg(g, &lv); + api_ensure_reg(g, &rv); + if (!api_is_lvalue(&lv.op)) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: store destination is not an lvalue"); + return; + } + ty = api_sv_type(&lv); + if (rv.op.kind == OPK_IMM || rv.op.kind == OPK_REG) { + src = rv.op; + } else { + src = api_force_reg(g, &rv, api_sv_type(&rv)); + } + T->store(T, lv.op, src, api_mem_for_lvalue(g, &lv.op, ty)); + api_release(g, &lv); + api_push(g, api_make_sv(src, ty)); +} + +/* ============================================================ + * Stack manipulation + * ============================================================ */ + +void cfree_cg_dup(CfreeCg* g) { + ApiSValue v; + if (!g || g->sp == 0) return; + v = g->stack[g->sp - 1]; + if (v.op.kind == OPK_REG && v.res == RES_REG) { + Reg r = api_alloc_reg_or_spill(g, v.op.cls, v.type); + Operand dst = api_op_reg(r, v.type); + g->target->copy(g->target, dst, v.op); + api_push(g, api_make_sv(dst, v.type)); + } else { + api_push(g, v); + } +} + +void cfree_cg_swap(CfreeCg* g) { + ApiSValue tmp; + if (!g || g->sp < 2) return; + tmp = g->stack[g->sp - 1]; + g->stack[g->sp - 1] = g->stack[g->sp - 2]; + g->stack[g->sp - 2] = tmp; +} + +void cfree_cg_drop(CfreeCg* g) { + ApiSValue v; + if (!g) return; + v = api_pop(g); + api_release(g, &v); +} + +void cfree_cg_rot3(CfreeCg* g) { + ApiSValue a, b, c; + if (!g || g->sp < 3) return; + a = g->stack[g->sp - 3]; + b = g->stack[g->sp - 2]; + c = g->stack[g->sp - 1]; + g->stack[g->sp - 3] = b; + g->stack[g->sp - 2] = c; + g->stack[g->sp - 1] = a; +} + +/* ============================================================ + * Arithmetic / compare / convert + * ============================================================ */ + +void cfree_cg_binop(CfreeCg* g, CfreeCgBinOp op) { + ApiSValue b, a; + CGTarget* T; + const Type* ty; + BinOp iop; + Operand ra, rb; + Reg rr; + Operand dst; + if (!g) return; + T = g->target; + b = api_pop(g); + a = api_pop(g); + ty = a.type ? a.type : b.type; + iop = api_map_binop(op); + + ra = api_force_reg_unless_imm(g, &a, ty); + rb = api_force_reg_unless_imm(g, &b, ty); + rr = api_alloc_reg_or_spill(g, api_type_class(ty), ty); + dst = api_op_reg(rr, ty); + T->binop(T, iop, dst, ra, rb); + api_release(g, &a); + api_release(g, &b); + api_push(g, api_make_sv(dst, ty)); +} + +void cfree_cg_unop(CfreeCg* g, CfreeCgUnOp op) { + ApiSValue a; + CGTarget* T; + const Type* ty; + UnOp iop; + Operand ra; + Reg rr; + Operand dst; + if (!g) return; + T = g->target; + a = api_pop(g); + ty = a.type ? a.type : a.op.type; + iop = api_map_unop(op); + + ra = api_force_reg_unless_imm(g, &a, ty); + rr = api_alloc_reg_or_spill(g, api_type_class(ty), ty); + dst = api_op_reg(rr, ty); + T->unop(T, iop, dst, ra); + api_release(g, &a); + api_push(g, api_make_sv(dst, ty)); +} + +void cfree_cg_cmp(CfreeCg* g, CfreeCgCmpOp op) { + ApiSValue b, a; + CGTarget* T; + const Type* opty; + const Type* i32; + CmpOp cop; + Operand ra, rb; + Reg rr; + Operand dst; + if (!g) return; + T = g->target; + b = api_pop(g); + a = api_pop(g); + opty = a.type ? a.type : b.type; + i32 = type_prim(g->c->global, TY_INT); + cop = api_map_cmp(op); + + ra = api_force_reg_unless_imm(g, &a, opty); + rb = api_force_reg_unless_imm(g, &b, opty); + rr = api_alloc_reg_or_spill(g, RC_INT, i32); + dst = api_op_reg(rr, i32); + T->cmp(T, cop, dst, ra, rb); + api_release(g, &a); + api_release(g, &b); + api_push(g, api_make_sv(dst, i32)); +} + +void cfree_cg_convert(CfreeCg* g, CfreeCgTypeId dst_type) { + ApiSValue v; + CGTarget* T; + const Type* sty; + const Type* dty; + ConvKind ck; + Operand src; + Reg rr; + Operand dst; + int s_int, d_int, s_flt, d_flt, s_ptr, d_ptr; + u32 s_sz, d_sz; + int s_signed; + if (!g) return; + T = g->target; + dty = resolve_type(g->c, dst_type); + if (!dty) return; + v = api_pop(g); + sty = v.type ? v.type : v.op.type; + if (sty == dty) { + api_push(g, v); + return; + } + + s_int = type_is_int(sty); + d_int = type_is_int(dty); + s_flt = sty && (sty->kind == TY_FLOAT || sty->kind == TY_DOUBLE); + d_flt = dty && (dty->kind == TY_FLOAT || dty->kind == TY_DOUBLE); + s_sz = sty ? abi_sizeof(g->c->abi, sty) : 0; + d_sz = dty ? abi_sizeof(g->c->abi, dty) : 0; + s_signed = sty ? abi_type_info(g->c->abi, sty).signed_ : 0; + s_ptr = type_is_ptr(sty); + d_ptr = type_is_ptr(dty); + + { + int s_int_or_ptr = s_int || s_ptr; + int d_int_or_ptr = d_int || d_ptr; + if (s_int_or_ptr && d_int_or_ptr) { + if (d_sz < s_sz) { + ck = CV_TRUNC; + } else if (d_sz > s_sz) { + ck = (s_int && s_signed) ? CV_SEXT : CV_ZEXT; + } else { + v.type = dty; + v.op.type = dty; + api_push(g, v); + return; + } + } else if (s_int && d_flt) { + ck = s_signed ? CV_ITOF_S : CV_ITOF_U; + } else if (s_flt && d_int) { + int d_signed = abi_type_info(g->c->abi, dty).signed_; + ck = d_signed ? CV_FTOI_S : CV_FTOI_U; + } else if (s_flt && d_flt) { + ck = (d_sz > s_sz) ? CV_FEXT : CV_FTRUNC; + } else { + ck = CV_BITCAST; + } + } + + src = api_force_reg(g, &v, sty); + rr = api_alloc_reg_or_spill(g, api_type_class(dty), dty); + dst = api_op_reg(rr, dty); + T->convert(T, ck, dst, src); + api_release(g, &v); + api_push(g, api_make_sv(dst, dty)); +} + +/* ============================================================ + * Intrinsics (stub) + * ============================================================ */ + +void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, + CfreeCgTypeId result_type) { + (void)g; (void)intrin; (void)nargs; (void)result_type; +} + +/* ============================================================ + * Atomics (stub) + * ============================================================ */ + +void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemOrder order) { + (void)g; (void)order; +} + +void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemOrder order) { + (void)g; (void)order; +} + +void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgAtomicOp op, CfreeCgMemOrder order) { + (void)g; (void)op; (void)order; +} + +void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemOrder success, + CfreeCgMemOrder failure) { + (void)g; (void)success; (void)failure; +} + +void cfree_cg_atomic_fence(CfreeCg* g, CfreeCgMemOrder order) { + (void)g; (void)order; +} + +/* ============================================================ + * Inline asm (stub) + * ============================================================ */ + +void cfree_cg_inline_asm(CfreeCg* g, CfreeSym tmpl, + const CfreeCgAsmOperand* outputs, uint32_t noutputs, + const CfreeCgAsmOperand* inputs, uint32_t ninputs, + const CfreeSym* clobbers, uint32_t nclobbers, + uint32_t flags) { + (void)g; (void)tmpl; (void)outputs; (void)noutputs; + (void)inputs; (void)ninputs; (void)clobbers; (void)nclobbers; (void)flags; +} + +/* ============================================================ + * Labels / branches + * ============================================================ */ + +CfreeCgLabel cfree_cg_label_new(CfreeCg* g) { + if (!g) return CFREE_CG_LABEL_NONE; + return (CfreeCgLabel)g->target->label_new(g->target); +} + +void cfree_cg_label_place(CfreeCg* g, CfreeCgLabel label) { + if (!g) return; + g->target->label_place(g->target, (Label)label); +} + +void cfree_cg_jump(CfreeCg* g, CfreeCgLabel label) { + if (!g) return; + g->target->jump(g->target, (Label)label); +} + +void cfree_cg_branch_true(CfreeCg* g, CfreeCgLabel label) { + ApiSValue v; + CGTarget* T; + const Type* ty; + if (!g) return; + T = g->target; + v = api_pop(g); + ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + if (v.op.kind == OPK_IMM) { + if (v.op.v.imm != 0) T->jump(T, (Label)label); + api_release(g, &v); + return; + } + { + Operand a = api_force_reg(g, &v, ty); + Operand zero = api_op_imm(0, ty); + T->cmp_branch(T, CMP_NE, a, zero, (Label)label); + api_release(g, &v); + } +} + +void cfree_cg_branch_false(CfreeCg* g, CfreeCgLabel label) { + ApiSValue v; + CGTarget* T; + const Type* ty; + if (!g) return; + T = g->target; + v = api_pop(g); + ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + if (v.op.kind == OPK_IMM) { + if (v.op.v.imm == 0) T->jump(T, (Label)label); + api_release(g, &v); + return; + } + { + Operand a = api_force_reg(g, &v, ty); + Operand zero = api_op_imm(0, ty); + T->cmp_branch(T, CMP_EQ, a, zero, (Label)label); + api_release(g, &v); + } +} + +/* ============================================================ + * Scopes / structured control flow + * ============================================================ */ + +CfreeCgScope cfree_cg_scope_begin(CfreeCg* g, CfreeCgTypeId result_type) { + Label break_lbl, cont_lbl; + CGScopeDesc d; + ApiCgScope* s; + if (!g) return 0; + break_lbl = g->target->label_new(g->target); + cont_lbl = g->target->label_new(g->target); + g->target->label_place(g->target, cont_lbl); + + if (g->nscopes >= API_CG_MAX_SCOPES) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: too many nested scopes"); + return 0; + } + s = &g->scopes[g->nscopes]; + s->break_lbl = break_lbl; + s->continue_lbl = cont_lbl; + s->result_type = resolve_type(g->c, result_type); + g->nscopes++; + + memset(&d, 0, sizeof d); + d.kind = (u8)SCOPE_LOOP; + d.break_label = break_lbl; + d.continue_label = cont_lbl; + d.result_type = s->result_type; + (void)g->target->scope_begin(g->target, &d); + + return (CfreeCgScope)g->nscopes; +} + +void cfree_cg_scope_end(CfreeCg* g, CfreeCgScope scope) { + u32 idx; + if (!g || scope == 0) return; + idx = (u32)scope - 1; + if (idx >= g->nscopes) return; + g->target->label_place(g->target, g->scopes[idx].break_lbl); + g->target->scope_end(g->target, (CGScope)scope); +} + +void cfree_cg_break(CfreeCg* g, CfreeCgScope scope) { + u32 idx; + if (!g || scope == 0) return; + idx = (u32)scope - 1; + if (idx >= g->nscopes) return; + g->target->jump(g->target, g->scopes[idx].break_lbl); +} + +void cfree_cg_break_true(CfreeCg* g, CfreeCgScope scope) { + u32 idx; + ApiSValue v; + CGTarget* T; + const Type* ty; + if (!g || scope == 0) return; + idx = (u32)scope - 1; + if (idx >= g->nscopes) return; + T = g->target; + v = api_pop(g); + ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + + if (g->scopes[idx].result_type && g->scopes[idx].result_type->kind != TY_VOID) { + cfree_cg_swap(g); + { + ApiSValue val = api_pop(g); + api_ensure_reg(g, &val); + Operand a = api_force_reg(g, &val, ty); + Operand zero = api_op_imm(0, ty); + T->cmp_branch(T, CMP_NE, a, zero, g->scopes[idx].break_lbl); + api_release(g, &val); + } + { + ApiSValue result = api_pop(g); + api_push(g, result); + } + } else { + if (v.op.kind == OPK_IMM) { + if (v.op.v.imm != 0) T->jump(T, g->scopes[idx].break_lbl); + api_release(g, &v); + } else { + Operand a = api_force_reg(g, &v, ty); + Operand zero = api_op_imm(0, ty); + T->cmp_branch(T, CMP_NE, a, zero, g->scopes[idx].break_lbl); + api_release(g, &v); + } + } +} + +void cfree_cg_break_false(CfreeCg* g, CfreeCgScope scope) { + u32 idx; + ApiSValue v; + CGTarget* T; + const Type* ty; + if (!g || scope == 0) return; + idx = (u32)scope - 1; + if (idx >= g->nscopes) return; + T = g->target; + v = api_pop(g); + ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + + if (g->scopes[idx].result_type && g->scopes[idx].result_type->kind != TY_VOID) { + cfree_cg_swap(g); + { + ApiSValue val = api_pop(g); + api_ensure_reg(g, &val); + Operand a = api_force_reg(g, &val, ty); + Operand zero = api_op_imm(0, ty); + T->cmp_branch(T, CMP_EQ, a, zero, g->scopes[idx].break_lbl); + api_release(g, &val); + } + { + ApiSValue result = api_pop(g); + api_push(g, result); + } + } else { + if (v.op.kind == OPK_IMM) { + if (v.op.v.imm == 0) T->jump(T, g->scopes[idx].break_lbl); + api_release(g, &v); + } else { + Operand a = api_force_reg(g, &v, ty); + Operand zero = api_op_imm(0, ty); + T->cmp_branch(T, CMP_EQ, a, zero, g->scopes[idx].break_lbl); + api_release(g, &v); + } + } +} + +void cfree_cg_continue(CfreeCg* g, CfreeCgScope scope) { + u32 idx; + if (!g || scope == 0) return; + idx = (u32)scope - 1; + if (idx >= g->nscopes) return; + g->target->jump(g->target, g->scopes[idx].continue_lbl); +} + +void cfree_cg_continue_true(CfreeCg* g, CfreeCgScope scope) { + (void)g; (void)scope; +} + +void cfree_cg_continue_false(CfreeCg* g, CfreeCgScope scope) { + (void)g; (void)scope; +} + +/* ============================================================ + * Dynamic stack allocation / variadics (stubs) + * ============================================================ */ + +void cfree_cg_alloca(CfreeCg* g, CfreeCgTypeId result_ptr_type, uint32_t align) { + (void)g; (void)result_ptr_type; (void)align; +} + +void cfree_cg_va_start(CfreeCg* g) { (void)g; } +void cfree_cg_va_arg(CfreeCg* g, CfreeCgTypeId type) { (void)g; (void)type; } +void cfree_cg_va_end(CfreeCg* g) { (void)g; } +void cfree_cg_va_copy(CfreeCg* g) { (void)g; } + +/* ============================================================ + * Memory operations (stubs) + * ============================================================ */ + +void cfree_cg_memcpy(CfreeCg* g, uint32_t size, uint32_t align) { + (void)g; (void)size; (void)align; +} + +void cfree_cg_memset(CfreeCg* g, uint8_t val, uint32_t size, uint32_t align) { + (void)g; (void)val; (void)size; (void)align; +} + +void cfree_cg_index(CfreeCg* g, uint32_t offset) { + (void)g; (void)offset; +} + +void cfree_cg_field_addr(CfreeCg* g, uint32_t field_index) { + (void)g; (void)field_index; +} + +/* ============================================================ + * Calls / return + * ============================================================ */ + +void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { + CGTarget* T; + const Type* fty; + const ABIFuncInfo* abi; + const Type* ret_ty; + int has_result; + CGABIValue* avs; + CGCallDesc desc; + ApiSValue callee; + if (!g) return; + T = g->target; + fty = resolve_type(g->c, fn_type); + if (!fty) return; + abi = abi_func_info(g->c->abi, fty); + ret_ty = fty->fn.ret; + has_result = ret_ty && ret_ty->kind != TY_VOID; + + if (g->sp < (u32)nargs + 1u) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: call stack underflow"); + return; + } + + avs = NULL; + if (nargs) { + avs = arena_array(g->c->tu, CGABIValue, nargs); + memset(avs, 0, sizeof(CGABIValue) * nargs); + } + + g->avs_in_flight = avs; + g->avs_in_flight_n = nargs; + + for (u32 i = 0; i < nargs; ++i) { + u32 idx = nargs - 1u - i; + ApiSValue arg = api_pop(g); + api_ensure_reg(g, &arg); + int is_vararg = (idx >= abi->nparams); + const Type* aty; + if (is_vararg) { + aty = arg.type ? arg.type : api_sv_type(&arg); + } else { + aty = fty->fn.params ? fty->fn.params[idx] : arg.type; + } + avs[idx].type = aty; + avs[idx].abi = is_vararg ? NULL : &abi->params[idx]; + int is_aggregate = aty && (aty->kind == TY_STRUCT || aty->kind == TY_UNION); + if (is_aggregate) { + Operand st = arg.op; + st.type = aty; + avs[idx].storage = st; + avs[idx].size = abi_sizeof(g->c->abi, aty); + } else { + avs[idx].storage = + api_is_lvalue(&arg.op) ? api_force_reg(g, &arg, aty) : arg.op; + } + } + + callee = api_pop(g); + api_ensure_reg(g, &callee); + Operand callee_op = (callee.op.kind == OPK_GLOBAL) + ? callee.op + : api_force_reg(g, &callee, fty); + + memset(&desc, 0, sizeof desc); + desc.fn_type = fty; + desc.abi = abi; + desc.callee = callee_op; + desc.args = avs; + desc.nargs = nargs; + desc.flags = CG_CALL_NONE; + desc.ret.type = ret_ty; + desc.ret.abi = &abi->ret; + + if (has_result) { + int ret_is_aggregate = + ret_ty->kind == TY_STRUCT || ret_ty->kind == TY_UNION; + if (ret_is_aggregate) { + FrameSlotDesc fsd; + memset(&fsd, 0, sizeof fsd); + fsd.type = ret_ty; + fsd.size = abi_sizeof(g->c->abi, ret_ty); + fsd.align = abi_alignof(g->c->abi, ret_ty); + fsd.kind = FS_LOCAL; + fsd.flags = FSF_ADDR_TAKEN; + FrameSlot ret_slot = T->frame_slot(T, &fsd); + desc.ret.storage = api_op_local(ret_slot, ret_ty); + } else { + Reg r = api_alloc_reg_or_spill(g, api_type_class(ret_ty), ret_ty); + desc.ret.storage = api_op_reg(r, ret_ty); + } + } + + T->call(T, &desc); + + for (u32 i = 0; i < nargs; ++i) { + api_release_arg_storage(g, &avs[i].storage); + } + g->avs_in_flight = NULL; + g->avs_in_flight_n = 0; + + if (callee.op.kind != OPK_GLOBAL) { + T->free_reg(T, callee_op.v.reg, RC_INT); + } + + if (has_result) { + api_push(g, api_make_sv(desc.ret.storage, ret_ty)); + } +} + +void cfree_cg_tail_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { + (void)g; (void)nargs; (void)fn_type; +} + +void cfree_cg_ret(CfreeCg* g) { + ApiSValue v; + CGTarget* T; + const Type* rty; + CGABIValue av; + Operand ret_op; + if (!g) return; + T = g->target; + rty = g->fn_ret_type; + if (!rty || rty->kind == TY_VOID) { + T->ret(T, NULL); + return; + } + v = api_pop(g); + memset(&av, 0, sizeof av); + av.type = rty; + av.abi = &g->fn_abi->ret; + int is_aggregate = rty->kind == TY_STRUCT || rty->kind == TY_UNION; + if (is_aggregate) { + av.storage = v.op; + av.storage.type = rty; + av.size = abi_sizeof(g->c->abi, rty); + T->ret(T, &av); + return; + } + ret_op = api_force_reg(g, &v, rty); + av.storage = ret_op; + T->ret(T, &av); + api_release(g, &v); +} + +void cfree_cg_ret_void(CfreeCg* g) { + if (!g) return; + g->target->ret(g->target, NULL); +} + +/* ============================================================ + * Data definitions (stubs) + * ============================================================ */ + +void cfree_cg_data_decl(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, + CfreeCgDeclAttrs attrs) { + (void)g; (void)name; (void)type; (void)attrs; +} + +void cfree_cg_data_begin(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, + CfreeCgDeclAttrs attrs) { + (void)g; (void)name; (void)type; (void)attrs; +} + +void cfree_cg_data_bytes(CfreeCg* g, const uint8_t* data, size_t len) { + (void)g; (void)data; (void)len; +} + +void cfree_cg_data_zero(CfreeCg* g, uint64_t size) { + (void)g; (void)size; +} + +void cfree_cg_data_symbol(CfreeCg* g, CfreeCgSymbolRefKind kind, + CfreeSym target, int64_t addend, uint32_t nbytes) { + (void)g; (void)kind; (void)target; (void)addend; (void)nbytes; +} + +void cfree_cg_data_end(CfreeCg* g) { (void)g; }