@@ -219,48 +219,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
219
219
sym:: saturating_add | sym:: saturating_sub => {
220
220
let l = self . read_immediate ( & args[ 0 ] ) ?;
221
221
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 } ,
225
224
& l,
226
225
& r,
227
226
) ?;
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
- } ;
264
227
self . write_scalar ( val, dest) ?;
265
228
}
266
229
sym:: discriminant_value => {
@@ -508,6 +471,49 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
508
471
self . binop_ignore_overflow ( BinOp :: Div , & a, & b, dest)
509
472
}
510
473
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
+
511
517
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
512
518
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
513
519
/// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
0 commit comments