Completely replace LargeInt

This commit is contained in:
Aaron Kutch
2020-10-12 23:58:55 -05:00
parent d5b7e2b6d3
commit fac884b0c4
5 changed files with 83 additions and 170 deletions

View File

@@ -1,25 +1,16 @@
use int::Int; use int::{DInt, Int};
use int::LargeInt;
trait UAddSub: LargeInt { trait UAddSub: DInt {
fn uadd(self, other: Self) -> Self { fn uadd(self, other: Self) -> Self {
let (low, carry) = self.low().overflowing_add(other.low()); let (lo, carry) = self.lo().overflowing_add(other.lo());
let high = self.high().wrapping_add(other.high()); let hi = self.hi().wrapping_add(other.hi());
let carry = if carry { let carry = if carry { Self::H::ONE } else { Self::H::ZERO };
Self::HighHalf::ONE Self::from_lo_hi(lo, hi.wrapping_add(carry))
} else {
Self::HighHalf::ZERO
};
Self::from_parts(low, high.wrapping_add(carry))
} }
fn uadd_one(self) -> Self { fn uadd_one(self) -> Self {
let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE); let (lo, carry) = self.lo().overflowing_add(Self::H::ONE);
let carry = if carry { let carry = if carry { Self::H::ONE } else { Self::H::ZERO };
Self::HighHalf::ONE Self::from_lo_hi(lo, self.hi().wrapping_add(carry))
} else {
Self::HighHalf::ZERO
};
Self::from_parts(low, self.high().wrapping_add(carry))
} }
fn usub(self, other: Self) -> Self { fn usub(self, other: Self) -> Self {
let uneg = (!other).uadd_one(); let uneg = (!other).uadd_one();
@@ -48,19 +39,9 @@ trait Addo: AddSub
where where
<Self as Int>::UnsignedInt: UAddSub, <Self as Int>::UnsignedInt: UAddSub,
{ {
fn addo(self, other: Self, overflow: &mut i32) -> Self { fn addo(self, other: Self) -> (Self, bool) {
*overflow = 0; let sum = AddSub::add(self, other);
let result = AddSub::add(self, other); (sum, (other < Self::ZERO) != (sum < self))
if other >= Self::ZERO {
if result < self {
*overflow = 1;
}
} else {
if result >= self {
*overflow = 1;
}
}
result
} }
} }
@@ -71,19 +52,9 @@ trait Subo: AddSub
where where
<Self as Int>::UnsignedInt: UAddSub, <Self as Int>::UnsignedInt: UAddSub,
{ {
fn subo(self, other: Self, overflow: &mut i32) -> Self { fn subo(self, other: Self) -> (Self, bool) {
*overflow = 0; let sum = AddSub::sub(self, other);
let result = AddSub::sub(self, other); (sum, (other < Self::ZERO) != (self < sum))
if other >= Self::ZERO {
if result > self {
*overflow = 1;
}
} else {
if result <= self {
*overflow = 1;
}
}
result
} }
} }
@@ -92,43 +63,34 @@ impl Subo for u128 {}
intrinsics! { intrinsics! {
pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 { 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) { pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) {
let mut oflow = 0; a.addo(b)
let r = a.addo(b, &mut oflow);
(r, oflow != 0)
} }
pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 { 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) { pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) {
let mut oflow = 0; a.addo(b)
let r = a.addo(b, &mut oflow);
(r, oflow != 0)
} }
pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 { 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) { pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) {
let mut oflow = 0; a.subo(b)
let r = a.subo(b, &mut oflow);
(r, oflow != 0)
} }
pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 { 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) { pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) {
let mut oflow = 0; a.subo(b)
let r = a.subo(b, &mut oflow);
(r, oflow != 0)
} }
} }

View File

@@ -384,50 +384,6 @@ impl_h_int!(
i64 u64 i128 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 /// Trait to express (possibly lossy) casting of integers
pub(crate) trait CastInto<T: Copy>: Copy { pub(crate) trait CastInto<T: Copy>: Copy {
fn cast(self) -> T; fn cast(self) -> T;

View File

@@ -1,26 +1,29 @@
use int::LargeInt;
use int::{DInt, HInt, Int}; use int::{DInt, HInt, Int};
trait Mul: LargeInt { trait Mul: DInt
fn mul(self, other: Self) -> Self { where
let half_bits = Self::BITS / 4; Self::H: DInt,
let lower_mask = !<<Self as LargeInt>::LowHalf>::ZERO >> half_bits; {
let mut low = (self.low() & lower_mask).wrapping_mul(other.low() & lower_mask); fn mul(self, rhs: Self) -> Self {
let mut t = low >> half_bits; // In order to prevent infinite recursion, we cannot use the `widen_mul` in this:
low &= lower_mask; //self.lo().widen_mul(rhs.lo())
t += (self.low() >> half_bits).wrapping_mul(other.low() & lower_mask); // .wrapping_add(self.lo().wrapping_mul(rhs.hi()).widen_hi())
low += (t & lower_mask) << half_bits; // .wrapping_add(self.hi().wrapping_mul(rhs.lo()).widen_hi())
let mut high = Self::low_as_high(t >> half_bits);
t = low >> half_bits; let lhs_lo = self.lo();
low &= lower_mask; let rhs_lo = rhs.lo();
t += (other.low() >> half_bits).wrapping_mul(self.low() & lower_mask); // construct the widening multiplication using only `Self::H` sized multiplications
low += (t & lower_mask) << half_bits; let tmp_0 = lhs_lo.lo().zero_widen_mul(rhs_lo.lo());
high += Self::low_as_high(t >> half_bits); let tmp_1 = lhs_lo.lo().zero_widen_mul(rhs_lo.hi());
high += Self::low_as_high((self.low() >> half_bits).wrapping_mul(other.low() >> half_bits)); let tmp_2 = lhs_lo.hi().zero_widen_mul(rhs_lo.lo());
high = high let tmp_3 = lhs_lo.hi().zero_widen_mul(rhs_lo.hi());
.wrapping_add(self.high().wrapping_mul(Self::low_as_high(other.low()))) // sum up all widening partials
.wrapping_add(Self::low_as_high(self.low()).wrapping_mul(other.high())); let mul = Self::from_lo_hi(tmp_0, tmp_3)
Self::from_parts(low, high) .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())
} }
} }

View File

@@ -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` /// Returns `a << b`, requires `b < Self::BITS`
fn ashl(self, offset: u32) -> Self fn ashl(self, shl: u32) -> Self {
where let n_h = Self::H::BITS;
Self: LargeInt<HighHalf = <Self as LargeInt>::LowHalf>, if shl & n_h != 0 {
{ // we only need `self.lo()` because `self.hi()` will be shifted out entirely
let half_bits = Self::BITS / 2; (self.lo() << (shl - n_h)).widen_hi()
if offset & half_bits != 0 { } else if shl == 0 {
Self::from_parts(Int::ZERO, self.low() << (offset - half_bits))
} else if offset == 0 {
self self
} else { } else {
Self::from_parts( Self::from_lo_hi(
self.low() << offset, self.lo() << shl,
(self.high() << offset) | (self.low() >> (half_bits - offset)), 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 u64 {}
impl Ashl for u128 {} impl Ashl for u128 {}
trait Ashr: Int + LargeInt { trait Ashr: DInt {
/// Returns arithmetic `a >> b`, requires `b < Self::BITS` /// Returns arithmetic `a >> b`, requires `b < Self::BITS`
fn ashr(self, offset: u32) -> Self fn ashr(self, shr: u32) -> Self {
where let n_h = Self::H::BITS;
Self: LargeInt<LowHalf = <<Self as LargeInt>::HighHalf as Int>::UnsignedInt>, if shr & n_h != 0 {
{ Self::from_lo_hi(
let half_bits = Self::BITS / 2; self.hi() >> (shr - n_h),
if offset & half_bits != 0 { // smear the sign bit
Self::from_parts( self.hi() >> (n_h - 1),
(self.high() >> (offset - half_bits)).unsigned(),
self.high() >> (half_bits - 1),
) )
} else if offset == 0 { } else if shr == 0 {
self self
} else { } else {
let high_unsigned = self.high().unsigned(); Self::from_lo_hi(
Self::from_parts( self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)),
(high_unsigned << (half_bits - offset)) | (self.low() >> offset), self.hi() >> shr,
self.high() >> offset,
) )
} }
} }
@@ -52,21 +47,18 @@ impl Ashr for i32 {}
impl Ashr for i64 {} impl Ashr for i64 {}
impl Ashr for i128 {} impl Ashr for i128 {}
trait Lshr: Int + LargeInt { trait Lshr: DInt {
/// Returns logical `a >> b`, requires `b < Self::BITS` /// Returns logical `a >> b`, requires `b < Self::BITS`
fn lshr(self, offset: u32) -> Self fn lshr(self, shr: u32) -> Self {
where let n_h = Self::H::BITS;
Self: LargeInt<HighHalf = <Self as LargeInt>::LowHalf>, if shr & n_h != 0 {
{ self.hi().logical_shr(shr - n_h).zero_widen()
let half_bits = Self::BITS / 2; } else if shr == 0 {
if offset & half_bits != 0 {
Self::from_parts(self.high() >> (offset - half_bits), Int::ZERO)
} else if offset == 0 {
self self
} else { } else {
Self::from_parts( Self::from_lo_hi(
(self.high() << (half_bits - offset)) | (self.low() >> offset), self.lo().logical_shr(shr) | (self.hi() << (n_h - shr)),
self.high() >> offset, self.hi().logical_shr(shr),
) )
} }
} }

View File

@@ -284,16 +284,16 @@ pub mod win64_128bit_abi_hack {
impl From<i128> for U64x2 { impl From<i128> for U64x2 {
fn from(i: i128) -> U64x2 { fn from(i: i128) -> U64x2 {
use int::LargeInt; use int::DInt;
let j = i as u128; let j = i as u128;
U64x2(j.low(), j.high()) U64x2(j.lo(), j.hi())
} }
} }
impl From<u128> for U64x2 { impl From<u128> for U64x2 {
fn from(i: u128) -> U64x2 { fn from(i: u128) -> U64x2 {
use int::LargeInt; use int::DInt;
U64x2(i.low(), i.high()) U64x2(i.lo(), i.hi())
} }
} }
} }