@@ -112,25 +112,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
112112
113113 // Shift ops can have an RHS with a different numeric type.
114114 if matches ! ( bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked ) {
115- let size = left. layout . size . bits ( ) ;
115+ let l_bits = left. layout . size . bits ( ) ;
116116 // Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is
117117 // the one MIR operator that does *not* directly map to a single LLVM operation.)
118118 let ( shift_amount, overflow) = if right. layout . abi . is_signed ( ) {
119119 let shift_amount = r_signed ( ) ;
120- let overflow = shift_amount < 0 || shift_amount >= i128:: from ( size) ;
121- // Deliberately wrapping `as` casts: shift_amount *can* be negative, but the result
122- // of the `as` will be equal modulo `size` (since it is a power of two).
123- let masked_amount = ( shift_amount as u128 ) % u128:: from ( size) ;
124- assert_eq ! ( overflow, shift_amount != i128 :: try_from( masked_amount) . unwrap( ) ) ;
125- ( masked_amount, overflow)
120+ let rem = shift_amount. rem_euclid ( l_bits. into ( ) ) ;
121+ // `rem` is guaranteed positive, so the `unwrap` cannot fail
122+ ( u128:: try_from ( rem) . unwrap ( ) , rem != shift_amount)
126123 } else {
127124 let shift_amount = r_unsigned ( ) ;
128- let overflow = shift_amount >= u128:: from ( size) ;
129- let masked_amount = shift_amount % u128:: from ( size) ;
130- assert_eq ! ( overflow, shift_amount != masked_amount) ;
131- ( masked_amount, overflow)
125+ let rem = shift_amount. rem_euclid ( l_bits. into ( ) ) ;
126+ ( rem, rem != shift_amount)
132127 } ;
133- let shift_amount = u32:: try_from ( shift_amount) . unwrap ( ) ; // we masked so this will always fit
128+ let shift_amount = u32:: try_from ( shift_amount) . unwrap ( ) ; // we brought this in the range `0..size` so this will always fit
134129 // Compute the shifted result.
135130 let result = if left. layout . abi . is_signed ( ) {
136131 let l = l_signed ( ) ;
0 commit comments