move saturating_add/sub into (pub) helper method
This commit is contained in:
parent
38a0b81b1c
commit
956659e5ce
1 changed files with 48 additions and 39 deletions
|
@ -219,48 +219,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
sym::saturating_add | sym::saturating_sub => {
|
sym::saturating_add | sym::saturating_sub => {
|
||||||
let l = self.read_immediate(&args[0])?;
|
let l = self.read_immediate(&args[0])?;
|
||||||
let r = self.read_immediate(&args[1])?;
|
let r = self.read_immediate(&args[1])?;
|
||||||
let is_add = intrinsic_name == sym::saturating_add;
|
let val = self.saturating_arith(
|
||||||
let (val, overflowed, _ty) = self.overflowing_binary_op(
|
if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub },
|
||||||
if is_add { BinOp::Add } else { BinOp::Sub },
|
|
||||||
&l,
|
&l,
|
||||||
&r,
|
&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)?;
|
self.write_scalar(val, dest)?;
|
||||||
}
|
}
|
||||||
sym::discriminant_value => {
|
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)
|
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<M::PointerTag>> {
|
||||||
|
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
|
/// 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
|
/// 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.
|
/// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue