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:
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