w6c: receive sub-8 odd-sized by-value struct/array CALL return (#107)

A struct/array sized {3,5,6,7} returned by value fell past every N_LET call-receive arm (the sized-tail arm handles {1,2,4}, the memcpy arm gates on sz>8), so cstage emitted nothing and silently DROPPED the CALL — garbage exit plus a gate-blind cs!=ww divergence (wwstage emitted CALL+MOVQ via its generic let fallback). Align cstage UP: emit the CALL + one MOVQ AX, the SysV single-eightbyte receive (ref/qbe/amd64/sysv.c retr). New table-driven gate 949 (runtime exit oracle on both drivers + cs==ww byte-id; negative-control proven).
This commit is contained in:
2026-06-19 12:47:23 +09:00
parent 3bb381ef48
commit 1466f50a09
3 changed files with 292 additions and 0 deletions

View File

@@ -12940,6 +12940,30 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
goto letlink;
}
}
/* #107: a struct/array call-receive whose size is a single
* eightbyte (< 8B) but NOT one of the sized-tail widths
* {1,2,4} — i.e. sz ∈ {3,5,6,7}, reachable via @packed (#51,
* e.g. @packed{u8,u32}=5) and natural sub-8 maxalign-1 shapes
* (struct{u8,u8,u8}=3) — is ONE INTEGER eightbyte returned in
* RAX (ref/qbe/amd64/sysv.c retr: the n*8<size loop runs once).
* The producer zero-pads AX to 24B and localslot rounds every
* slot up to 8B, so a single full-word MOVQ stores it cleanly.
* Pre-fix this size fell past EVERY arm (the sized-tail arm
* below excludes these tails; the memcpy arm gates on sz>8) and
* cstage emitted NOTHING — the CALL was silently DROPPED, while
* wwstage emitted CALL + MOVQ AX via its generic let fallback
* (cgenstmt.ww:3007): gate-blind cs≠ww AND a silent miscompile.
* Aligns cstage UP to wwstage's SysV-correct single-MOVQ
* receive. Task #107. */
if (n->rhs && n->rhs->kind == N_CALL && lu
&& (lu->kind == TY_STRUCT || lu->kind == TY_ARRAY)
&& sz < 8
&& (sz % 8 == 3 || sz % 8 == 5
|| sz % 8 == 6 || sz % 8 == 7)) {
cgexpr(c, n->rhs, *locals);
ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off));
goto letlink;
}
if (n->rhs && n->rhs->kind == N_CALL && lu
&& (lu->kind == TY_STRUCT || lu->kind == TY_ARRAY)
&& sz <= 24