From 076b91f8ad9ce5bbebc5690b6ef9a1ff162f5efb Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 7 Aug 2013 15:40:09 -0400 Subject: add intrinsics for checked overflow add/sub/mul --- src/libstd/num/num.rs | 449 +++++++++++++++++++++++++++++++++++++- src/libstd/prelude.rs | 2 +- src/libstd/unstable/intrinsics.rs | 54 +++++ 3 files changed, 503 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index bbadf1caca2..f0c432ce2eb 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -18,7 +18,9 @@ use cmp::{Eq, ApproxEq, Ord}; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; -use option::Option; +use option::{Option, Some, None}; +#[cfg(not(stage0))] +use unstable::intrinsics; pub mod strconv; @@ -516,6 +518,414 @@ impl Saturating for u16 {} impl Saturating for u32 {} impl Saturating for u64 {} +pub trait CheckedAdd: Add { + fn checked_add(&self, v: &Self) -> Option; +} + +#[cfg(not(stage0))] +impl CheckedAdd for i8 { + #[inline] + fn checked_add(&self, v: &i8) -> Option { + unsafe { + let (x, y) = intrinsics::i8_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedAdd for i16 { + #[inline] + fn checked_add(&self, v: &i16) -> Option { + unsafe { + let (x, y) = intrinsics::i16_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedAdd for i32 { + #[inline] + fn checked_add(&self, v: &i32) -> Option { + unsafe { + let (x, y) = intrinsics::i32_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedAdd for i64 { + #[inline] + fn checked_add(&self, v: &i64) -> Option { + unsafe { + let (x, y) = intrinsics::i64_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0), target_word_size = "32")] +impl CheckedAdd for int { + #[inline] + fn checked_add(&self, v: &int) -> Option { + unsafe { + let (x, y) = intrinsics::i32_add_with_overflow(*self as i32, *v as i32); + if y { None } else { Some(x as int) } + } + } +} + +#[cfg(not(stage0), target_word_size = "64")] +impl CheckedAdd for int { + #[inline] + fn checked_add(&self, v: &int) -> Option { + unsafe { + let (x, y) = intrinsics::i64_add_with_overflow(*self as i64, *v as i64); + if y { None } else { Some(x as int) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedAdd for u8 { + #[inline] + fn checked_add(&self, v: &u8) -> Option { + unsafe { + let (x, y) = intrinsics::u8_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedAdd for u16 { + #[inline] + fn checked_add(&self, v: &u16) -> Option { + unsafe { + let (x, y) = intrinsics::u16_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedAdd for u32 { + #[inline] + fn checked_add(&self, v: &u32) -> Option { + unsafe { + let (x, y) = intrinsics::u32_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedAdd for u64 { + #[inline] + fn checked_add(&self, v: &u64) -> Option { + unsafe { + let (x, y) = intrinsics::u64_add_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0), target_word_size = "32")] +impl CheckedAdd for uint { + #[inline] + fn checked_add(&self, v: &uint) -> Option { + unsafe { + let (x, y) = intrinsics::u32_add_with_overflow(*self as u32, *v as u32); + if y { None } else { Some(x as uint) } + } + } +} + +#[cfg(not(stage0), target_word_size = "64")] +impl CheckedAdd for uint { + #[inline] + fn checked_add(&self, v: &uint) -> Option { + unsafe { + let (x, y) = intrinsics::u64_add_with_overflow(*self as u64, *v as u64); + if y { None } else { Some(x as uint) } + } + } +} + +pub trait CheckedSub: Sub { + fn checked_sub(&self, v: &Self) -> Option; +} + +#[cfg(not(stage0))] +impl CheckedSub for i8 { + #[inline] + fn checked_sub(&self, v: &i8) -> Option { + unsafe { + let (x, y) = intrinsics::i8_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedSub for i16 { + #[inline] + fn checked_sub(&self, v: &i16) -> Option { + unsafe { + let (x, y) = intrinsics::i16_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedSub for i32 { + #[inline] + fn checked_sub(&self, v: &i32) -> Option { + unsafe { + let (x, y) = intrinsics::i32_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedSub for i64 { + #[inline] + fn checked_sub(&self, v: &i64) -> Option { + unsafe { + let (x, y) = intrinsics::i64_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0), target_word_size = "32")] +impl CheckedSub for int { + #[inline] + fn checked_sub(&self, v: &int) -> Option { + unsafe { + let (x, y) = intrinsics::i32_sub_with_overflow(*self as i32, *v as i32); + if y { None } else { Some(x as int) } + } + } +} + +#[cfg(not(stage0), target_word_size = "64")] +impl CheckedSub for int { + #[inline] + fn checked_sub(&self, v: &int) -> Option { + unsafe { + let (x, y) = intrinsics::i64_sub_with_overflow(*self as i64, *v as i64); + if y { None } else { Some(x as int) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedSub for u8 { + #[inline] + fn checked_sub(&self, v: &u8) -> Option { + unsafe { + let (x, y) = intrinsics::u8_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedSub for u16 { + #[inline] + fn checked_sub(&self, v: &u16) -> Option { + unsafe { + let (x, y) = intrinsics::u16_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedSub for u32 { + #[inline] + fn checked_sub(&self, v: &u32) -> Option { + unsafe { + let (x, y) = intrinsics::u32_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedSub for u64 { + #[inline] + fn checked_sub(&self, v: &u64) -> Option { + unsafe { + let (x, y) = intrinsics::u64_sub_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0), target_word_size = "32")] +impl CheckedSub for uint { + #[inline] + fn checked_sub(&self, v: &uint) -> Option { + unsafe { + let (x, y) = intrinsics::u32_sub_with_overflow(*self as u32, *v as u32); + if y { None } else { Some(x as uint) } + } + } +} + +#[cfg(not(stage0), target_word_size = "64")] +impl CheckedSub for uint { + #[inline] + fn checked_sub(&self, v: &uint) -> Option { + unsafe { + let (x, y) = intrinsics::u64_sub_with_overflow(*self as u64, *v as u64); + if y { None } else { Some(x as uint) } + } + } +} + +pub trait CheckedMul: Mul { + fn checked_mul(&self, v: &Self) -> Option; +} + +#[cfg(not(stage0))] +impl CheckedMul for i8 { + #[inline] + fn checked_mul(&self, v: &i8) -> Option { + unsafe { + let (x, y) = intrinsics::i8_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedMul for i16 { + #[inline] + fn checked_mul(&self, v: &i16) -> Option { + unsafe { + let (x, y) = intrinsics::i16_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedMul for i32 { + #[inline] + fn checked_mul(&self, v: &i32) -> Option { + unsafe { + let (x, y) = intrinsics::i32_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedMul for i64 { + #[inline] + fn checked_mul(&self, v: &i64) -> Option { + unsafe { + let (x, y) = intrinsics::i64_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0), target_word_size = "32")] +impl CheckedMul for int { + #[inline] + fn checked_mul(&self, v: &int) -> Option { + unsafe { + let (x, y) = intrinsics::i32_mul_with_overflow(*self as i32, *v as i32); + if y { None } else { Some(x as int) } + } + } +} + +#[cfg(not(stage0), target_word_size = "64")] +impl CheckedMul for int { + #[inline] + fn checked_mul(&self, v: &int) -> Option { + unsafe { + let (x, y) = intrinsics::i64_mul_with_overflow(*self as i64, *v as i64); + if y { None } else { Some(x as int) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedMul for u8 { + #[inline] + fn checked_mul(&self, v: &u8) -> Option { + unsafe { + let (x, y) = intrinsics::u8_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedMul for u16 { + #[inline] + fn checked_mul(&self, v: &u16) -> Option { + unsafe { + let (x, y) = intrinsics::u16_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedMul for u32 { + #[inline] + fn checked_mul(&self, v: &u32) -> Option { + unsafe { + let (x, y) = intrinsics::u32_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0))] +impl CheckedMul for u64 { + #[inline] + fn checked_mul(&self, v: &u64) -> Option { + unsafe { + let (x, y) = intrinsics::u64_mul_with_overflow(*self, *v); + if y { None } else { Some(x) } + } + } +} + +#[cfg(not(stage0), target_word_size = "32")] +impl CheckedMul for uint { + #[inline] + fn checked_mul(&self, v: &uint) -> Option { + unsafe { + let (x, y) = intrinsics::u32_mul_with_overflow(*self as u32, *v as u32); + if y { None } else { Some(x as uint) } + } + } +} + +#[cfg(not(stage0), target_word_size = "64")] +impl CheckedMul for uint { + #[inline] + fn checked_mul(&self, v: &uint) -> Option { + unsafe { + let (x, y) = intrinsics::u64_mul_with_overflow(*self as u64, *v as u64); + if y { None } else { Some(x as uint) } + } + } +} + /// Helper function for testing numeric operations #[cfg(test)] pub fn test_num(ten: T, two: T) { @@ -534,6 +944,8 @@ pub fn test_num(ten: T, two: T) { #[cfg(test)] mod tests { + use prelude::*; + use uint; use super::*; macro_rules! test_cast_20( @@ -639,4 +1051,39 @@ mod tests { assert_eq!(max_value.saturating_sub(-max_value), max_value); assert_eq!((max_value-2).saturating_sub(-1), max_value-1); } + + #[test] + fn test_checked_add() { + let five_less = uint::max_value - 5; + assert_eq!(five_less.checked_add(&0), Some(uint::max_value - 5)); + assert_eq!(five_less.checked_add(&1), Some(uint::max_value - 4)); + assert_eq!(five_less.checked_add(&2), Some(uint::max_value - 3)); + assert_eq!(five_less.checked_add(&3), Some(uint::max_value - 2)); + assert_eq!(five_less.checked_add(&4), Some(uint::max_value - 1)); + assert_eq!(five_less.checked_add(&5), Some(uint::max_value)); + assert_eq!(five_less.checked_add(&6), None); + assert_eq!(five_less.checked_add(&7), None); + } + + #[test] + fn test_checked_sub() { + assert_eq!(5u.checked_sub(&0), Some(5)); + assert_eq!(5u.checked_sub(&1), Some(4)); + assert_eq!(5u.checked_sub(&2), Some(3)); + assert_eq!(5u.checked_sub(&3), Some(2)); + assert_eq!(5u.checked_sub(&4), Some(1)); + assert_eq!(5u.checked_sub(&5), Some(0)); + assert_eq!(5u.checked_sub(&6), None); + assert_eq!(5u.checked_sub(&7), None); + } + + #[test] + fn test_checked_mul() { + let third = uint::max_value / 3; + assert_eq!(third.checked_mul(&0), Some(0)); + assert_eq!(third.checked_mul(&1), Some(third)); + assert_eq!(third.checked_mul(&2), Some(third * 2)); + assert_eq!(third.checked_mul(&3), Some(third * 3)); + assert_eq!(third.checked_mul(&4), None); + } } diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 9a8737f4dee..93e14be582b 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -53,7 +53,7 @@ pub use iter::Times; pub use iterator::Extendable; pub use iterator::{Iterator, DoubleEndedIterator}; pub use iterator::{ClonableIterator, OrdIterator}; -pub use num::{Num, NumCast}; +pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; pub use num::{Orderable, Signed, Unsigned, Round}; pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; pub use num::{Integer, Fractional, Real, RealExt}; diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index c60edad3dbd..9f69ee47e9b 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -428,6 +428,60 @@ extern "rust-intrinsic" { pub fn bswap16(x: i16) -> i16; pub fn bswap32(x: i32) -> i32; pub fn bswap64(x: i64) -> i64; + + #[cfg(not(stage0))] + pub fn i8_add_with_overflow(x: i8, y: i8) -> (i8, bool); + #[cfg(not(stage0))] + pub fn i16_add_with_overflow(x: i16, y: i16) -> (i16, bool); + #[cfg(not(stage0))] + pub fn i32_add_with_overflow(x: i32, y: i32) -> (i32, bool); + #[cfg(not(stage0))] + pub fn i64_add_with_overflow(x: i64, y: i64) -> (i64, bool); + + #[cfg(not(stage0))] + pub fn u8_add_with_overflow(x: u8, y: u8) -> (u8, bool); + #[cfg(not(stage0))] + pub fn u16_add_with_overflow(x: u16, y: u16) -> (u16, bool); + #[cfg(not(stage0))] + pub fn u32_add_with_overflow(x: u32, y: u32) -> (u32, bool); + #[cfg(not(stage0))] + pub fn u64_add_with_overflow(x: u64, y: u64) -> (u64, bool); + + #[cfg(not(stage0))] + pub fn i8_sub_with_overflow(x: i8, y: i8) -> (i8, bool); + #[cfg(not(stage0))] + pub fn i16_sub_with_overflow(x: i16, y: i16) -> (i16, bool); + #[cfg(not(stage0))] + pub fn i32_sub_with_overflow(x: i32, y: i32) -> (i32, bool); + #[cfg(not(stage0))] + pub fn i64_sub_with_overflow(x: i64, y: i64) -> (i64, bool); + + #[cfg(not(stage0))] + pub fn u8_sub_with_overflow(x: u8, y: u8) -> (u8, bool); + #[cfg(not(stage0))] + pub fn u16_sub_with_overflow(x: u16, y: u16) -> (u16, bool); + #[cfg(not(stage0))] + pub fn u32_sub_with_overflow(x: u32, y: u32) -> (u32, bool); + #[cfg(not(stage0))] + pub fn u64_sub_with_overflow(x: u64, y: u64) -> (u64, bool); + + #[cfg(not(stage0))] + pub fn i8_mul_with_overflow(x: i8, y: i8) -> (i8, bool); + #[cfg(not(stage0))] + pub fn i16_mul_with_overflow(x: i16, y: i16) -> (i16, bool); + #[cfg(not(stage0))] + pub fn i32_mul_with_overflow(x: i32, y: i32) -> (i32, bool); + #[cfg(not(stage0))] + pub fn i64_mul_with_overflow(x: i64, y: i64) -> (i64, bool); + + #[cfg(not(stage0))] + pub fn u8_mul_with_overflow(x: u8, y: u8) -> (u8, bool); + #[cfg(not(stage0))] + pub fn u16_mul_with_overflow(x: u16, y: u16) -> (u16, bool); + #[cfg(not(stage0))] + pub fn u32_mul_with_overflow(x: u32, y: u32) -> (u32, bool); + #[cfg(not(stage0))] + pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool); } #[cfg(target_endian = "little")] pub fn to_le16(x: i16) -> i16 { x } -- cgit 1.4.1-3-g733a5 From 7db605cd158e39eecb96dad692ba56ea75aba735 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 11 Aug 2013 02:58:52 -0400 Subject: disable 64-bit CheckedMul on 32-bit code generation problem reported as issue #8449 --- src/libstd/num/num.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index f0c432ce2eb..62452a4edff 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -827,7 +827,8 @@ impl CheckedMul for i32 { } } -#[cfg(not(stage0))] +// FIXME: #8449: should not be disabled on 32-bit +#[cfg(not(stage0), target_word_size = "64")] impl CheckedMul for i64 { #[inline] fn checked_mul(&self, v: &i64) -> Option { @@ -893,7 +894,8 @@ impl CheckedMul for u32 { } } -#[cfg(not(stage0))] +// FIXME: #8449: should not be disabled on 32-bit +#[cfg(not(stage0), target_word_size = "64")] impl CheckedMul for u64 { #[inline] fn checked_mul(&self, v: &u64) -> Option { -- cgit 1.4.1-3-g733a5