diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 104b124bad4..d4fade76138 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -909,6 +909,7 @@ $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_saturating_int_methods")] #[inline] #[cfg(not(stage0))] pub const fn saturating_add(self, rhs: Self) -> Self { @@ -957,6 +958,7 @@ assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringi $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_saturating_int_methods")] #[inline] #[cfg(not(stage0))] pub const fn saturating_sub(self, rhs: Self) -> Self { diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 5ec18d133c6..e8dc22b8a59 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -122,55 +122,41 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> self.binop_with_overflow(bin_op, lhs, rhs, dest)?; } } - "saturating_add" => { + "saturating_add" | "saturating_sub" => { let l = self.read_immediate(args[0])?; let r = self.read_immediate(args[1])?; - let (val, overflowed) = self.binary_op_imm(BinOp::Add, l, r)?; - if overflowed { - let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; - let num_bits = l.layout.size.bits(); - let val = if l.layout.abi.is_signed() { - // For signed addition the saturated value depends on the - // sign of either term - if first_term & (1 << (num_bits-1)) == 0 { // signed term is positive - Scalar::from_uint((1u128 << (num_bits - 1)) - 1, - Size::from_bits(num_bits)) - } else { // signed term is negative - Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) - } - } else { - Scalar::from_uint(u128::max_value() >> (128 - num_bits), - Size::from_bits(num_bits)) - }; - self.write_scalar(val, dest)?; + let is_add = intrinsic_name == "saturating_add"; + let (val, overflowed) = self.binary_op_imm(if is_add { + BinOp::Add } else { - self.write_scalar(val, dest)?; - } - } - "saturating_sub" => { - let l = self.read_immediate(args[0])?; - let r = self.read_immediate(args[1])?; - let (val, overflowed) = self.binary_op_imm(BinOp::Sub, l, r)?; - if overflowed { + BinOp::Sub + }, l, r)?; + let val = if overflowed { + // For signed ints the saturated value depends on the + // sign of the first term let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; let num_bits = l.layout.size.bits(); - let val = if l.layout.abi.is_signed() { + if l.layout.abi.is_signed() { if first_term & (1 << (num_bits-1)) == 0 { // first term is positive - // so overflow is positive - Scalar::from_uint((1u128 << (num_bits - 1)) - 1, + Scalar::from_uint((1u128 << (num_bits - 1)) - 1, // max positive Size::from_bits(num_bits)) - } else { - // if first term negative, overflow must be negative + } else { // first term is negative + // max negative Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits)) } - } else { - // unsigned underflow saturates to 0 - Scalar::from_uint(0u128, Size::from_bits(num_bits)) - }; - self.write_scalar(val, dest)?; + } else { // unsigned + if is_add { + // max unsigned + Scalar::from_uint(u128::max_value() >> (128 - num_bits), + Size::from_bits(num_bits)) + } else { // underflow to 0 + Scalar::from_uint(0u128, Size::from_bits(num_bits)) + } + } } else { - self.write_scalar(val, dest)?; - } + val + }; + self.write_scalar(val, dest)?; } "unchecked_shl" | "unchecked_shr" => { let l = self.read_immediate(args[0])?; diff --git a/src/test/run-pass/const-int-saturating-arith.rs b/src/test/run-pass/const-int-saturating-arith.rs index 92372e073cf..4f586a276f0 100644 --- a/src/test/run-pass/const-int-saturating-arith.rs +++ b/src/test/run-pass/const-int-saturating-arith.rs @@ -1,3 +1,5 @@ +#![feature(const_saturating_int_methods)] + const INT_U32_NO: u32 = (42 as u32).saturating_add(2); const INT_U32: u32 = u32::max_value().saturating_add(1); const INT_U128: u128 = u128::max_value().saturating_add(1);