|
@@ -1,95 +1,96 @@
|
|
|
+use core::ops;
|
|
|
+
|
|
|
use int::LargeInt;
|
|
|
use int::Int;
|
|
|
|
|
|
-macro_rules! mul {
|
|
|
- ($(#[$attr:meta])+ |
|
|
|
- $abi:tt, $intrinsic:ident: $ty:ty) => {
|
|
|
- /// Returns `a * b`
|
|
|
- $(#[$attr])+
|
|
|
- pub extern $abi fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
|
|
- let half_bits = <$ty>::bits() / 4;
|
|
|
- let lower_mask = !0 >> half_bits;
|
|
|
- let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
|
|
|
- let mut t = low >> half_bits;
|
|
|
- low &= lower_mask;
|
|
|
- t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask);
|
|
|
- low += (t & lower_mask) << half_bits;
|
|
|
- let mut high = (t >> half_bits) as hty!($ty);
|
|
|
- t = low >> half_bits;
|
|
|
- low &= lower_mask;
|
|
|
- t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask);
|
|
|
- low += (t & lower_mask) << half_bits;
|
|
|
- high += (t >> half_bits) as hty!($ty);
|
|
|
- high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as hty!($ty);
|
|
|
- high = high.wrapping_add(a.high().wrapping_mul(b.low() as hty!($ty)))
|
|
|
- .wrapping_add((a.low() as hty!($ty)).wrapping_mul(b.high()));
|
|
|
- <$ty>::from_parts(low, high)
|
|
|
- }
|
|
|
+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)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-macro_rules! mulo {
|
|
|
- ($intrinsic:ident: $ty:ty) => {
|
|
|
- // Default is "C" ABI
|
|
|
- mulo!($intrinsic: $ty, "C");
|
|
|
- };
|
|
|
- ($intrinsic:ident: $ty:ty, $abi:tt) => {
|
|
|
- /// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows
|
|
|
- #[cfg_attr(not(test), no_mangle)]
|
|
|
- pub extern $abi fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty {
|
|
|
- *overflow = 0;
|
|
|
- let result = a.wrapping_mul(b);
|
|
|
- if a == <$ty>::min_value() {
|
|
|
- if b != 0 && b != 1 {
|
|
|
- *overflow = 1;
|
|
|
- }
|
|
|
- return result;
|
|
|
+impl Mul for u64 {}
|
|
|
+impl Mul for i128 {}
|
|
|
+
|
|
|
+trait Mulo: Int + ops::Neg<Output = Self> {
|
|
|
+ fn mulo(self, other: Self, overflow: &mut i32) -> Self {
|
|
|
+ *overflow = 0;
|
|
|
+ let result = self.wrapping_mul(other);
|
|
|
+ if self == Self::min_value() {
|
|
|
+ if other != Self::zero() && other != Self::one() {
|
|
|
+ *overflow = 1;
|
|
|
}
|
|
|
- if b == <$ty>::min_value() {
|
|
|
- if a != 0 && a != 1 {
|
|
|
- *overflow = 1;
|
|
|
- }
|
|
|
- return result;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ if other == Self::min_value() {
|
|
|
+ if self != Self::zero() && self != Self::one() {
|
|
|
+ *overflow = 1;
|
|
|
}
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
- let sa = a >> (<$ty>::bits() - 1);
|
|
|
- let abs_a = (a ^ sa) - sa;
|
|
|
- let sb = b >> (<$ty>::bits() - 1);
|
|
|
- let abs_b = (b ^ sb) - sb;
|
|
|
- if abs_a < 2 || abs_b < 2 {
|
|
|
- return result;
|
|
|
+ let sa = self >> (Self::bits() - 1);
|
|
|
+ let abs_a = (self ^ sa) - sa;
|
|
|
+ let sb = other >> (Self::bits() - 1);
|
|
|
+ let abs_b = (other ^ sb) - sb;
|
|
|
+ let two = Self::one() + Self::one();
|
|
|
+ if abs_a < two || abs_b < two {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ if sa == sb {
|
|
|
+ if abs_a > Self::max_value() / abs_b {
|
|
|
+ *overflow = 1;
|
|
|
}
|
|
|
- if sa == sb {
|
|
|
- if abs_a > <$ty>::max_value() / abs_b {
|
|
|
- *overflow = 1;
|
|
|
- }
|
|
|
- } else {
|
|
|
- if abs_a > <$ty>::min_value() / -abs_b {
|
|
|
- *overflow = 1;
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ if abs_a > Self::min_value() / -abs_b {
|
|
|
+ *overflow = 1;
|
|
|
}
|
|
|
- result
|
|
|
}
|
|
|
+ result
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
|
|
-mul!(#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
|
|
|
- #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))]
|
|
|
- | "C", __muldi3: u64);
|
|
|
+impl Mulo for i32 {}
|
|
|
+impl Mulo for i64 {}
|
|
|
+impl Mulo for i128 {}
|
|
|
|
|
|
-#[cfg(not(target_arch = "arm"))]
|
|
|
-mul!(#[cfg_attr(not(test), no_mangle)]
|
|
|
- | "C", __multi3: i128);
|
|
|
+intrinsics! {
|
|
|
+ #[cfg(not(all(feature = "c", target_arch = "x86")))]
|
|
|
+ pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 {
|
|
|
+ a.mul(b)
|
|
|
+ }
|
|
|
|
|
|
-#[cfg(target_arch = "arm")]
|
|
|
-mul!(#[cfg_attr(not(test), no_mangle)]
|
|
|
- | "aapcs", __multi3: i128);
|
|
|
+ #[aapcs_on_arm]
|
|
|
+ pub extern "C" fn __multi3(a: i128, b: i128) -> i128 {
|
|
|
+ a.mul(b)
|
|
|
+ }
|
|
|
+
|
|
|
+ pub extern "C" fn __mulosi4(a: i32, b: i32, oflow: &mut i32) -> i32 {
|
|
|
+ a.mulo(b, oflow)
|
|
|
+ }
|
|
|
|
|
|
-mulo!(__mulosi4: i32);
|
|
|
-mulo!(__mulodi4: i64);
|
|
|
+ pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 {
|
|
|
+ a.mulo(b, oflow)
|
|
|
+ }
|
|
|
|
|
|
-#[cfg(all(windows, target_pointer_width="64"))]
|
|
|
-mulo!(__muloti4: i128, "unadjusted");
|
|
|
-#[cfg(not(all(windows, target_pointer_width="64")))]
|
|
|
-mulo!(__muloti4: i128);
|
|
|
+ #[unadjusted_on_win64]
|
|
|
+ pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 {
|
|
|
+ a.mulo(b, oflow)
|
|
|
+ }
|
|
|
+}
|