Selaa lähdekoodia

Completely replace `LargeInt`

Aaron Kutch 4 vuotta sitten
vanhempi
commit
400c5042d8
5 muutettua tiedostoa jossa 83 lisäystä ja 170 poistoa
  1. 23 61
      src/int/addsub.rs
  2. 0 44
      src/int/mod.rs
  3. 24 21
      src/int/mul.rs
  4. 32 40
      src/int/shift.rs
  5. 4 4
      src/macros.rs

+ 23 - 61
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
     <Self as Int>::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
     <Self as Int>::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)
     }
 }

+ 0 - 44
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<T: Copy>: Copy {
     fn cast(self) -> T;

+ 24 - 21
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 = !<<Self as LargeInt>::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())
     }
 }
 

+ 32 - 40
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<HighHalf = <Self as 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<LowHalf = <<Self as 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<HighHalf = <Self as 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),
             )
         }
     }

+ 4 - 4
src/macros.rs

@@ -284,16 +284,16 @@ pub mod win64_128bit_abi_hack {
 
     impl From<i128> 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<u128> for U64x2 {
         fn from(i: u128) -> U64x2 {
-            use int::LargeInt;
-            U64x2(i.low(), i.high())
+            use int::DInt;
+            U64x2(i.lo(), i.hi())
         }
     }
 }