kit

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

commit 324f8448f5eb6f6259e3870d714024379995936d
parent b25fcf61b2c648bb5c0376b5d6d7d04976239499
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 18 May 2026 13:26:27 -0700

fix parse aggregate and VLA lowering

Diffstat:
Mlang/c/parse/parse_expr.c | 166+++++++++++++++++++++++++++++++------------------------------------------------
Mlang/c/parse/parse_init.c | 22+++++++---------------
Mlang/c/parse/parse_type.c | 1+
Msrc/api/cg.c | 30++++++++++++++++++++----------
4 files changed, 93 insertions(+), 126 deletions(-)

diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -540,12 +540,17 @@ i64 eval_const_int(Parser* p, SrcLoc loc) { return cexpr_bor(p, loc); } * to_rvalue * ============================================================ */ +static void decay_array_to_pointer(Parser* p, const Type* arr_ty) { + const Type* ptr_ty = type_ptr(p->pool, arr_ty->arr.elem); + cfree_cg_addr_offset(p->cg, 0, pcg_tid(p->c, ptr_ty)); + pcg_retag_top(p, ptr_ty); +} + void to_rvalue(Parser* p) { const Type* t = cg_top_type(p->cg); if (t) { if (t->kind == TY_ARRAY) { - cg_addr(p->cg); - cg_retag_top(p->cg, type_ptr(p->pool, t->arr.elem)); + decay_array_to_pointer(p, t); return; } if (t->kind == TY_FUNC) { @@ -567,6 +572,8 @@ void coerce_top_to_lvalue(Parser* p) { if (!src || !dst || src == dst) return; if (type_is_arith(src) && type_is_arith(dst)) { cg_convert(p->cg, dst); + } else if (type_is_arith(src) && type_is_ptr(dst)) { + cg_convert(p->cg, dst); } } @@ -1050,6 +1057,49 @@ static void parse_primary(Parser* p) { perr(p, "expected expression"); } +static int find_record_member_path(Parser* p, const Type* rec_ty, Sym mname, + const Type** out_ty, u32 path[2], + u32* out_depth) { + const ABIRecordLayout* L; + if (!rec_ty || (rec_ty->kind != TY_STRUCT && rec_ty->kind != TY_UNION)) + return 0; + L = c_abi_record_layout(p->abi, p->pool, rec_ty); + if (!L) return 0; + for (u16 i = 0; i < rec_ty->rec.nfields; ++i) { + const Field* f = &rec_ty->rec.fields[i]; + if (f->name == mname && mname != 0) { + *out_ty = f->type; + path[0] = i; + *out_depth = 1; + return 1; + } + if ((f->flags & FIELD_ANON) && + (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) { + const ABIRecordLayout* IL = c_abi_record_layout(p->abi, p->pool, f->type); + if (!IL) continue; + for (u16 j = 0; j < f->type->rec.nfields; ++j) { + const Field* ff = &f->type->rec.fields[j]; + if (ff->name == mname && mname != 0) { + *out_ty = ff->type; + path[0] = i; + path[1] = j; + *out_depth = 2; + return 1; + } + } + } + } + return 0; +} + +static void cg_record_member_path(Parser* p, const Type* member_ty, + const u32* path, u32 depth) { + for (u32 i = 0; i < depth; ++i) { + cfree_cg_field(p->cg, path[i]); + } + pcg_retag_top(p, member_ty); +} + static void parse_postfix(Parser* p) { parse_primary(p); for (;;) { @@ -1103,8 +1153,7 @@ static void parse_postfix(Parser* p) { const Type* lt0 = cg_top_type(p->cg); advance(p); /* '[' */ if (lt0 && lt0->kind == TY_ARRAY) { - cg_addr(p->cg); - cg_retag_top(p->cg, type_ptr(p->pool, lt0->arr.elem)); + decay_array_to_pointer(p, lt0); } else if (lt0 && lt0->kind == TY_PTR) { cg_load(p->cg); } @@ -1112,8 +1161,7 @@ static void parse_postfix(Parser* p) { { const Type* it0 = cg_top_type(p->cg); if (it0 && it0->kind == TY_ARRAY) { - cg_addr(p->cg); - cg_retag_top(p->cg, type_ptr(p->pool, it0->arr.elem)); + decay_array_to_pointer(p, it0); } else { to_rvalue(p); } @@ -1146,8 +1194,8 @@ static void parse_postfix(Parser* p) { const Type* lt = cg_top_type(p->cg); Sym mname; const Type* mty = NULL; - u32 moff = 0; - const Field* mf = NULL; + u32 path[2]; + u32 depth = 0; advance(p); /* '.' */ if (!lt || (lt->kind != TY_STRUCT && lt->kind != TY_UNION)) { perr(p, @@ -1158,57 +1206,9 @@ static void parse_postfix(Parser* p) { } mname = p->cur.v.ident; advance(p); - { - const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, lt); - if (!L) perr(p, "no such member"); - int found = 0; - for (u16 i = 0; i < lt->rec.nfields; ++i) { - const Field* f = &lt->rec.fields[i]; - if (f->name == mname && mname != 0) { - mty = f->type; - moff = L->fields[i].offset; - mf = f; - found = 1; - break; - } - /* anonymous member flattening */ - if ((f->flags & FIELD_ANON) && - (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) { - const Type* inner_ty = NULL; - u32 inner_off = 0; - const Field* inner_f = NULL; - const ABIRecordLayout* IL = - c_abi_record_layout(p->abi, p->pool, f->type); - if (IL) { - for (u16 j = 0; j < f->type->rec.nfields; ++j) { - const Field* ff = &f->type->rec.fields[j]; - if (ff->name == mname && mname != 0) { - inner_ty = ff->type; - inner_off = IL->fields[j].offset; - inner_f = ff; - break; - } - } - } - if (inner_ty) { - mty = inner_ty; - moff = L->fields[i].offset + inner_off; - mf = inner_f; - found = 1; - break; - } - } - } - if (!found) perr(p, "no such member"); - } - (void)mf; - cg_addr(p->cg); - cg_retag_top(p->cg, type_ptr(p->pool, mty)); - if (moff > 0) { - cg_push_int(p->cg, (i64)moff, ty_size_t(p)); - cg_binop(p->cg, BO_IADD); - } - cg_deref(p->cg, mty); + if (!find_record_member_path(p, lt, mname, &mty, path, &depth)) + perr(p, "no such member"); + cg_record_member_path(p, mty, path, depth); continue; } if (is_punct(&t, P_ARROW)) { @@ -1216,8 +1216,8 @@ static void parse_postfix(Parser* p) { const Type* rec_ty; Sym mname; const Type* mty = NULL; - u32 moff = 0; - const Field* mf = NULL; + u32 path[2]; + u32 depth = 0; advance(p); /* `->` */ to_rvalue(p); lt0 = cg_top_type(p->cg); @@ -1233,46 +1233,10 @@ static void parse_postfix(Parser* p) { } mname = p->cur.v.ident; advance(p); - { - const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, rec_ty); - if (!L) perr(p, "no such member"); - int found = 0; - for (u16 i = 0; i < rec_ty->rec.nfields; ++i) { - const Field* f = &rec_ty->rec.fields[i]; - if (f->name == mname && mname != 0) { - mty = f->type; - moff = L->fields[i].offset; - mf = f; - found = 1; - break; - } - if ((f->flags & FIELD_ANON) && - (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) { - const ABIRecordLayout* IL = - c_abi_record_layout(p->abi, p->pool, f->type); - if (IL) { - for (u16 j = 0; j < f->type->rec.nfields; ++j) { - const Field* ff = &f->type->rec.fields[j]; - if (ff->name == mname && mname != 0) { - mty = ff->type; - moff = L->fields[i].offset + IL->fields[j].offset; - mf = ff; - found = 1; - break; - } - } - } - if (found) break; - } - } - if (!found) perr(p, "no such member"); - } - (void)mf; - if (moff > 0) { - cg_push_int(p->cg, (i64)moff, ty_size_t(p)); - cg_binop(p->cg, BO_IADD); - } - cg_deref(p->cg, mty); + if (!find_record_member_path(p, rec_ty, mname, &mty, path, &depth)) + perr(p, "no such member"); + cg_deref(p->cg, rec_ty); + cg_record_member_path(p, mty, path, depth); continue; } break; diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -16,10 +16,6 @@ * File-local helpers * ============================================================ */ -static const Type* ty_size_t_init(Parser* p) { - return c_abi_size_type(p->abi, p->pool); -} - static SrcLoc tok_loc_init(const Tok* t) { return t->loc; } static CKw ident_kw_init(const Parser* p, Sym name) { @@ -55,13 +51,10 @@ static u32 init_elided(Parser* p, FrameSlot slot, const Type* arr_ty, * local `slot` (whose type is `arr_ty`), with element type `elem_ty`. */ void push_subobject_lv(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* elem_ty) { + const Type* elem_ptr_ty = type_ptr(p->pool, elem_ty); cg_push_local_typed(p->cg, slot, arr_ty); - cg_addr(p->cg); - cg_retag_top(p->cg, type_ptr(p->pool, elem_ty)); - if (offset > 0) { - cg_push_int(p->cg, (i64)offset, ty_size_t_init(p)); - cg_binop(p->cg, BO_IADD); - } + cfree_cg_addr_offset(p->cg, (i64)offset, pcg_tid(p->c, elem_ptr_ty)); + pcg_retag_top(p, elem_ptr_ty); cg_deref(p->cg, elem_ty); } @@ -70,14 +63,12 @@ static void emit_copy_leaf(Parser* p, FrameSlot dst_slot, const Type* dst_arr_ty, u32 dst_off, FrameSlot src_ptr_slot, const Type* src_ptr_ty, u32 src_off, const Type* leaf_ty) { + const Type* leaf_ptr_ty = type_ptr(p->pool, leaf_ty); push_subobject_lv(p, dst_slot, dst_arr_ty, dst_off, leaf_ty); cg_push_local_typed(p->cg, src_ptr_slot, src_ptr_ty); cg_load(p->cg); - cg_retag_top(p->cg, type_ptr(p->pool, leaf_ty)); - if (src_off > 0) { - cg_push_int(p->cg, (i64)src_off, ty_size_t_init(p)); - cg_binop(p->cg, BO_IADD); - } + cfree_cg_addr_offset(p->cg, (i64)src_off, pcg_tid(p->c, leaf_ptr_ty)); + pcg_retag_top(p, leaf_ptr_ty); cg_deref(p->cg, leaf_ty); cg_load(p->cg); cg_store(p->cg); @@ -352,6 +343,7 @@ static u32 init_elided(Parser* p, FrameSlot slot, const Type* arr_ty, push_subobject_lv(p, slot, arr_ty, offset, ty); parse_assign_expr(p); to_rvalue(p); + coerce_top_to_lvalue(p); cg_store(p->cg); cg_drop(p->cg); if (had_brace) { diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -1032,6 +1032,7 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { to_rvalue(p); cg_push_local_typed(p->cg, out->vla_count_slot, fsd.type); cg_swap(p->cg); + coerce_top_to_lvalue(p); cg_store(p->cg); cg_drop(p->cg); p->vla_pending = 1; diff --git a/src/api/cg.c b/src/api/cg.c @@ -3421,41 +3421,51 @@ void cfree_cg_addr_offset(CfreeCg *g, int64_t byte_offset, Operand base; Operand result; Reg rr; + int want_ptr; + int base_is_lvalue; + int free_base = 0; if (!g) return; rty = resolve_type(g->c, result_type); if (!rty) return; v = api_pop(g); + want_ptr = cg_type_is_ptr(g->c, rty); + base_is_lvalue = api_is_lvalue_sv(&v); if (v.source_local != CFREE_CG_LOCAL_NONE) api_local_const_clear(api_local_from_handle(g, v.source_local)); api_ensure_reg(g, &v); if (v.op.kind == OPK_GLOBAL) { result = api_op_global(v.op.v.global.sym, v.op.v.global.addend + byte_offset, rty); - api_push(g, cg_type_is_ptr(g->c, rty) ? api_make_sv(result, rty) - : api_make_lv(result, rty)); + api_push(g, want_ptr ? api_make_sv(result, rty) : api_make_lv(result, rty)); return; } - if (v.op.kind == OPK_INDIRECT) { + if (!want_ptr && v.op.kind == OPK_INDIRECT) { i64 ofs = (i64)v.op.v.ind.ofs + byte_offset; if (ofs >= INT32_MIN && ofs <= INT32_MAX) { result = api_op_indirect(v.op.v.ind.base, (i32)ofs, rty); - api_push(g, cg_type_is_ptr(g->c, rty) ? api_make_sv(result, rty) - : api_make_lv(result, rty)); + api_push(g, api_make_lv(result, rty)); return; } } - ptr_ty = cg_type_is_ptr(g->c, api_sv_type(&v)) ? api_sv_type(&v) - : cg_type_ptr_to(g->c, rty); - base = api_is_lvalue_sv(&v) ? api_force_reg(g, &v, ptr_ty) - : api_force_reg(g, &v, ptr_ty); + ptr_ty = want_ptr ? rty : cg_type_ptr_to(g->c, rty); + if (!base_is_lvalue && cg_type_is_ptr(g->c, api_sv_type(&v))) + ptr_ty = api_sv_type(&v); + if (base_is_lvalue) { + base = api_lvalue_addr(g, &v, ptr_ty); + free_base = 1; + } else { + base = api_force_reg(g, &v, ptr_ty); + } rr = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); result = api_op_reg(rr, ptr_ty); g->target->binop(g->target, BO_IADD, result, base, api_op_imm(byte_offset, ptr_ty)); + if (free_base) + api_free_reg(g, base.v.reg, RC_INT); api_release(g, &v); - if (cg_type_is_ptr(g->c, rty)) { + if (want_ptr) { result.type = rty; api_push(g, api_make_sv(result, rty)); } else {