test: migrate callret-unsigned/sar-shr/widen-pad behavior to test/lang @test
Three more value-observable behavior families ported from the C corpus to in-language @test, routed by the ratified observability rule (value -> test/lang @test; process-outcome stays in runww). Additive: the .c sources keep running in $(TESTS), so no byte-id coverage is removed -- de-dup is deferred to fold 6 (task #12). 906_callret_unsigned_arith -> callret_unsigned_test: call-result unsigned opcode select keyed by callee return type (#168, the N_CALL twin of gunsigned's module-global #134); operands flow through real calls so the return-type arm is exercised, not N_IDENT. 912_sar_shr -> sar_shr_test: signed >> / >>= must emit SAR not SHR (#136); asserts the i64/i32 value directly, dropping the C 8-bit exit-code encoding. 793_widen_pad_zero -> widen_pad_test: widening a narrow value into a wider tagged slot zeroes the high pad words (#227).
This commit is contained in:
54
test/lang/callret_unsigned_test.ww
Normal file
54
test/lang/callret_unsigned_test.ww
Normal file
@@ -0,0 +1,54 @@
|
||||
// callret_unsigned_test — an unsigned value returned from a CALL must select
|
||||
// the UNSIGNED opcode (DIVQ / SHRQ / JA) on the div / mod / shift / relational
|
||||
// path, keyed by the callee's RETURN type, migrated from
|
||||
// test/wcc/906_callret_unsigned_arith_run.c (#168, the N_CALL twin of #134 /
|
||||
// gunsigned's #25). The wwstage nodeisunsigned had no N_CALL arm, so a
|
||||
// call-result operand fell to `return false` (signed) → signed IDIVQ/SARQ/JG
|
||||
// on an unsigned-returning call → silent wrong arithmetic (cstage already read
|
||||
// the N_CALL result stamp).
|
||||
//
|
||||
// The subject IS the CALL-RESULT shape, so each operand MUST flow through a
|
||||
// real fn call: a `let a = uval();` local-bind would land on the N_IDENT arm
|
||||
// (which strconv already exercised) and HIDE the bug — gate-blind, the
|
||||
// bootstrap never divides/shifts a call result by an unsigned type. So the
|
||||
// rows are distinct call-result SHAPES (div / mod / shift / relational), not a
|
||||
// data table, mirroring gunsigned's "shapes not data" reasoning.
|
||||
//
|
||||
// Every unsigned row uses the high-bit value 0x8000000000000001 so the
|
||||
// unsigned vs signed op diverges at RUNTIME (not just in the .s) — the @test
|
||||
// asserts the unsigned semantics directly; the .s byte-id net stays in the
|
||||
// .c. The signed-returning CONTROL guards against an over-broad fix: a signed
|
||||
// callee must STILL pick IDIVQ/SARQ.
|
||||
|
||||
package callret_unsigned_test;
|
||||
|
||||
fn uval() u64 = { return 0x8000000000000001u64; };
|
||||
fn sval() i64 = { return -100i64; };
|
||||
fn sshift() i64 = { return -8i64; };
|
||||
|
||||
@test fn callret_unsigned_path() void = {
|
||||
// u64_div_callret: 0x8000..1 / 2 unsigned == 0x4000..0 (signed IDIVQ
|
||||
// sign-extends the high-bit dividend → 0xC000..1).
|
||||
assert(uval() / 2u64 == 0x4000000000000000u64);
|
||||
|
||||
// u64_mod_callret: unsigned rem == 1 (signed rem == -1).
|
||||
assert(uval() % 2u64 == 1u64);
|
||||
|
||||
// u64_shr_callret: SHRQ (logical) == 0x4000..0 (SARQ sign-fills the set
|
||||
// MSB → 0xC000..0).
|
||||
assert(uval() >> 1u64 == 0x4000000000000000u64);
|
||||
|
||||
// u64_cmp_callret: 0x8000..1 > 1 is true unsigned (JA), false signed
|
||||
// (JG reads the high bit as the sign).
|
||||
assert(uval() > 1u64);
|
||||
};
|
||||
|
||||
@test fn callret_signed_ctl() void = {
|
||||
// i64_div_callret control: -100 / 7 == -14 (toward zero); must KEEP
|
||||
// IDIVQ — an unsigned div of -100-as-u64 would be huge, not -14.
|
||||
assert(sval() / 7i64 == -14i64);
|
||||
|
||||
// i64_shr_callret control: -8 >> 1 == -4 via SARQ; SHRQ would zero-fill
|
||||
// to a large positive.
|
||||
assert(sshift() >> 1i64 == -4i64);
|
||||
};
|
||||
Reference in New Issue
Block a user