@@ -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