kit

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

commit e364e60ef0f3fab4cc3ca9a074933888e414d543
parent b66a8bce2eac0fbc4869ba95e78c1a8a081bfed9
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 19 May 2026 22:04:36 -0700

Fix signed pointer index lowering

Diffstat:
Mlang/c/parse/parse_expr.c | 25+++++++++++++------------
Msrc/cg/arith.c | 34++++++++++++++++++++++++++++++++++
Atest/link/cases/38_macho_bss_linkedit_gap/a.c | 8++++++++
Atest/link/cases/38_macho_bss_linkedit_gap/expected | 1+
Atest/link/cases/38_macho_bss_linkedit_gap/j_targets | 1+
Atest/link/cases/38_macho_bss_linkedit_gap/targets | 1+
Atest/parse/cases/6_5_6_01_negative_pointer_subscript.c | 6++++++
Atest/parse/cases/6_5_6_01_negative_pointer_subscript.expected | 1+
8 files changed, 65 insertions(+), 12 deletions(-)

diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -2031,6 +2031,7 @@ static void parse_postfix(Parser* p) { perr(p, "invalid subscript: needs one pointer and one integer"); } if (!elem) perr(p, "subscript on incomplete pointee"); + coerce_top_to_type(p, c_abi_ptrdiff_type(p->abi, p->pool)); { FrameSlot elem_vla_slot = vla_size_slot_for_type(vla_bounds, elem); if (elem_vla_slot != FRAME_SLOT_NONE) { @@ -2563,6 +2564,15 @@ static void parse_mul(Parser* p) { } } +static void scale_pointer_index(Parser* p, u32 elem_size) { + const Type* idx_ty = c_abi_ptrdiff_type(p->abi, p->pool); + coerce_top_to_type(p, idx_ty); + if (elem_size != 1) { + cg_push_int(p->cg, (i64)elem_size, idx_ty); + cg_binop(p->cg, BO_IMUL); + } +} + static void emit_add_or_sub(Parser* p, BinOp bop) { const Type* lt = cg_top2_type(p->cg); const Type* rt = cg_top_type(p->cg); @@ -2576,10 +2586,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { if (lt->ptr.pointee && lt->ptr.pointee->kind == TY_VOID) perr(p, "pointer arithmetic on void pointer"); u32 esz = c_abi_sizeof(p->abi, lt->ptr.pointee); - if (esz != 1) { - cg_push_int(p->cg, (i64)esz, ty_size_t(p)); - cg_binop(p->cg, BO_IMUL); - } + scale_pointer_index(p, esz); cg_binop(p->cg, BO_IADD); return; } @@ -2588,10 +2595,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { perr(p, "pointer arithmetic on void pointer"); cg_swap(p->cg); u32 esz = c_abi_sizeof(p->abi, rt->ptr.pointee); - if (esz != 1) { - cg_push_int(p->cg, (i64)esz, ty_size_t(p)); - cg_binop(p->cg, BO_IMUL); - } + scale_pointer_index(p, esz); cg_binop(p->cg, BO_IADD); return; } @@ -2600,10 +2604,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { if (lt->ptr.pointee && lt->ptr.pointee->kind == TY_VOID) perr(p, "pointer arithmetic on void pointer"); u32 esz = c_abi_sizeof(p->abi, lt->ptr.pointee); - if (esz != 1) { - cg_push_int(p->cg, (i64)esz, ty_size_t(p)); - cg_binop(p->cg, BO_IMUL); - } + scale_pointer_index(p, esz); cg_binop(p->cg, BO_ISUB); return; } diff --git a/src/cg/arith.c b/src/cg/arith.c @@ -1,5 +1,31 @@ #include "cg/internal.h" +static int api_try_fold_int_convert(CfreeCg* g, ConvKind ck, CfreeCgTypeId sty, + CfreeCgTypeId dty, i64 in, i64* out) { + u32 sw; + u32 dw; + u64 r; + if (!g || !out || !api_foldable_int_like_type(g->c, sty, &sw) || + !api_foldable_int_like_type(g->c, dty, &dw)) { + return 0; + } + switch (ck) { + case CV_SEXT: + r = (u64)api_sign_extend_width((u64)in, sw); + break; + case CV_ZEXT: + r = api_mask_width((u64)in, sw); + break; + case CV_TRUNC: + r = api_mask_width((u64)in, dw); + break; + default: + return 0; + } + *out = api_fold_result(g->c, dty, r, dw); + return 1; +} + void api_cg_binop(CfreeCg* g, BinOp iop, u32 flags) { ApiSValue b, a; CGTarget* T; @@ -379,6 +405,14 @@ void api_cg_convert_kind(CfreeCg* g, CfreeCgTypeId dst_type, ConvKind ck) { api_push(g, api_make_sv(dst, dty)); return; } + if (api_sv_op_is(&v, OPK_IMM)) { + i64 folded; + if (api_try_fold_int_convert(g, ck, sty, dty, v.op.v.imm, &folded)) { + api_release(g, &v); + api_push(g, api_make_sv(api_op_imm(folded, dty), dty)); + return; + } + } if (ck == CV_BITCAST && abi_cg_sizeof(g->c->abi, sty) == abi_cg_sizeof(g->c->abi, dst_type) && api_type_class(sty) == api_type_class(dty)) { diff --git a/test/link/cases/38_macho_bss_linkedit_gap/a.c b/test/link/cases/38_macho_bss_linkedit_gap/a.c @@ -0,0 +1,8 @@ +static unsigned long long big[1400]; + +int test_main(void) { + if (big[700] != 0) return 1; + if (big[1000] != 0) return 2; + big[1000] = 5; + return big[1000] == 5 ? 0 : 3; +} diff --git a/test/link/cases/38_macho_bss_linkedit_gap/expected b/test/link/cases/38_macho_bss_linkedit_gap/expected @@ -0,0 +1 @@ +0 diff --git a/test/link/cases/38_macho_bss_linkedit_gap/j_targets b/test/link/cases/38_macho_bss_linkedit_gap/j_targets @@ -0,0 +1 @@ + diff --git a/test/link/cases/38_macho_bss_linkedit_gap/targets b/test/link/cases/38_macho_bss_linkedit_gap/targets @@ -0,0 +1 @@ +aa64-macho diff --git a/test/parse/cases/6_5_6_01_negative_pointer_subscript.c b/test/parse/cases/6_5_6_01_negative_pointer_subscript.c @@ -0,0 +1,6 @@ +int test_main(void) { + char buf[8]; + char *p = &buf[4]; + buf[3] = 17; + return p[-1] == 17 ? 0 : 1; +} diff --git a/test/parse/cases/6_5_6_01_negative_pointer_subscript.expected b/test/parse/cases/6_5_6_01_negative_pointer_subscript.expected @@ -0,0 +1 @@ +0