From 6a586cf79226cbe2fd3b1d810492b8621252ca82 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 25 May 2026 14:29:34 +0900 Subject: [PATCH] cgen: wwstage cglet spills both eightbytes of a 16B tuple-from-call receive (#102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wwstage-only. cglet had no 16B whole-tuple-from-call receive branch, so `let t = call()` whose callee returns a 2-eightbyte (16B) tuple fell through to the generic single-word store (MOVQ AX, off(BP)) and never spilled word1 (the DX eightbyte) — silent loss of t.1. Align to cstage cgen.c:6652, which spills both AX->off+0 and DX->off+8. Not a tupstore cursor off-by-one and not f64-specific: the destructure form `let (a,b) = call()` (cgmlet + tupstore cursor) was already byte-id; only the whole-tuple N_LET receive dropped word1, for any element mix incl. all-integer (i64,i64). An f64 element surfaced it first. The f64 element rides its eightbyte in AX/DX at receive and is re-read from X0/XMM at field-read (already byte-id), so no SSE cursor is needed. --- selfhost/cmd/wcc/cgenstmt.ww | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/selfhost/cmd/wcc/cgenstmt.ww b/selfhost/cmd/wcc/cgenstmt.ww index 6cac2f74..34b01c40 100644 --- a/selfhost/cmd/wcc/cgenstmt.ww +++ b/selfhost/cmd/wcc/cgenstmt.ww @@ -864,6 +864,26 @@ fn cglet(c: *cgen, n: *node) void = { }; }; }; + // 16B tuple init from a function call: SysV returns a + // 16-byte aggregate across the integer cursor (AX, DX). Spill + // BOTH eightbytes over the integer registers — an f64 element + // also rides its eightbyte in AX/DX here and is re-read from + // X0/XMM at field-read time, so no SSE cursor is needed (the + // f64 read is already byte-id). Mirror of cstage cgen.c:6652. + // Without this branch a 16B tuple receive (any element mix, + // incl. all-integer) fell to the generic single-word store + // below and dropped word1 — silent loss of t.1 (#102). + if (rettupleof(c, rhs) != nil && sz == 16) { + cgexpr(c, rhs); + emitline("\tMOVQ\tAX, "); + emitoff(off: i64); + emitline("(BP)\n"); + emitline("\tMOVQ\tDX, "); + emitoff((off + 8): i64); + emitline("(BP)\n"); + c.lastwasreturn = 0; + return; + }; // Array literal init: `let xs: [N]T = [a, b, c];` (or [_]T). // Walk elements in declaration order, store each at off + i*esz // using the right width for the element type. Trailing `...`