// 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); };