diff --git a/src/int/add.rs b/src/int/add.rs new file mode 100644 index 0000000..639d14a --- /dev/null +++ b/src/int/add.rs @@ -0,0 +1,111 @@ +use int::LargeInt; +use int::Int; + +trait Add: LargeInt { + fn add(self, other: Self) -> Self { + let (low, carry) = self.low().overflowing_add(other.low()); + let high = self.high().wrapping_add(other.high()); + let carry = if carry { Self::HighHalf::ONE } else { Self::HighHalf::ZERO }; + Self::from_parts(low, high.wrapping_add(carry)) + } +} + +impl Add for u128 {} + +trait Addo: Int { + fn addo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_add(other); + if other >= Self::ZERO { + if result < self { + *overflow = 1; + } + } else { + if result >= self { + *overflow = 1; + } + } + result + } +} + +impl Addo for i128 {} +impl Addo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_add")] +#[allow(dead_code)] +fn rust_i128_add(a: i128, b: i128) -> i128 { + rust_u128_add(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_addo")] +#[allow(dead_code)] +fn rust_i128_addo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_add")] +#[allow(dead_code)] +fn rust_u128_add(a: u128, b: u128) -> u128 { + a.add(b) +} +#[cfg_attr(not(stage0), lang = "u128_addo")] +#[allow(dead_code)] +fn rust_u128_addo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.addo(b, &mut oflow); + (r, oflow != 0) +} + +#[test] +fn test_add() { + assert_eq!(rust_u128_add(1, 2), 3); + assert_eq!(rust_u128_add(!0, 3), 2); + assert_eq!(rust_u128_add(1 << 63, 1 << 63), 1 << 64); + assert_eq!(rust_u128_add( + 0x54009B79B43145A0_B781BF1FD491296E_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + 0xB41A6A66596687B1_3B1C743CE9F12161_u128); + assert_eq!(rust_u128_add( + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + 0x2AC60FFECA228F12_37A550530BE8B83E_u128); + + assert_eq!(rust_i128_add(1, 2), 3); + assert_eq!(rust_i128_add(-1, 3), 2); +} + +#[test] +fn test_addo() { + assert_eq!(rust_u128_addo(1, 2), (3, false)); + assert_eq!(rust_u128_addo(!0, 3), (2, true)); + assert_eq!(rust_u128_addo(1 << 63, 1 << 63), (1 << 64, false)); + assert_eq!(rust_u128_addo( + 0x54009B79B43145A0_B781BF1FD491296E_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + (0xB41A6A66596687B1_3B1C743CE9F12161_u128, false)); + assert_eq!(rust_u128_addo( + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + (0x2AC60FFECA228F12_37A550530BE8B83E_u128, true)); + + assert_eq!(rust_i128_addo(1, 2), (3, false)); + assert_eq!(rust_i128_addo(-1, 3), (2, false)); + assert_eq!(rust_i128_addo(1 << 63, 1 << 63), (1 << 64, false)); + assert_eq!(rust_i128_addo( + 0x54009B79B43145A0_B781BF1FD491296E_i128, + 0x6019CEECA5354210_839AB51D155FF7F3_i128), + (-0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); + assert_eq!(rust_i128_addo( + 0x3AE89C3AACEE47CD_8721275248B38DDB_i128, + -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); + assert_eq!(rust_i128_addo( + -0x54009B79B43145A0_B781BF1FD491296E_i128, + -0x6019CEECA5354210_839AB51D155FF7F3_i128), + (0x4BE59599A699784E_C4E38BC3160EDE9F_i128, true)); + assert_eq!(rust_i128_addo( + -0x3AE89C3AACEE47CD_8721275248B38DDB_i128, + 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (-0x2AC60FFECA228F12_37A550530BE8B83E_i128, false)); +} \ No newline at end of file diff --git a/src/int/mod.rs b/src/int/mod.rs index 37dac8c..c5490cb 100644 --- a/src/int/mod.rs +++ b/src/int/mod.rs @@ -12,9 +12,11 @@ macro_rules! os_ty { } } +pub mod add; pub mod mul; pub mod sdiv; pub mod shift; +pub mod sub; pub mod udiv; /// Trait for some basic operations on integers @@ -72,6 +74,7 @@ pub trait Int: fn wrapping_mul(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self; fn wrapping_shl(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); fn aborting_div(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self; fn leading_zeros(self) -> u32; @@ -119,6 +122,10 @@ macro_rules! int_impl_common { ::wrapping_shl(self, other) } + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } + fn aborting_div(self, other: Self) -> Self { unwrap(::checked_div(self, other)) } diff --git a/src/int/mul.rs b/src/int/mul.rs index a4b2ebd..9d45fa5 100644 --- a/src/int/mul.rs +++ b/src/int/mul.rs @@ -70,6 +70,18 @@ impl Mulo for i32 {} impl Mulo for i64 {} impl Mulo for i128 {} +trait UMulo : Int { + fn mulo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_mul(other); + if self > Self::max_value().aborting_div(other) { + *overflow = 1; + } + result + } +} +impl UMulo for u128 {} + intrinsics! { #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] #[arm_aeabi_alias = __aeabi_lmul] @@ -95,3 +107,28 @@ intrinsics! { a.mulo(b, oflow) } } + +#[cfg_attr(not(stage0), lang = "i128_mul")] +#[allow(dead_code)] +fn rust_i128_mul(a: i128, b: i128) -> i128 { + __multi3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_mulo")] +#[allow(dead_code)] +fn rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = __muloti4(a, b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_mul")] +#[allow(dead_code)] +fn rust_u128_mul(a: u128, b: u128) -> u128 { + __multi3(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "u128_mulo")] +#[allow(dead_code)] +fn rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.mulo(b, &mut oflow); + (r, oflow != 0) +} diff --git a/src/int/sdiv.rs b/src/int/sdiv.rs index ff8fa61..6fef631 100644 --- a/src/int/sdiv.rs +++ b/src/int/sdiv.rs @@ -97,3 +97,14 @@ intrinsics! { a.divmod(b, rem, |a, b| __divdi3(a, b)) } } + +#[cfg_attr(not(stage0), lang = "i128_div")] +#[allow(dead_code)] +fn rust_i128_div(a: i128, b: i128) -> i128 { + __divti3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_rem")] +#[allow(dead_code)] +fn rust_i128_rem(a: i128, b: i128) -> i128 { + __modti3(a, b) +} diff --git a/src/int/shift.rs b/src/int/shift.rs index 805d705..de6d06b 100644 --- a/src/int/shift.rs +++ b/src/int/shift.rs @@ -95,3 +95,45 @@ intrinsics! { a.lshr(b) } } + +#[cfg_attr(not(stage0), lang = "i128_shl")] +#[allow(dead_code)] +fn rust_i128_shl(a: i128, b: u32) -> i128 { + __ashlti3(a as _, b) as _ +} +#[cfg_attr(not(stage0), lang = "i128_shlo")] +#[allow(dead_code)] +fn rust_i128_shlo(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shl(a, b as _), b >= 128) +} +#[cfg_attr(not(stage0), lang = "u128_shl")] +#[allow(dead_code)] +fn rust_u128_shl(a: u128, b: u32) -> u128 { + __ashlti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_shlo")] +#[allow(dead_code)] +fn rust_u128_shlo(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shl(a, b as _), b >= 128) +} + +#[cfg_attr(not(stage0), lang = "i128_shr")] +#[allow(dead_code)] +fn rust_i128_shr(a: i128, b: u32) -> i128 { + __ashrti3(a, b) +} +#[cfg_attr(not(stage0), lang = "i128_shro")] +#[allow(dead_code)] +fn rust_i128_shro(a: i128, b: u128) -> (i128, bool) { + (rust_i128_shr(a, b as _), b >= 128) +} +#[cfg_attr(not(stage0), lang = "u128_shr")] +#[allow(dead_code)] +fn rust_u128_shr(a: u128, b: u32) -> u128 { + __lshrti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_shro")] +#[allow(dead_code)] +fn rust_u128_shro(a: u128, b: u128) -> (u128, bool) { + (rust_u128_shr(a, b as _), b >= 128) +} diff --git a/src/int/sub.rs b/src/int/sub.rs new file mode 100644 index 0000000..4d3dfeb --- /dev/null +++ b/src/int/sub.rs @@ -0,0 +1,109 @@ +use int::LargeInt; +use int::Int; + +trait Sub: LargeInt { + fn sub(self, other: Self) -> Self { + let neg_other = (!other).wrapping_add(Self::ONE); + self.wrapping_add(neg_other) + } +} + +impl Sub for u128 {} + +trait Subo: Int { + fn subo(self, other: Self, overflow: &mut i32) -> Self { + *overflow = 0; + let result = self.wrapping_sub(other); + if other >= Self::ZERO { + if result > self { + *overflow = 1; + } + } else { + if result <= self { + *overflow = 1; + } + } + result + } +} + +impl Subo for i128 {} +impl Subo for u128 {} + +#[cfg_attr(not(stage0), lang = "i128_sub")] +#[allow(dead_code)] +fn rust_i128_sub(a: i128, b: i128) -> i128 { + rust_u128_sub(a as _, b as _) as _ +} +#[cfg_attr(not(stage0), lang = "i128_subo")] +#[allow(dead_code)] +fn rust_i128_subo(a: i128, b: i128) -> (i128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} +#[cfg_attr(not(stage0), lang = "u128_sub")] +#[allow(dead_code)] +fn rust_u128_sub(a: u128, b: u128) -> u128 { + a.sub(b) +} +#[cfg_attr(not(stage0), lang = "u128_subo")] +#[allow(dead_code)] +fn rust_u128_subo(a: u128, b: u128) -> (u128, bool) { + let mut oflow = 0; + let r = a.subo(b, &mut oflow); + (r, oflow != 0) +} + +#[test] +fn test_sub() { + assert_eq!(rust_u128_sub(3, 2), 1); + assert_eq!(rust_u128_sub(2, 3), !0); + assert_eq!(rust_u128_sub(1 << 64, 1 << 63), 1 << 63); + assert_eq!(rust_u128_sub( + 0xB41A6A66596687B1_3B1C743CE9F12161_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + 0x54009B79B43145A0_B781BF1FD491296E_u128); + assert_eq!(rust_u128_sub( + 0x2AC60FFECA228F12_37A550530BE8B83E_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + 0x3AE89C3AACEE47CD_8721275248B38DDB_u128); + + assert_eq!(rust_i128_sub(3, 2), 1); + assert_eq!(rust_i128_sub(2, 3), -1); +} + +#[test] +fn test_subo() { + assert_eq!(rust_u128_subo(3, 2), (1, false)); + assert_eq!(rust_u128_subo(2, 3), (!0, true)); + assert_eq!(rust_u128_subo(1 << 64, 1 << 63), (1 << 63, false)); + assert_eq!(rust_u128_subo( + 0xB41A6A66596687B1_3B1C743CE9F12161_u128, + 0x6019CEECA5354210_839AB51D155FF7F3_u128), + (0x54009B79B43145A0_B781BF1FD491296E_u128, false)); + assert_eq!(rust_u128_subo( + 0x2AC60FFECA228F12_37A550530BE8B83E_u128, + 0xEFDD73C41D344744_B0842900C3352A63_u128), + (0x3AE89C3AACEE47CD_8721275248B38DDB_u128, true)); + + assert_eq!(rust_i128_subo(3, 2), (1, false)); + assert_eq!(rust_i128_subo(2, 3), (-1, false)); + assert_eq!(rust_i128_subo(1 << 64, 1 << 63), (1 << 63, false)); + assert_eq!(rust_i128_subo( + -0x4BE59599A699784E_C4E38BC3160EDE9F_i128, + 0x6019CEECA5354210_839AB51D155FF7F3_i128), + (0x54009B79B43145A0_B781BF1FD491296E_i128, true)); + assert_eq!(rust_i128_subo( + 0x2AC60FFECA228F12_37A550530BE8B83E_i128, + -0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); + assert_eq!(rust_i128_subo( + 0x4BE59599A699784E_C4E38BC3160EDE9F_i128, + -0x6019CEECA5354210_839AB51D155FF7F3_i128), + (-0x54009B79B43145A0_B781BF1FD491296E_i128, true)); + assert_eq!(rust_i128_subo( + -0x2AC60FFECA228F12_37A550530BE8B83E_i128, + 0x10228C3BE2CBB8BB_4F7BD6FF3CCAD59D_i128), + (-0x3AE89C3AACEE47CD_8721275248B38DDB_i128, false)); +} \ No newline at end of file diff --git a/src/int/udiv.rs b/src/int/udiv.rs index 74a2ac3..0442a8c 100644 --- a/src/int/udiv.rs +++ b/src/int/udiv.rs @@ -269,3 +269,14 @@ intrinsics! { udivmod_inner!(n, d, rem, u128) } } + +#[cfg_attr(not(stage0), lang = "u128_div")] +#[allow(dead_code)] +fn rust_u128_div(a: u128, b: u128) -> u128 { + __udivti3(a, b) +} +#[cfg_attr(not(stage0), lang = "u128_rem")] +#[allow(dead_code)] +fn rust_u128_rem(a: u128, b: u128) -> u128 { + __umodti3(a, b) +} diff --git a/src/lib.rs b/src/lib.rs index 8bf3230..ff7885b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ #![feature(repr_simd)] #![feature(abi_unadjusted)] #![feature(linkage)] +#![feature(lang_items)] #![allow(unused_features)] #![no_builtins] #![unstable(feature = "compiler_builtins_lib",