w6c: f32 arg-push/pop uses MOVSS not MOVSD (#143)

cstage spilled f32 args via MOVSD (8-byte); ABI-correct is MOVSS (4-byte,
single class) per SysV (ref/qbe amd64/emit.c:524 — slot-copy-through-XMM
follows the float class). wwstage already emitted MOVSS; align cstage up
via op_for(node_isf32) at the arg PUSH (cgen.c:5366) + POP (cgen.c:5469).
Byte-id-only divergence (callee reads the f32 param low-32 regardless),
but it blocked cs==ww — closes the f32-arg-push half of the float-register
family (#119/#122/#125/#157). Bootstrap-NEUTRAL (no f32-arg caller in the
990-997 gated path). Test 907_f32arg_run (f32-arg push single/multi/mixed/
stack, cs==ww byte-id). Make test 187/187 incl 990-997.

Unblocks fold-5b (strconv f32tos passes f32 to f32bits).
This commit is contained in:
2026-05-27 16:17:09 +09:00
parent 0e66073e32
commit aff7725f8f
3 changed files with 248 additions and 2 deletions

View File

@@ -5364,8 +5364,14 @@ cgexpr(Cg *c, Node *n, Local *locals)
}
cgexpr(c, args[i], locals);
if (node_isfloat(args[i])) {
/* f32 spills 4B (MOVSS), f64 8B (MOVSD): the SysV
* float class drives the width per ref/qbe
* amd64/emit.c:524 (slot-copy single→movss). The
* slot is 8B either way; the pop reads the same
* width back. #143. */
int fmov = op_for(args[i], A_MOVSD, A_MOVSS);
ins2(c, A_SUBQ, aimm(8), areg(D_SP));
ins2(c, A_MOVSD, areg(D_X0), amem(D_SP, 0));
ins2(c, fmov, areg(D_X0), amem(D_SP, 0));
} else if (node_isstr(args[i])) {
/* str IS []u8: cgexpr left (AX=ptr, BX=len,
* CX=cap). Push the triple, same as slice
@@ -5468,7 +5474,12 @@ cgexpr(Cg *c, Node *n, Local *locals)
}
if (node_isfloat(args[i])) {
if (fi < 8) {
ins2(c, A_MOVSD, amem(D_SP, 0),
/* Reload the spilled f32/f64 at its class
* width — MOVSS for f32, MOVSD for f64 —
* matching the push above (#143). */
int fmov = op_for(args[i], A_MOVSD,
A_MOVSS);
ins2(c, fmov, amem(D_SP, 0),
areg(sysv_fargregs[fi]));
ins2(c, A_ADDQ, aimm(8), areg(D_SP));
fi++;