Files
ww/test/lang/tupparam_test.ww
Hojun-Cho 07b3c74ab0 test: migrate Fam8 tuple value tests to @test + reject carriers (#5-C2)
fold-2 chunk C2 (drew's Fam8-13 plan): 14 tuple value-row C drivers migrate to
15 test/lang/*_test.ww @test row-tables (the +1 is 954_tuprecv, slimmed not
deleted -- its value rows split out while the asserttyped-stamp dimension stays
as a carrier-split C pin, mutation-proven non-vacuous). Reject rows move to 32
test/wcc/data/*/case.ww //ww:error carriers (runww asserts the substring in
BOTH stages). The test-lang byte-id (LANGBYTEID) gate gives cs==ww automatically
and is strictly more sensitive than re-running the wwstage leg; floor 59->74.
Tuple surfaced zero cs!=ww as the plan predicted -- no value-only carve. The 945
trio folds in here; 940_global_sret / 940_str_forrange / 926_tagscr untouched
(routed to drew per-file). Test count 402->388 = the 14 retired drivers.
2026-06-24 01:44:13 +09:00

85 lines
3.5 KiB
Plaintext

// tupparam_test — runtime contract for #163, the tuple-PARAM ABI (the param
// twin of #164's tuple RETURN). Migrated from test/wcc/905_tupparam_run.c.
// A tuple passed AS AN ARGUMENT was unhandled in both stages: a tuple-typed
// call result left its elements in the return-ABI cursor and the SEND fell to
// the 1-GP-word else, so all but the first element was dropped. The fix
// restages the tuple into a frame slot by SysV class then pushes the slot
// words; both stages byte-identical (rule 10). GATE-BLIND TO BYTE-ID ALONE:
// pre-fix both stages were symmetric-WRONG, so cs==ww held — the rows diverge
// only at RUNTIME; these @test fns pin that runtime contract (T1), the byte-id
// gate (T2) keeps cs==ww. The loud-stop arg-reg-overflow row is a reject
// carrier (test/wcc/data/tupparam_gp_overflow_loudstop/).
package tupparam_test;
fn pair_f64f64_arg(a: f64, b: f64) (f64, f64) = { return (a, b); };
fn add_f64f64_arg(t: (f64, f64)) f64 = { return t.0 + t.1; };
fn pair_i64i64_arg(a: i64, b: i64) (i64, i64) = { return (a, b); };
fn add_i64i64_arg(t: (i64, i64)) i64 = { return t.0 + t.1; };
fn mk_f64i64_arg(a: f64, b: i64) (f64, i64) = { return (a, b); };
fn add_f64i64_arg(t: (f64, i64)) i64 = { return (t.0: i64) + t.1; };
fn mk_i64f64_arg(a: i64, b: f64) (i64, f64) = { return (a, b); };
fn add_i64f64_arg(t: (i64, f64)) i64 = { return t.0 + (t.1: i64); };
fn mk_f64str_arg(a: f64) (f64, str) = { return (a, "hello"); };
fn add_f64str_arg(t: (f64, str)) i64 = {
return (t.0: i64) + (t.1.len: i64);
};
fn pair_two_tuple_args(a: i64, b: i64) (i64, i64) = { return (a, b); };
fn add4_two_tuple_args(s: (i64, i64), t: (i64, i64)) i64 = {
return s.0 + s.1 + t.0 + t.1;
};
fn pair_f64f64_chain(a: f64, b: f64) (f64, f64) = { return (a, b); };
fn id_f64f64_chain(t: (f64, f64)) f64 = { return t.0 * 10.0 + t.1; };
// HEADLINE — (f64, f64) arg. Pre-fix the SEND pushes only AX (the two floats
// stay stranded in X0/X1) and the callee reads one GP word. Post-fix each
// float rides the SSE arg cursor (X0, X1).
@test fn f64f64_arg() void = {
assert(!(add_f64f64_arg(pair_f64f64_arg(3.0, 5.0)) != 8.0));
};
// (i64, i64) arg — proves the broader INTEGER-tuple-param drop is fixed
// (master dropped the second i64 too). e0->DI, e1->SI.
@test fn i64i64_arg() void = {
assert(!(add_i64i64_arg(pair_i64i64_arg(3, 5)) != 8));
};
// (f64, i64) — class independent of position: f64@X0 (SSE cursor), i64@DI
// (INTEGER cursor), independent counters.
@test fn f64i64_arg() void = {
assert(!(add_f64i64_arg(mk_f64i64_arg(3.0, 5)) != 8));
};
// (i64, f64) — order-swap: i64@DI, f64@X0. Confirms the float lands in the
// next XMM regardless of its positional slot.
@test fn i64f64_arg() void = {
assert(!(add_i64f64_arg(mk_i64f64_arg(3, 5.0)) != 8));
};
// (f64, str) — SSE + wide (24B {ptr,len,cap}) coexist. The f64 rides X0 (SSE,
// consuming no GP slot); the str rides DI/SI/DX (INTEGER cursor). f=4.0,
// s.len=5 -> 4+5 = 9.
@test fn f64str_arg() void = {
assert(!(add_f64str_arg(mk_f64str_arg(4.0)) != 9));
};
// MULTI-TUPLE-ARG, ONE CALL — f(g(), h()) where both args are tuple-producing
// calls. Proves @tupargscr (single-slot-per-fn) is REUSED per arg, not
// COLLIDED. 1+2+3+4 = 10.
@test fn two_tuple_args() void = {
assert(!(add4_two_tuple_args(pair_two_tuple_args(1, 2),
pair_two_tuple_args(3, 4)) != 10));
};
// CONTROL — a tuple arg threaded through a chain of two calls, proving the
// SEND/RECV round-trips through the slot intact.
@test fn f64f64_chain() void = {
assert(!(id_f64f64_chain(pair_f64f64_chain(3.0, 5.0)) != 35.0));
};