fold-2 chunk C4 (drew's Fam8-13 plan): 13 float value-row C drivers re-homed. 11 migrate to test/lang/*_test.ww @test row-tables (exact IEEE-bit asserts); 1 float-overflow reject row -> a runww //ww:error carrier. 956_tuprecv_f64 slims to a w6c_ww asserttyped pin (20 value rows -> @test; the stamp dimension can't be a value/byte-id @test) -- mutation-proven non-vacuous (break #121 stamp -> RED 6/6 -> restore -> GREEN) + an in-test vacuity self-check. 946_structparam/structret stay whole: their SSE register-class .s-grep (SysV ABI conformance, #165/#171a) is the genuine defect-guard, not @test-expressible. Float was the predicted SSE-cursor byte-id hotspot -- zero fresh cs!=ww surfaced; 951_f64cgen (cstage-only before) byte-ids clean. LANGBYTEID floor 82->93; test count 384->374 (10 deleted drivers; 956 + the 2 946 kept).
144 lines
3.8 KiB
Plaintext
144 lines
3.8 KiB
Plaintext
// f64cgen_test — f64/f32 deref-load + NaN relop, migrated from
|
|
// test/wcc/951_f64cgen_run.c (#5-C4, #96 + #97). Two GATE-BLIND f64 codegen
|
|
// bugs (both stages byte-identical before+after the fix, so byte-id never
|
|
// catches a reintroduction — the T1 cstage run is the live net):
|
|
// #96 — f64/f32 deref-load must MOVSD/MOVSS into X0, not MOVQ into AX.
|
|
// #97 — f64/f32 compare must consult PF (parity) for IEEE-754 NaN: with a NaN
|
|
// operand `!=` is true, the other five relops false.
|
|
// The C driver was cstage-ONLY (no byte-id leg — ww_ww run was broken #95);
|
|
// this migration ADDS the T2 cs==ww byte-id assertion for the first time.
|
|
|
|
package f64cgen_test;
|
|
|
|
fn deref(p: *f64) f64 = { return *p; };
|
|
|
|
fn zero() f64 = { return 0.0; };
|
|
|
|
fn one() f64 = { return 1.0; };
|
|
|
|
fn z() f64 = { return 0.0; };
|
|
|
|
fn z32() f32 = { return 0.0; };
|
|
|
|
fn one32() f32 = { return 1.0; };
|
|
|
|
fn tobits(f: f64) u64 = { return *((&f): *u64); };
|
|
|
|
fn frombits(b: u64) f64 = { return *((&b): *f64); };
|
|
|
|
// #96 deref-load: dirty X0 with junk before the call so X0-retention can't mask
|
|
// a broken return load; `*px` must reach X0 for the MULSD.
|
|
@test fn deref_basic() void = {
|
|
let x: f64 = 7.5;
|
|
let y: f64 = 1.25;
|
|
let px: *f64 = &x;
|
|
let junk: f64 = y * 2.0;
|
|
assert(junk == 2.5);
|
|
let r: f64 = deref(px);
|
|
assert(r == 7.5);
|
|
let q: f64 = *px * 2.0;
|
|
assert(q == 15.0);
|
|
};
|
|
|
|
// #96 value propagation through an f64-returning fn then truncated to i32.
|
|
@test fn deref_valueprop() void = {
|
|
let x: f64 = 42.0;
|
|
let r: f64 = deref(&x);
|
|
assert(r: i32 == 42);
|
|
};
|
|
|
|
@test fn arith_deref() void = {
|
|
let x: f64 = 7.5;
|
|
let p: *f64 = &x;
|
|
let q: f64 = *p * 2.0;
|
|
assert(q: i32 == 15);
|
|
};
|
|
|
|
// #96 f64frombits round-trip: reinterpret a u64 bit pattern as f64.
|
|
@test fn frombits_roundtrip() void = {
|
|
let bits: u64 = 0x4045000000000000u64;
|
|
let f: f64 = *((&bits): *f64);
|
|
assert(f: i32 == 42);
|
|
};
|
|
|
|
// #96 copysign(5.0, -1.0) == -5.0 built from tobits/frombits reinterprets.
|
|
@test fn copysign() void = {
|
|
let x: f64 = 5.0;
|
|
let y: f64 = -1.0;
|
|
let mag: u64 = tobits(x) & 0x7fffffffffffffffu64;
|
|
let sgn: u64 = tobits(y) & 0x8000000000000000u64;
|
|
let r: f64 = frombits(mag | sgn);
|
|
assert(!(r > 0.0));
|
|
assert(r < -4.5);
|
|
assert(r > -5.5);
|
|
};
|
|
|
|
// #97 full NaN relop sweep (f64, UCOMISD). Runtime NaN via 0.0/0.0 through
|
|
// opaque fns so the checker can't const-fold it.
|
|
@test fn nan_sweep() void = {
|
|
let z: f64 = zero();
|
|
let nan: f64 = z / z;
|
|
let x: f64 = one();
|
|
assert(nan != nan);
|
|
assert(!(nan == nan));
|
|
assert(!(nan == x));
|
|
assert(!(nan < x));
|
|
assert(!(nan <= x));
|
|
assert(!(nan > x));
|
|
assert(!(nan >= x));
|
|
assert(nan != x);
|
|
assert(!(x != x));
|
|
assert(x == x);
|
|
assert(x < 2.0);
|
|
assert(x <= 1.0);
|
|
assert(2.0 > x);
|
|
assert(1.0 >= x);
|
|
assert(!(x > 2.0));
|
|
};
|
|
|
|
// #97 value propagation: of the 6 relops against NaN, exactly one (`!=`) is true.
|
|
@test fn nan_count() void = {
|
|
let nan: f64 = z() / z();
|
|
let x: f64 = 1.0;
|
|
let n: i32 = 0;
|
|
if (nan == x) { n += 1; };
|
|
if (nan != x) { n += 1; };
|
|
if (nan < x) { n += 1; };
|
|
if (nan <= x) { n += 1; };
|
|
if (nan > x) { n += 1; };
|
|
if (nan >= x) { n += 1; };
|
|
assert(n == 1);
|
|
};
|
|
|
|
// #97 f32 path (UCOMISS): NaN unordered rules, plus ordered f64 relops correct.
|
|
@test fn f32_nan_ordered() void = {
|
|
let z: f32 = z32();
|
|
let nan: f32 = z / z;
|
|
let x: f32 = one32();
|
|
assert(nan != nan);
|
|
assert(!(nan == nan));
|
|
assert(!(nan < x));
|
|
assert(!(nan >= x));
|
|
let a: f64 = 2.0;
|
|
let b: f64 = 3.0;
|
|
assert(a < b);
|
|
assert(!(a > b));
|
|
assert(a <= a);
|
|
assert(b >= a);
|
|
assert(a == 2.0);
|
|
assert(!(a != 2.0));
|
|
assert(!(b < a));
|
|
assert(b > a);
|
|
};
|
|
|
|
// #97 `>`/`>=` left-bare arm with runtime-built operands (JA/JAE template
|
|
// unchanged by the fix — guards the untouched arm).
|
|
@test fn gt_only() void = {
|
|
let a: f64 = z() + 2.0;
|
|
let b: f64 = z() + 3.0;
|
|
assert(b > a);
|
|
assert(!(a > b));
|
|
assert(b >= a);
|
|
assert(a >= a);
|
|
};
|