commit faf2962b92abeaaa068ef34fca5b3a1c9dfe85e1
parent 3d2eb21daf7ec352bb0d5c59715d12beed45d2e0
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 16 Jun 2026 19:27:12 -0700
arm32 Phase 2: split wide (8-byte) memory accesses into two 4-byte halves
A handful of cg paths (notably an i64 switch scrutinee) hand the backend a single
8-byte load/store into an even/odd register pair instead of pre-splitting to
lanes; rv32 splits these in its emit, arm panicked. arm_emit_mem now emits the
low lane at [base,off] and the high lane at [base,off+4] over (rt, rt+1). Fixes
i64 switch + i64 global-array/record accesses.
Diffstat:
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/arch/arm32/native.c b/src/arch/arm32/native.c
@@ -393,7 +393,27 @@ static void arm_emit_mem(Arm32NativeTarget* a, int is_load, NativeLoc reg,
u32 rt = loc_reg(reg);
u32 size = mem.size ? mem.size : native_type_size(&a->base, reg.type);
u32 t3hw1, t4hw1;
- if (size >= 8u) arm_panic(a, "8-byte memory access not lowered (wide8 path)");
+ if (size >= 8u) {
+ /* Split a wide (8-byte) access into two 4-byte halves over the consecutive
+ * register pair: low lane = rt at [base, off], high lane = rt+1 at
+ * [base, off+4] (little-endian). The cg hands a few paths — notably an i64
+ * switch scrutinee — a single 8-byte access into an even/odd pair; rv32
+ * splits identically. (Wider-than-8 is not produced by the C frontend.) */
+ KitCgTypeId i32t = builtin_id(KIT_CG_BUILTIN_I32);
+ NativeLoc lo = reg, hi = reg;
+ NativeAddr addr_hi = addr;
+ MemAccess m = mem;
+ if (size != 8u) arm_panic(a, "memory access wider than 8 bytes");
+ m.size = 4u;
+ m.type = i32t;
+ lo.type = i32t;
+ hi.type = i32t;
+ hi.v.reg = (rt + 1u) & 0xfu;
+ addr_hi.offset += 4;
+ arm_emit_mem(a, is_load, lo, addr, m);
+ arm_emit_mem(a, is_load, hi, addr_hi, m);
+ return;
+ }
/* pick the op (T3 positive, T4 +/-) for this width. */
if (size == 1u) {
t3hw1 = is_load ? 0xf890u : 0xf880u;