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.
27 lines
639 B
C
27 lines
639 B
C
/*
|
|
* C-FFI variadic test fixture (C1, catB-54). A va_arg(double) summer the
|
|
* ww caller links against to prove the SysV AL=XMM-count fix: the callee
|
|
* gates its xmm-save-area stores on `test %al,%al`, so a wrong AL makes
|
|
* these va_arg(double) reads pull garbage.
|
|
*
|
|
* Built self-contained (zero relocs, zero undef syms) so w6l can link it
|
|
* with no libc — verified via readelf -r / nm. Do not add any call that
|
|
* pulls in a libc symbol.
|
|
*/
|
|
#include <stdarg.h>
|
|
|
|
double
|
|
fixture(long n, ...)
|
|
{
|
|
va_list ap;
|
|
double s;
|
|
long i;
|
|
|
|
va_start(ap, n);
|
|
s = 0;
|
|
for(i = 0; i < n; i++)
|
|
s += va_arg(ap, double);
|
|
va_end(ap);
|
|
return s;
|
|
}
|