diff --git a/bootstrap/src/compiler.rs b/bootstrap/src/compiler.rs index 3491c6aee0..f87a89367b 100644 --- a/bootstrap/src/compiler.rs +++ b/bootstrap/src/compiler.rs @@ -16668,6 +16668,25 @@ impl VerilogCodegen { // in $signed() (Verilog sign-extends it into the wider signed // context) and the unsigned operand is zero-extended one bit, // $signed({1'b0, x}), so it stays non-negative. + // W-27: a RIGHT SHIFT of a signed value needs `>>>`. + // Verilog's `>>` fills with zeros whatever the operand + // is declared, and the repair below fires only on + // ordered relations, so no shift was ever fixed up. On + // `specs/igla/race/cordic_fixed.t27:42`, `x - (y >> shift)` + // with x=100, y=-64, shift=2 simulates to -16268 where + // the spec, C and Zig all say 116: y = 16'hFFC0 = 65472, + // 65472 >> 2 = 16368, 100 - 16368 = -16268. + // + // This project's own hand-written golden CORDIC RTL + // writes `y0 >>> 1` for the identical rotation, so the + // right operator was known and the expression path + // emitted it zero times across 559 generated modules. + let shift_signed = node.extra_op == ">>" + && matches!( + self.expr_width_signed(&node.children[0]), + Some((_, true)) + ); + let op = if shift_signed { ">>>" } else { op }; let ordered_rel = matches!(op, "<" | "<=" | ">" | ">="); let rel_signed = ordered_rel && match ( diff --git a/bootstrap/stage0/FROZEN_HASH b/bootstrap/stage0/FROZEN_HASH index f9f9072e9f..3f6eb71f65 100644 --- a/bootstrap/stage0/FROZEN_HASH +++ b/bootstrap/stage0/FROZEN_HASH @@ -1 +1 @@ -d08617f241b7aebdbef21636a651180b9b303ea20c1077452be83165e3a5b736 +b109d745f01460f08fb2f8547d27a816dfecaff6c3f917da90f2f465c3daa86d diff --git a/docs/now/2026-08-30-a-signed-right-shift-needs-three-angles.md b/docs/now/2026-08-30-a-signed-right-shift-needs-three-angles.md new file mode 100644 index 0000000000..016413b125 --- /dev/null +++ b/docs/now/2026-08-30-a-signed-right-shift-needs-three-angles.md @@ -0,0 +1,12 @@ +# NOW -- A signed right shift needs three angle brackets (2026-08-30) + +## The Verilog backend filled with zeros where the spec said sign (Refs #2860) + +- `>>` was mapped to Verilog's `>>` unconditionally; Verilog's `>>` is LOGICAL and fills with zeros however the operand is declared +- the signedness repair the backend already has fires only on ordered relations `< <= > >=`, so no shift was ever fixed up +- simulated on the ACTUAL generated module: `cordic_x_next(100, -64, shift=2)` returned **-16268**; the spec, C and Zig all say **116** +- y = -64 is 16'hFFC0 = 65472; 65472 >> 2 = 16368; 100 - 16368 = -16268 +- this project's own hand-written golden CORDIC RTL writes `y0 >>> 1` for the identical rotation, so the right operator was known and the expression path emitted it ZERO times across 559 modules +- `>>>` occurrences corpus-wide: 2 -> 369 across 48 specs; both of the old two were inside string literals +- iverilog acceptance unchanged 373/559 -- the wrong shift was always legal Verilog, which is why no gate could have caught it +- tempered, and the audit said so first: 42 of the 45 affected specs shift non-negative values today, so they are LATENT. The three igla/race CORDIC specs are value-corrupting now