// sar_shr_test — a SIGNED right-shift (both plain `>>` and compound `>>=`) // must emit SAR (arithmetic, sign-fills the MSB), not SHR (logical, zero-fill), // migrated from test/wcc/912_sar_shr_run.c (#136). Pre-fix BOTH stages emitted // SHRQ for signed RSHIFT (A_SARQ was absent from the w6a opcode table), so // `let i: i32 = -200; i >>= 2;` produced 0x3FFFFFCE (1073741774) instead of // -50 — cs==ww held, so byte-id was GREEN while the runtime was wrong. The C // .c keeps the .s byte-id net; this file pins the RUNTIME semantics directly, // dropping the C original's 8-bit exit-code encoding (assert the i64/i32 value // in-language — the whole point of the @test model). // // Unlike gunsigned/idxarg, the bug lives in the shift codegen itself, not in // how the operand is sourced, so indexing a row's operand and then shifting // STILL exercises the shift site — a row-loop is appropriate. The VALUE (neg // vs pos) is the data dimension and loops; the (type, operator) SHAPE selects // distinct shift sites (i32 vs i64; cgbin `>>` vs compound `>>=`), so it is one // @test fn per shape over a shared row table. Negatives discriminate SAR from // SHR; the positive row is a no-regression control (SAR == SHR on positives). package sar_shr_test; // One shift row: x >> sh (or x >>= sh) must equal want. Each consuming @test // fixes the operand TYPE and OPERATOR; the rows vary only sign/magnitude. type shrow = struct { x: i64, sh: i64, want: i64, }; let rows: [3]shrow = [ shrow { x = -200i64, sh = 2i64, want = -50i64 }, shrow { x = -8i64, sh = 1i64, want = -4i64 }, shrow { x = 200i64, sh = 2i64, want = 50i64 }, ]; @test fn shift_i64_binop() void = { let i: i32 = 0; for (i < len(rows)) { assert(rows[i].x >> rows[i].sh == rows[i].want); i += 1; }; }; @test fn shift_i64_compound() void = { let i: i32 = 0; for (i < len(rows)) { let v: i64 = rows[i].x; v >>= rows[i].sh; assert(v == rows[i].want); i += 1; }; }; @test fn shift_i32_binop() void = { let i: i32 = 0; for (i < len(rows)) { let x: i32 = rows[i].x: i32; let r: i32 = x >> (rows[i].sh: i32); assert(r == rows[i].want: i32); i += 1; }; }; @test fn shift_i32_compound() void = { let i: i32 = 0; for (i < len(rows)) { let v: i32 = rows[i].x: i32; v >>= rows[i].sh: i32; assert(v == rows[i].want: i32); i += 1; }; }; @test fn shift_unsigned_ctl() void = { // u32 control: 200u32 >> 2 == 50 — SHRQ unchanged by the fix. let a: u32 = 200u32; a >>= 2u32; assert(a == 50u32); // u64 high-bit control: the fix must NOT make unsigned use SAR. A // logical SHRQ of 0x8000..0 >> 1 == 0x4000..0; an over-broad SARQ would // sign-fill the set MSB → 0xC000..0. let b: u64 = 0x8000000000000000u64; assert(b >> 1u64 == 0x4000000000000000u64); };