Implement all the 128-bit operator lang items from rust PR 46093

This commit is contained in:
Scott McMurray 2017-11-25 04:21:05 -08:00
parent 02b3734a5b
commit 5e71218390
8 changed files with 329 additions and 0 deletions

111
src/int/add.rs Normal file
View File

@ -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));
}

View File

@ -12,9 +12,11 @@ macro_rules! os_ty {
} }
} }
pub mod add;
pub mod mul; pub mod mul;
pub mod sdiv; pub mod sdiv;
pub mod shift; pub mod shift;
pub mod sub;
pub mod udiv; pub mod udiv;
/// Trait for some basic operations on integers /// Trait for some basic operations on integers
@ -72,6 +74,7 @@ pub trait Int:
fn wrapping_mul(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self;
fn wrapping_sub(self, other: Self) -> Self; fn wrapping_sub(self, other: Self) -> Self;
fn wrapping_shl(self, other: u32) -> 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_div(self, other: Self) -> Self;
fn aborting_rem(self, other: Self) -> Self; fn aborting_rem(self, other: Self) -> Self;
fn leading_zeros(self) -> u32; fn leading_zeros(self) -> u32;
@ -119,6 +122,10 @@ macro_rules! int_impl_common {
<Self>::wrapping_shl(self, other) <Self>::wrapping_shl(self, other)
} }
fn overflowing_add(self, other: Self) -> (Self, bool) {
<Self>::overflowing_add(self, other)
}
fn aborting_div(self, other: Self) -> Self { fn aborting_div(self, other: Self) -> Self {
unwrap(<Self>::checked_div(self, other)) unwrap(<Self>::checked_div(self, other))
} }

View File

@ -70,6 +70,18 @@ impl Mulo for i32 {}
impl Mulo for i64 {} impl Mulo for i64 {}
impl Mulo for i128 {} 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! { intrinsics! {
#[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))] #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))]
#[arm_aeabi_alias = __aeabi_lmul] #[arm_aeabi_alias = __aeabi_lmul]
@ -95,3 +107,28 @@ intrinsics! {
a.mulo(b, oflow) 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)
}

View File

@ -97,3 +97,14 @@ intrinsics! {
a.divmod(b, rem, |a, b| __divdi3(a, b)) 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)
}

View File

@ -95,3 +95,45 @@ intrinsics! {
a.lshr(b) 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)
}

109
src/int/sub.rs Normal file
View File

@ -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));
}

View File

@ -269,3 +269,14 @@ intrinsics! {
udivmod_inner!(n, d, rem, u128) 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)
}

View File

@ -17,6 +17,7 @@
#![feature(repr_simd)] #![feature(repr_simd)]
#![feature(abi_unadjusted)] #![feature(abi_unadjusted)]
#![feature(linkage)] #![feature(linkage)]
#![feature(lang_items)]
#![allow(unused_features)] #![allow(unused_features)]
#![no_builtins] #![no_builtins]
#![unstable(feature = "compiler_builtins_lib", #![unstable(feature = "compiler_builtins_lib",