From 956659e5ced806360b726c103eb7ab1d960c163a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 19:09:22 -0500 Subject: [PATCH 1/2] move saturating_add/sub into (pub) helper method --- .../src/interpret/intrinsics.rs | 87 ++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index bf7e811c76f8e..6578db04c07eb 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -219,48 +219,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::saturating_add | sym::saturating_sub => { let l = self.read_immediate(&args[0])?; let r = self.read_immediate(&args[1])?; - let is_add = intrinsic_name == sym::saturating_add; - let (val, overflowed, _ty) = self.overflowing_binary_op( - if is_add { BinOp::Add } else { BinOp::Sub }, + let val = self.saturating_arith( + if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub }, &l, &r, )?; - let val = if overflowed { - let size = l.layout.size; - let num_bits = size.bits(); - if l.layout.abi.is_signed() { - // For signed ints the saturated value depends on the sign of the first - // term since the sign of the second term can be inferred from this and - // the fact that the operation has overflowed (if either is 0 no - // overflow can occur) - let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; - let first_term_positive = first_term & (1 << (num_bits - 1)) == 0; - if first_term_positive { - // Negative overflow not possible since the positive first term - // can only increase an (in range) negative term for addition - // or corresponding negated positive term for subtraction - Scalar::from_uint( - (1u128 << (num_bits - 1)) - 1, // max positive - Size::from_bits(num_bits), - ) - } else { - // Positive overflow not possible for similar reason - // max negative - Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) - } - } else { - // unsigned - if is_add { - // max unsigned - Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits)) - } else { - // underflow to 0 - Scalar::from_uint(0u128, Size::from_bits(num_bits)) - } - } - } else { - val - }; self.write_scalar(val, dest)?; } sym::discriminant_value => { @@ -508,6 +471,52 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.binop_ignore_overflow(BinOp::Div, &a, &b, dest) } + pub fn saturating_arith( + &self, + mir_op: BinOp, + l: &ImmTy<'tcx, M::PointerTag>, + r: &ImmTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Scalar> { + assert!(matches!(mir_op, BinOp::Add | BinOp::Sub)); + let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?; + Ok(if overflowed { + let size = l.layout.size; + let num_bits = size.bits(); + if l.layout.abi.is_signed() { + // For signed ints the saturated value depends on the sign of the first + // term since the sign of the second term can be inferred from this and + // the fact that the operation has overflowed (if either is 0 no + // overflow can occur) + let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; + let first_term_positive = first_term & (1 << (num_bits - 1)) == 0; + if first_term_positive { + // Negative overflow not possible since the positive first term + // can only increase an (in range) negative term for addition + // or corresponding negated positive term for subtraction + Scalar::from_uint( + (1u128 << (num_bits - 1)) - 1, // max positive + Size::from_bits(num_bits), + ) + } else { + // Positive overflow not possible for similar reason + // max negative + Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) + } + } else { + // unsigned + if matches!(mir_op, BinOp::Add) { + // max unsigned + Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits)) + } else { + // underflow to 0 + Scalar::from_uint(0u128, Size::from_bits(num_bits)) + } + } + } else { + val + }) + } + /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its /// allocation. For integer pointers, we consider each of them their own tiny allocation of size /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value. From ac844986d8f5646b686e2a5619e5a90372953b38 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 19:11:31 -0500 Subject: [PATCH 2/2] use singed_int_max/min helper methods --- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 6578db04c07eb..63c0248993f6c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -493,23 +493,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Negative overflow not possible since the positive first term // can only increase an (in range) negative term for addition // or corresponding negated positive term for subtraction - Scalar::from_uint( - (1u128 << (num_bits - 1)) - 1, // max positive - Size::from_bits(num_bits), - ) + Scalar::from_int(size.signed_int_max(), size) } else { // Positive overflow not possible for similar reason // max negative - Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) + Scalar::from_int(size.signed_int_min(), size) } } else { // unsigned if matches!(mir_op, BinOp::Add) { // max unsigned - Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits)) + Scalar::from_uint(size.unsigned_int_max(), size) } else { // underflow to 0 - Scalar::from_uint(0u128, Size::from_bits(num_bits)) + Scalar::from_uint(0u128, size) } } } else {