diff --git a/Makefile b/Makefile index 520418d7..739e95ab 100644 --- a/Makefile +++ b/Makefile @@ -431,7 +431,7 @@ MISC_WW_TARGETS = $(MISC_WW_TESTS:%=wwtest/%) TOOL_WW_TESTS = test/tool/rejects_test.ww test/tool/driver_test.ww \ test/tool/wwdump_test.ww test/tool/ffi_test.ww \ test/tool/attest_test.ww test/tool/wwirune_test.ww \ - test/tool/c6soak_test.ww + test/tool/c6soak_test.ww test/tool/ffivariadic_test.ww TOOL_WW_TARGETS = $(TOOL_WW_TESTS:%=wwtest/%) BOOTSTRAP_WRAPPER_SOURCES = test/wcc/950_selfcheck.c \ test/wcc/991_w6a_ww.c \ @@ -464,18 +464,19 @@ $(BIN)/test_400_w6c: test/wcc/400_w6c.c \ $(BIN)/test_%: test/wcc/%.c test/wcc/wwtestpkg.h $(LIB)/libwcc.a | $(BIN) $(CC) $(CFLAGS) $(INCS) -o $@ $< $(LIB)/libwcc.a -# 989_ffivariadic depends on a C callee archive the harness finds via -# $(BIN)/../ffivariadic. The fixture is built self-contained (zero -# relocs + undef syms) so w6l links it with no libc; flags are fixed, -# NOT $(CFLAGS), to keep that property. The rule was dropped in the -# test-graph rewrite (228a632a) and a stale out/ tree masked it. +# test/tool/ffivariadic_test.ww links a C callee archive it reaches +# via testenv.repo() + /out/ffivariadic. The fixture is built +# self-contained (zero relocs + undef syms) so w6l links it with no +# libc; flags are fixed, NOT $(CFLAGS), to keep that property. The +# rule was dropped in the test-graph rewrite (228a632a) and a stale +# out/ tree masked it. $(OUT)/ffivariadic/libffifix.a: test/wcc/data/ffivariadic/fixture.c @mkdir -p $(OUT)/ffivariadic $(CC) -O1 -fno-stack-protector -fno-asynchronous-unwind-tables \ -fcf-protection=none -c -o $(OUT)/ffivariadic/fixture.o $< $(AR) rcs $@ $(OUT)/ffivariadic/fixture.o -$(BIN)/test_989_ffivariadic_run: $(OUT)/ffivariadic/libffifix.a +wwtest/test/tool/ffivariadic_test.ww: $(OUT)/ffivariadic/libffifix.a # Native library tests execute their source owner directly. The retired C # launchers added no assertion beyond this exit status. diff --git a/test/tool/ffivariadic_test.ww b/test/tool/ffivariadic_test.ww new file mode 100644 index 00000000..b6090c9b --- /dev/null +++ b/test/tool/ffivariadic_test.ww @@ -0,0 +1,127 @@ +package ffivariadic_test; + +// SysV variadic-FFI AL contract, runtime-gated on both driver stages. +// Port of the retired native carrier test/wcc/989_ffivariadic_run.c; +// every assertion preserved. +// +// A ww caller of a C variadic fn (`@symbol("fixture") fn fixture(n: +// i64, ...) f64;`) must set AL to the count of XMM regs used for the +// variadic FLOAT args: the C callee gates its xmm-save-area stores on +// `test %al,%al`, so a wrong AL makes va_arg(double) read garbage. +// The pre-fix bug hardcoded AL=0 (`XORQ AX,AX`) — correct only for a +// zero-float call. Ref SysV §3.5.7, ref/qbe/amd64/sysv.c:384. +// +// Byte-id can never see AL correctness, so each row builds a ww +// caller against the host-cc-built va_arg(double) summer +// (test/wcc/data/ffivariadic/fixture.c archived as +// out/ffivariadic/libffifix.a, self-contained: zero relocs/undef +// syms, no libc, so w6l links it hermetically) and asserts the +// runtime sum via the binary's exit code, on BOTH `ww` and `ww_ww`. +// +// NON-VACUITY: fixture(2,1.0,2.0) is vacuous on this box — with AL=0 +// the two skipped xmm slots alias stale stack already holding +// 1.0/2.0. At >=3 floats the coincidence breaks deterministically, +// so every f64 row uses >=3 floats and reverting the fix FAILS here. +// +// f32 rows (#14): C default argument promotion widens each f32 arg +// to f64. f32three — exact values, unpromoted MOVSS leaves stale +// high 4B, sum misses 7.0. f32inexact — 0.1 is INEXACT in f32; the +// expected side `(x: f64)` is the SAME var widened at runtime, so +// equality holds iff the f32-ROUNDED value was promoted (not the f64 +// literal, not garbage); single f32 arg also lands the fi==1 +// boundary. f32mixed — only the f32 args promote; the native-f64 arg +// passes at width, never double-promoted. +// +// Dropped C machinery, not assertions: the ww_ww-absent skip gate +// (the Make target declares both drivers) and the unlink/rmdir +// accounting (testenv.clean asserts the removal). + +import os; +import os.exec; +import strings; +import testenv; +import time; + +fn fail(label: str, why: str) void = { + let m: str = strings.concat("ffivariadic FAIL: ", label, " -- ", + why, "\n"); + os.write(2, m.ptr, m.len: u64); + assert(false); +}; + +fn tmo() time.duration = { + return (240i64 * (time.second: i64)): time.duration; +}; + +// -1 encodes an abnormal (non-EXIT) termination, never a valid code. +fn runcode(dir: str, name: str, argv: []str) i32 = { + let co: testenv.commandout; + testenv.runcommand(dir, dir, name, argv, tmo(), &co); + if (co.termination != exec.termination.EXIT) { return -1; }; + return co.code; +}; + +fn caller(call: str, want: str) str = { + return strings.concat( + "package main;\n", + "@symbol(\"fixture\") fn fixture(n: i64, ...) f64;\n", + "export fn main() int = {\n", + "\tlet r: f64 = ", call, ";\n", + "\tif (r == ", want, ") { return 0; };\n", + "\treturn 1;\n", + "};\n"); +}; + +@test fn variadic_al() void = { + let labels: []str = ["three", "five", "eight", "f32three", + "f32inexact", "f32mixed"]; + let srcs: []str = [ + caller("fixture(3, 1.0, 2.0, 3.0)", "6.0"), + caller("fixture(5, 1.0, 2.0, 3.0, 4.0, 5.0)", "15.0"), + caller("fixture(8, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0)", + "36.0"), + caller("fixture(3, 1.5: f32, 2.5: f32, 3.0: f32)", "7.0"), + strings.concat( + "package main;\n", + "@symbol(\"fixture\") fn fixture(n: i64, ...) f64;\n", + "export fn main() int = {\n", + "\tlet x: f32 = 0.1: f32;\n", + "\tlet r: f64 = fixture(1, x);\n", + "\tif (r == (x: f64)) { return 0; };\n", + "\treturn 1;\n", + "};\n"), + caller("fixture(3, 1.5: f32, 2.0, 3.5: f32)", "7.0"), + ]; + let libdir: str = strings.concat(testenv.repo(), "/out/ffivariadic"); + let drvs: []str = ["ww", "ww_ww"]; + let td: str = testenv.fresh(); + let i: i32 = 0; + for (i < labels.len) { + let src: str = strings.concat(td, "/", labels[i], ".ww"); + testenv.writefile(src, srcs[i]); + let s: i32 = 0; + for (s < 2) { + // "out." prefix: a bare