use core::ops; use int::Int; use int::LargeInt; 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) } } impl Mul for u64 {} impl Mul for i128 {} trait Mulo: Int + ops::Neg { 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; } return result; } if other == Self::min_value() { if self != Self::ZERO && self != Self::ONE { *overflow = 1; } 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().aborting_div(abs_b) { *overflow = 1; } } else { if abs_a > Self::min_value().aborting_div(-abs_b) { *overflow = 1; } } result } } impl Mulo for i32 {} impl Mulo for i64 {} 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! { #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { a.mul(b) } #[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) } pub extern "C" fn __mulodi4(a: i64, b: i64, oflow: &mut i32) -> i64 { a.mulo(b, oflow) } #[unadjusted_on_win64] pub extern "C" fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { a.mulo(b, oflow) } pub extern "C" fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool) { let mut oflow = 0; let r = __muloti4(a, b, &mut oflow); (r, oflow != 0) } pub extern "C" fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool) { let mut oflow = 0; let r = a.mulo(b, &mut oflow); (r, oflow != 0) } }