@@ -219,48 +219,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
219219 sym:: saturating_add | sym:: saturating_sub => {
220220 let l = self . read_immediate ( & args[ 0 ] ) ?;
221221 let r = self . read_immediate ( & args[ 1 ] ) ?;
222- let is_add = intrinsic_name == sym:: saturating_add;
223- let ( val, overflowed, _ty) = self . overflowing_binary_op (
224- if is_add { BinOp :: Add } else { BinOp :: Sub } ,
222+ let val = self . saturating_arith (
223+ if intrinsic_name == sym:: saturating_add { BinOp :: Add } else { BinOp :: Sub } ,
225224 & l,
226225 & r,
227226 ) ?;
228- let val = if overflowed {
229- let size = l. layout . size ;
230- let num_bits = size. bits ( ) ;
231- if l. layout . abi . is_signed ( ) {
232- // For signed ints the saturated value depends on the sign of the first
233- // term since the sign of the second term can be inferred from this and
234- // the fact that the operation has overflowed (if either is 0 no
235- // overflow can occur)
236- let first_term: u128 = l. to_scalar ( ) ?. to_bits ( l. layout . size ) ?;
237- let first_term_positive = first_term & ( 1 << ( num_bits - 1 ) ) == 0 ;
238- if first_term_positive {
239- // Negative overflow not possible since the positive first term
240- // can only increase an (in range) negative term for addition
241- // or corresponding negated positive term for subtraction
242- Scalar :: from_uint (
243- ( 1u128 << ( num_bits - 1 ) ) - 1 , // max positive
244- Size :: from_bits ( num_bits) ,
245- )
246- } else {
247- // Positive overflow not possible for similar reason
248- // max negative
249- Scalar :: from_uint ( 1u128 << ( num_bits - 1 ) , Size :: from_bits ( num_bits) )
250- }
251- } else {
252- // unsigned
253- if is_add {
254- // max unsigned
255- Scalar :: from_uint ( size. unsigned_int_max ( ) , Size :: from_bits ( num_bits) )
256- } else {
257- // underflow to 0
258- Scalar :: from_uint ( 0u128 , Size :: from_bits ( num_bits) )
259- }
260- }
261- } else {
262- val
263- } ;
264227 self . write_scalar ( val, dest) ?;
265228 }
266229 sym:: discriminant_value => {
@@ -508,6 +471,49 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
508471 self . binop_ignore_overflow ( BinOp :: Div , & a, & b, dest)
509472 }
510473
474+ pub fn saturating_arith (
475+ & self ,
476+ mir_op : BinOp ,
477+ l : & ImmTy < ' tcx , M :: PointerTag > ,
478+ r : & ImmTy < ' tcx , M :: PointerTag > ,
479+ ) -> InterpResult < ' tcx , Scalar < M :: PointerTag > > {
480+ assert ! ( matches!( mir_op, BinOp :: Add | BinOp :: Sub ) ) ;
481+ let ( val, overflowed, _ty) = self . overflowing_binary_op ( mir_op, l, r) ?;
482+ Ok ( if overflowed {
483+ let size = l. layout . size ;
484+ let num_bits = size. bits ( ) ;
485+ if l. layout . abi . is_signed ( ) {
486+ // For signed ints the saturated value depends on the sign of the first
487+ // term since the sign of the second term can be inferred from this and
488+ // the fact that the operation has overflowed (if either is 0 no
489+ // overflow can occur)
490+ let first_term: u128 = l. to_scalar ( ) ?. to_bits ( l. layout . size ) ?;
491+ let first_term_positive = first_term & ( 1 << ( num_bits - 1 ) ) == 0 ;
492+ if first_term_positive {
493+ // Negative overflow not possible since the positive first term
494+ // can only increase an (in range) negative term for addition
495+ // or corresponding negated positive term for subtraction
496+ Scalar :: from_int ( size. signed_int_max ( ) , size)
497+ } else {
498+ // Positive overflow not possible for similar reason
499+ // max negative
500+ Scalar :: from_int ( size. signed_int_min ( ) , size)
501+ }
502+ } else {
503+ // unsigned
504+ if matches ! ( mir_op, BinOp :: Add ) {
505+ // max unsigned
506+ Scalar :: from_uint ( size. unsigned_int_max ( ) , size)
507+ } else {
508+ // underflow to 0
509+ Scalar :: from_uint ( 0u128 , size)
510+ }
511+ }
512+ } else {
513+ val
514+ } )
515+ }
516+
511517 /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
512518 /// allocation. For integer pointers, we consider each of them their own tiny allocation of size
513519 /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
0 commit comments