w6c: set variadic-call AL to XMM-reg count, not hardcoded 0 (catB-54 C1)
SysV §3.5.7 requires a variadic call to set AL = number of vector (XMM) regs used for the variable float args; the C callee gates its xmm-save-area stores on `test %al,%al`, so the old hardcoded XORQ AX,AX (AL=0) made va_arg(double) read garbage for any float-bearing C variadic call. Emit MOVQ $fi,AX (fi = the in-scope XMM cursor, ≤8); w6a has no MOVL-immediate encoding so MOVQ is the assemblable form and sets AL=fi identically. fi==0 keeps XORQ → byte-identical to pre-fix for no-float variadic calls. Runtime test 989_ffivariadic links a cc-compiled va_arg(double) fixture (zero relocs/undefined, w6l-linkable) and sweeps N=3/5/8 floats (N=2 is vacuous via stale-stack aliasing). C1 of the C-FFI-variadic align-up (USER ruling); C2 wwstage + C3 bodiless gate follow. ref/qbe/amd64/sysv.c:384. 454 green.
This commit is contained in:
@@ -10215,11 +10215,20 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
areg(D_DI));
|
||||
}
|
||||
}
|
||||
/* SysV: variadic callees require AL to hold the count of
|
||||
* XMM regs used in the variable portion. We don't pass
|
||||
* floats yet, so AL=0 covers every case we emit. */
|
||||
if (cu && cu->kind == TY_FN && cu->variadic)
|
||||
ins2(c, A_XORQ, areg(D_AX), areg(D_AX));
|
||||
/* SysV §3.5.7: a variadic call must set AL to the number of
|
||||
* vector (XMM) regs used to pass the variable float args — the
|
||||
* callee gates its xmm-save-area stores on `test %al,%al`, so a
|
||||
* wrong AL makes va_arg(double) read garbage. fi is the XMM
|
||||
* cursor (capped at 8 above). cstage formerly hardcoded AL=0,
|
||||
* correct only for zero-float variadic calls. Ref ref/qbe/
|
||||
* amd64/sysv.c:384. MOVL-imm has no w6a encoding, so the imm→reg
|
||||
* MOVQ idiom carries it (AL = low byte, fi ≤ 8). */
|
||||
if (cu && cu->kind == TY_FN && cu->variadic) {
|
||||
if (fi > 0)
|
||||
ins2(c, A_MOVQ, aimm(fi), areg(D_AX));
|
||||
else
|
||||
ins2(c, A_XORQ, areg(D_AX), areg(D_AX));
|
||||
}
|
||||
if (n->lhs->kind == N_IDENT) {
|
||||
/* If the callee names a local variable holding a
|
||||
* function pointer, load it and call indirect. Without
|
||||
|
||||
Reference in New Issue
Block a user