kit

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

commit 7ea57a999f6e38192ca781416198d64c778cc276
parent d33227bb2f34d7317626dd64e31ce3e96f455bf8
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 27 May 2026 05:49:32 -0700

opt: handle aggregate-typed COPY/LOAD/STORE via byte copy

Aggregate values flow through IR_COPY/IR_LOAD/IR_STORE (e.g. assigning a
struct-returning call result, copying a record local). These were emitted as
scalar moves, truncating to one register width and reading wrong field
offsets. Route aggregate / >8-byte value types through copy_bytes via a new
emit_agg_move helper.

Fixes record-by-value return and slice cases (130, 124) on the optimizer
path. Default test path remains 408/408. Remaining bypass-off failures: tail
+ sret (36, 37) and inline asm (7 cases).

Diffstat:
Msrc/opt/pass_native_emit.c | 37+++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+), 0 deletions(-)

diff --git a/src/opt/pass_native_emit.c b/src/opt/pass_native_emit.c @@ -464,6 +464,25 @@ static void write_loc(NativeEmitCtx* e, NativeLoc dst, NativeLoc src, e->target->store(e->target, addr, src, mem); } +static int type_is_aggregate_or_large(NativeEmitCtx* e, CfreeCgTypeId type) { + return type && + (cg_type_is_aggregate(e->c, type) || type_size_or(e->c, type, 8u) > 8u); +} + +/* Copy an aggregate / oversized value between two memory locations. dst and + * src must be addressable (frame/global/indirect/reg-as-pointer); used for + * 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, + CfreeCgTypeId type) { + 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); + e->target->copy_bytes(e->target, da, sa, acc); +} + static CGFuncDesc semantic_func_desc(NativeEmitCtx* e) { OptCGFuncDesc* in = &e->f->desc; CGFuncDesc out; @@ -733,11 +752,23 @@ static void emit_inst(NativeEmitCtx* e, u32 block, u32 order_index, Inst* in, e->target->load_const(e->target, dst, in->extra.cbytes); return; case IR_COPY: + 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); + return; + } dst = loc_from_operand(e, &in->opnds[0], in->loc); src = loc_from_operand(e, &in->opnds[1], in->loc); write_loc(e, dst, src, mem_for_type(e->c, in->opnds[0].type), in->loc); return; case IR_LOAD: + 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); + return; + } dst = loc_from_operand(e, &in->opnds[0], in->loc); addr = addr_from_operand(e, &in->opnds[1], in->loc); legalize_addr(e, &addr, in->extra.mem, in->loc); @@ -755,6 +786,12 @@ static void emit_inst(NativeEmitCtx* e, u32 block, u32 order_index, Inst* in, } return; case IR_STORE: + 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); + return; + } addr = addr_from_operand(e, &in->opnds[0], in->loc); legalize_addr(e, &addr, in->extra.mem, in->loc); src = loc_from_operand(e, &in->opnds[1], in->loc);