kit

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

commit 1e34b851ae4ce33c8520189942c885db7bef59dd
parent f6c08eea644fb990f6c4deaade3b295923dfe392
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 17 Jun 2026 00:41:41 -0700

opt: legalize aggregate-move addresses (collapse a scaled index)

emit_agg_move handed its source/dest NativeAddr straight to copy_bytes without
the legalize_addr the scalar load/store path runs. copy_bytes addresses a
base+offset granule ladder with no scaled-index form, so a folded array index
was silently dropped and every element aliased element 0. This bites 32-bit
targets specifically: an 8-byte i64/double is a 'large' move there, so an
`arr[i]` access of an i64 array arrives here with the index folded into the
address (124-element sums returned seed*N). Legalize both addresses so an
index the target cannot encode collapses into a plain base register first.

Diffstat:
Msrc/opt/pass_native_emit.c | 17+++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/opt/pass_native_emit.c b/src/opt/pass_native_emit.c @@ -540,13 +540,22 @@ static int type_is_aggregate_or_large(NativeEmitCtx* e, KitCgTypeId type) { * IR_COPY/IR_LOAD/IR_STORE whose value type cannot move through one register. */ static void emit_agg_move(NativeEmitCtx* e, NativeAddr da, NativeAddr sa, - KitCgTypeId type) { + KitCgTypeId type, SrcLoc loc) { AggregateAccess acc; memset(&acc, 0, sizeof acc); acc.type = type; acc.size = type_size_or(e->c, type, 8u); acc.align = type_align_or(e->c, type, 8u); acc.mem = mem_for_type(e->c, type); + /* Legalize both addresses exactly as the scalar load/store path does: a + * copy_bytes granule ladder addresses base+offset only, so any addressing mode + * the target cannot encode — notably a scaled index, which an 8-byte i64/double + * load on a 32-bit target arrives with (it is a "large" move here, the array + * index folded into the address) — must collapse into a plain base register + * first. Without this the index is silently dropped and every element aliases + * element 0. */ + legalize_addr(e, &da, acc.mem, loc); + legalize_addr(e, &sa, acc.mem, loc); e->target->copy_bytes(e->target, da, sa, acc); } @@ -791,7 +800,7 @@ static void emit_inst(NativeEmitCtx* e, u32 block, u32 order_index, Inst* in, if (type_is_aggregate_or_large(e, in->opnds[0].type)) { emit_agg_move(e, addr_from_operand(e, &in->opnds[0], in->loc), addr_from_operand(e, &in->opnds[1], in->loc), - in->opnds[0].type); + in->opnds[0].type, in->loc); return; } dst = loc_from_operand(e, &in->opnds[0], in->loc); @@ -802,7 +811,7 @@ static void emit_inst(NativeEmitCtx* e, u32 block, u32 order_index, Inst* in, if (type_is_aggregate_or_large(e, in->opnds[0].type)) { addr = addr_from_operand(e, &in->opnds[1], in->loc); emit_agg_move(e, addr_from_operand(e, &in->opnds[0], in->loc), addr, - in->opnds[0].type); + in->opnds[0].type, in->loc); return; } dst = loc_from_operand(e, &in->opnds[0], in->loc); @@ -825,7 +834,7 @@ static void emit_inst(NativeEmitCtx* e, u32 block, u32 order_index, Inst* in, if (type_is_aggregate_or_large(e, in->opnds[1].type)) { emit_agg_move(e, addr_from_operand(e, &in->opnds[0], in->loc), addr_from_operand(e, &in->opnds[1], in->loc), - in->opnds[1].type); + in->opnds[1].type, in->loc); return; } addr = addr_from_operand(e, &in->opnds[0], in->loc);