lang: Fold signed right shifts arithmetically
261f5d9f6b595456047f8816dcd1e0a9dc002d825a6cb6648397aa4d4195984f
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
deffec0a
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 | + | } |