From 400c5042d8fcc951e1c27252615cb4b9557ad084 Mon Sep 17 00:00:00 2001 From: Aaron Kutch Date: Mon, 12 Oct 2020 23:58:55 -0500 Subject: [PATCH] Completely replace `LargeInt` --- src/int/addsub.rs | 84 +++++++++++++---------------------------------- src/int/mod.rs | 44 ------------------------- src/int/mul.rs | 45 +++++++++++++------------ src/int/shift.rs | 72 ++++++++++++++++++---------------------- src/macros.rs | 8 ++--- 5 files changed, 83 insertions(+), 170 deletions(-) diff --git a/src/int/addsub.rs b/src/int/addsub.rs index 0a88e2fc..f4841e90 100644 --- a/src/int/addsub.rs +++ b/src/int/addsub.rs @@ -1,25 +1,16 @@ -use int::Int; -use int::LargeInt; +use int::{DInt, Int}; -trait UAddSub: LargeInt { +trait UAddSub: DInt { fn uadd(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)) + let (lo, carry) = self.lo().overflowing_add(other.lo()); + let hi = self.hi().wrapping_add(other.hi()); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, hi.wrapping_add(carry)) } fn uadd_one(self) -> Self { - let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); - let carry = if carry { - Self::HighHalf::ONE - } else { - Self::HighHalf::ZERO - }; - Self::from_parts(low, self.high().wrapping_add(carry)) + let (lo, carry) = self.lo().overflowing_add(Self::H::ONE); + let carry = if carry { Self::H::ONE } else { Self::H::ZERO }; + Self::from_lo_hi(lo, self.hi().wrapping_add(carry)) } fn usub(self, other: Self) -> Self { let uneg = (!other).uadd_one(); @@ -48,19 +39,9 @@ trait Addo: AddSub where ::UnsignedInt: UAddSub, { - fn addo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = AddSub::add(self, other); - if other >= Self::ZERO { - if result < self { - *overflow = 1; - } - } else { - if result >= self { - *overflow = 1; - } - } - result + fn addo(self, other: Self) -> (Self, bool) { + let sum = AddSub::add(self, other); + (sum, (other < Self::ZERO) != (sum < self)) } } @@ -71,19 +52,9 @@ trait Subo: AddSub where ::UnsignedInt: UAddSub, { - fn subo(self, other: Self, overflow: &mut i32) -> Self { - *overflow = 0; - let result = AddSub::sub(self, other); - if other >= Self::ZERO { - if result > self { - *overflow = 1; - } - } else { - if result <= self { - *overflow = 1; - } - } - result + fn subo(self, other: Self) -> (Self, bool) { + let sum = AddSub::sub(self, other); + (sum, (other < Self::ZERO) != (self < sum)) } } @@ -92,43 +63,34 @@ impl Subo for u128 {} intrinsics! { pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { - __rust_u128_add(a as _, b as _) as _ + AddSub::add(a,b) } pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) + a.addo(b) } pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { - a.add(b) + AddSub::add(a,b) } pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.addo(b, &mut oflow); - (r, oflow != 0) + a.addo(b) } - pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { - __rust_u128_sub(a as _, b as _) as _ + AddSub::sub(a,b) } pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + a.subo(b) } pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { - a.sub(b) + AddSub::sub(a,b) } pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) { - let mut oflow = 0; - let r = a.subo(b, &mut oflow); - (r, oflow != 0) + a.subo(b) } } diff --git a/src/int/mod.rs b/src/int/mod.rs index da2263f6..1ce3d92d 100644 --- a/src/int/mod.rs +++ b/src/int/mod.rs @@ -384,50 +384,6 @@ impl_h_int!( i64 u64 i128 ); -/// Trait to convert an integer to/from smaller parts -pub(crate) trait LargeInt: Int { - type LowHalf: Int; - type HighHalf: Int; - - fn low(self) -> Self::LowHalf; - fn low_as_high(low: Self::LowHalf) -> Self::HighHalf; - fn high(self) -> Self::HighHalf; - fn high_as_low(low: Self::HighHalf) -> Self::LowHalf; - fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; -} - -macro_rules! large_int { - ($ty:ty, $tylow:ty, $tyhigh:ty, $halfbits:expr) => { - impl LargeInt for $ty { - type LowHalf = $tylow; - type HighHalf = $tyhigh; - - fn low(self) -> $tylow { - self as $tylow - } - fn low_as_high(low: $tylow) -> $tyhigh { - low as $tyhigh - } - fn high(self) -> $tyhigh { - (self >> $halfbits) as $tyhigh - } - fn high_as_low(high: $tyhigh) -> $tylow { - high as $tylow - } - fn from_parts(low: $tylow, high: $tyhigh) -> $ty { - low as $ty | ((high as $ty) << $halfbits) - } - } - }; -} - -large_int!(u32, u16, u16, 16); -large_int!(i32, u16, i16, 16); -large_int!(u64, u32, u32, 32); -large_int!(i64, u32, i32, 32); -large_int!(u128, u64, u64, 64); -large_int!(i128, u64, i64, 64); - /// Trait to express (possibly lossy) casting of integers pub(crate) trait CastInto: Copy { fn cast(self) -> T; diff --git a/src/int/mul.rs b/src/int/mul.rs index e5c0afc1..a5238eea 100644 --- a/src/int/mul.rs +++ b/src/int/mul.rs @@ -1,26 +1,29 @@ -use int::LargeInt; use int::{DInt, HInt, Int}; -trait Mul: LargeInt { - fn mul(self, other: Self) -> Self { - let half_bits = Self::BITS / 4; - let lower_mask = !<::LowHalf>::ZERO >> half_bits; - let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); - let mut t = low >> half_bits; - low &= lower_mask; - t += (self.low() >> half_bits).wrapping_mul(other.low() & lower_mask); - low += (t & lower_mask) << half_bits; - let mut high = Self::low_as_high(t >> half_bits); - t = low >> half_bits; - low &= lower_mask; - t += (other.low() >> half_bits).wrapping_mul(self.low() & lower_mask); - low += (t & lower_mask) << half_bits; - high += Self::low_as_high(t >> half_bits); - high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); - high = high - .wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) - .wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); - Self::from_parts(low, high) +trait Mul: DInt +where + Self::H: DInt, +{ + fn mul(self, rhs: Self) -> Self { + // In order to prevent infinite recursion, we cannot use the `widen_mul` in this: + //self.lo().widen_mul(rhs.lo()) + // .wrapping_add(self.lo().wrapping_mul(rhs.hi()).widen_hi()) + // .wrapping_add(self.hi().wrapping_mul(rhs.lo()).widen_hi()) + + let lhs_lo = self.lo(); + let rhs_lo = rhs.lo(); + // construct the widening multiplication using only `Self::H` sized multiplications + let tmp_0 = lhs_lo.lo().zero_widen_mul(rhs_lo.lo()); + let tmp_1 = lhs_lo.lo().zero_widen_mul(rhs_lo.hi()); + let tmp_2 = lhs_lo.hi().zero_widen_mul(rhs_lo.lo()); + let tmp_3 = lhs_lo.hi().zero_widen_mul(rhs_lo.hi()); + // sum up all widening partials + let mul = Self::from_lo_hi(tmp_0, tmp_3) + .wrapping_add(tmp_1.zero_widen() << (Self::BITS / 4)) + .wrapping_add(tmp_2.zero_widen() << (Self::BITS / 4)); + // add the higher partials + mul.wrapping_add(lhs_lo.wrapping_mul(rhs.hi()).widen_hi()) + .wrapping_add(self.hi().wrapping_mul(rhs_lo).widen_hi()) } } diff --git a/src/int/shift.rs b/src/int/shift.rs index 674c3ee8..20561786 100644 --- a/src/int/shift.rs +++ b/src/int/shift.rs @@ -1,20 +1,18 @@ -use int::{Int, LargeInt}; +use int::{DInt, HInt, Int}; -trait Ashl: Int + LargeInt { +trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` - fn ashl(self, offset: u32) -> Self - where - Self: LargeInt::LowHalf>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts(Int::ZERO, self.low() << (offset - half_bits)) - } else if offset == 0 { + fn ashl(self, shl: u32) -> Self { + let n_h = Self::H::BITS; + if shl & n_h != 0 { + // we only need `self.lo()` because `self.hi()` will be shifted out entirely + (self.lo() << (shl - n_h)).widen_hi() + } else if shl == 0 { self } else { - Self::from_parts( - self.low() << offset, - (self.high() << offset) | (self.low() >> (half_bits - offset)), + Self::from_lo_hi( + self.lo() << shl, + self.lo().logical_shr(n_h - shl) | (self.hi() << shl), ) } } @@ -24,25 +22,22 @@ impl Ashl for u32 {} impl Ashl for u64 {} impl Ashl for u128 {} -trait Ashr: Int + LargeInt { +trait Ashr: DInt { /// Returns arithmetic `a >> b`, requires `b < Self::BITS` - fn ashr(self, offset: u32) -> Self - where - Self: LargeInt::HighHalf as Int>::UnsignedInt>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts( - (self.high() >> (offset - half_bits)).unsigned(), - self.high() >> (half_bits - 1), + fn ashr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + Self::from_lo_hi( + self.hi() >> (shr - n_h), + // smear the sign bit + self.hi() >> (n_h - 1), ) - } else if offset == 0 { + } else if shr == 0 { self } else { - let high_unsigned = self.high().unsigned(); - Self::from_parts( - (high_unsigned << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset, + Self::from_lo_hi( + self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.hi() >> shr, ) } } @@ -52,21 +47,18 @@ impl Ashr for i32 {} impl Ashr for i64 {} impl Ashr for i128 {} -trait Lshr: Int + LargeInt { +trait Lshr: DInt { /// Returns logical `a >> b`, requires `b < Self::BITS` - fn lshr(self, offset: u32) -> Self - where - Self: LargeInt::LowHalf>, - { - let half_bits = Self::BITS / 2; - if offset & half_bits != 0 { - Self::from_parts(self.high() >> (offset - half_bits), Int::ZERO) - } else if offset == 0 { + fn lshr(self, shr: u32) -> Self { + let n_h = Self::H::BITS; + if shr & n_h != 0 { + self.hi().logical_shr(shr - n_h).zero_widen() + } else if shr == 0 { self } else { - Self::from_parts( - (self.high() << (half_bits - offset)) | (self.low() >> offset), - self.high() >> offset, + Self::from_lo_hi( + self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)), + self.hi().logical_shr(shr), ) } } diff --git a/src/macros.rs b/src/macros.rs index b02f3ea5..56f27164 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -284,16 +284,16 @@ pub mod win64_128bit_abi_hack { impl From for U64x2 { fn from(i: i128) -> U64x2 { - use int::LargeInt; + use int::DInt; let j = i as u128; - U64x2(j.low(), j.high()) + U64x2(j.lo(), j.hi()) } } impl From for U64x2 { fn from(i: u128) -> U64x2 { - use int::LargeInt; - U64x2(i.low(), i.high()) + use int::DInt; + U64x2(i.lo(), i.hi()) } } }