lang: Fold signed right shifts arithmetically
470dd84a2660655e20dd2f513af46afc8b3a5a6ec80d844fdad76f9710f51d42
The constant folder shifted a negative value’s absolute magnitude and restored its sign, which rounds odd negative values toward zero instead of matching an arithmetic right shift. Shift signed constants through their signed representation and reconstruct the width-limited result from its bit pattern. Assisted-by: Codex:gpt-5.6-sol
1 parent
1361514f
lib/std/lang/resolver.rad
+10 -3
| 6345 | 6345 | let raw = (0 - left.magnitude) if left.negative else left.magnitude; |
|
| 6346 | 6346 | let shamt = right.magnitude % left.bits as u64; |
|
| 6347 | 6347 | return ConstValue::Int(constIntFromBits(raw << shamt, left.bits, left.signed)); |
|
| 6348 | 6348 | }, |
|
| 6349 | 6349 | case ast::BinaryOp::Shr => { |
|
| 6350 | - | return ConstValue::Int(ConstInt { |
|
| 6351 | - | magnitude: left.magnitude >> right.magnitude, bits, signed, negative: left.negative, |
|
| 6352 | - | }); |
|
| 6350 | + | let shamt = right.magnitude % left.bits as u64; |
|
| 6351 | + | if left.signed { |
|
| 6352 | + | let shifted = constIntToSigned(left) >> shamt as i64; |
|
| 6353 | + | return ConstValue::Int( |
|
| 6354 | + | constIntFromBits(shifted as u64, left.bits, true) |
|
| 6355 | + | ); |
|
| 6356 | + | } |
|
| 6357 | + | return ConstValue::Int( |
|
| 6358 | + | constIntFromBits(left.magnitude >> shamt, left.bits, false) |
|
| 6359 | + | ); |
|
| 6353 | 6360 | }, |
|
| 6354 | 6361 | case ast::BinaryOp::Eq => return ConstValue::Bool(l == r), |
|
| 6355 | 6362 | case ast::BinaryOp::Ne => return ConstValue::Bool(l <> r), |
|
| 6356 | 6363 | case ast::BinaryOp::Lt => |
|
| 6357 | 6364 | return ConstValue::Bool(l < r if signed else left.magnitude < right.magnitude), |
test/tests/const.i32.shift.right.rad
added
+12 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | //! Folded signed right shifts must round toward negative infinity. |
|
| 3 | + | ||
| 4 | + | constant NEGATIVE: i32 = -7; |
|
| 5 | + | constant SHIFTED: i32 = NEGATIVE >> 1; |
|
| 6 | + | ||
| 7 | + | @default fn main() -> i32 { |
|
| 8 | + | if SHIFTED == -4 { |
|
| 9 | + | return 0; |
|
| 10 | + | } |
|
| 11 | + | return 1; |
|
| 12 | + | } |