Macro-ify udivmod
This commit is contained in:
parent
1e27c3f937
commit
8fe50d813c
|
@ -1,3 +1,14 @@
|
|||
macro_rules! hty {
|
||||
($ty:ty) => {
|
||||
<$ty as LargeInt>::HighHalf
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! os_ty {
|
||||
($ty:ty) => {
|
||||
<$ty as Int>::OtherSign
|
||||
}
|
||||
}
|
||||
|
||||
pub mod mul;
|
||||
pub mod sdiv;
|
||||
|
@ -6,6 +17,8 @@ pub mod udiv;
|
|||
|
||||
/// Trait for some basic operations on integers
|
||||
pub trait Int {
|
||||
/// Type with the same width but other signedness
|
||||
type OtherSign;
|
||||
/// Returns the bitwidth of the int type
|
||||
fn bits() -> u32;
|
||||
}
|
||||
|
@ -13,11 +26,13 @@ pub trait Int {
|
|||
macro_rules! int_impl {
|
||||
($ity:ty, $sty:ty, $bits:expr) => {
|
||||
impl Int for $ity {
|
||||
type OtherSign = $sty;
|
||||
fn bits() -> u32 {
|
||||
$bits
|
||||
}
|
||||
}
|
||||
impl Int for $sty {
|
||||
type OtherSign = $ity;
|
||||
fn bits() -> u32 {
|
||||
$bits
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use int::LargeInt;
|
|||
use int::Int;
|
||||
|
||||
macro_rules! mul {
|
||||
($intrinsic:ident: $ty:ty, $tyh:ty) => {
|
||||
($intrinsic:ident: $ty:ty) => {
|
||||
/// Returns `a * b`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||
|
@ -13,15 +13,15 @@ macro_rules! mul {
|
|||
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 $tyh;
|
||||
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 $tyh;
|
||||
high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as $tyh;
|
||||
high = high.wrapping_add(a.high().wrapping_mul(b.low() as $tyh))
|
||||
.wrapping_add((a.low() as $tyh).wrapping_mul(b.high()));
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -73,9 +73,9 @@ macro_rules! mulo {
|
|||
}
|
||||
|
||||
#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
||||
mul!(__muldi3: u64, u32);
|
||||
mul!(__muldi3: u64);
|
||||
|
||||
mul!(__multi3: i128, i64);
|
||||
mul!(__multi3: i128);
|
||||
|
||||
mulo!(__mulosi4: i32);
|
||||
mulo!(__mulodi4: i64);
|
||||
|
|
273
src/int/udiv.rs
273
src/int/udiv.rs
|
@ -114,152 +114,159 @@ pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 {
|
|||
rem
|
||||
}
|
||||
|
||||
/// Returns `n / d` and sets `*rem = n % d`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||
// NOTE X is unknown, K != 0
|
||||
if n.high() == 0 {
|
||||
if d.high() == 0 {
|
||||
// 0 X
|
||||
// ---
|
||||
// 0 X
|
||||
macro_rules! udivmod_inner {
|
||||
($n:expr, $d:expr, $rem:expr, $ty:ty) => {{
|
||||
let (n, d, rem) = ($n, $d, $rem);
|
||||
// NOTE X is unknown, K != 0
|
||||
if n.high() == 0 {
|
||||
if d.high() == 0 {
|
||||
// 0 X
|
||||
// ---
|
||||
// 0 X
|
||||
|
||||
if let Some(rem) = rem {
|
||||
*rem = u64::from(urem!(n.low(), d.low()));
|
||||
}
|
||||
return u64::from(udiv!(n.low(), d.low()));
|
||||
} else {
|
||||
// 0 X
|
||||
// ---
|
||||
// K X
|
||||
if let Some(rem) = rem {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
let mut sr;
|
||||
let mut q;
|
||||
let mut r;
|
||||
|
||||
if d.low() == 0 {
|
||||
if d.high() == 0 {
|
||||
// K X
|
||||
// ---
|
||||
// 0 0
|
||||
// NOTE This should be unreachable in safe Rust because the program will panic before
|
||||
// this intrinsic is called
|
||||
unsafe {
|
||||
intrinsics::abort()
|
||||
}
|
||||
}
|
||||
|
||||
if n.low() == 0 {
|
||||
// K 0
|
||||
// ---
|
||||
// K 0
|
||||
if let Some(rem) = rem {
|
||||
*rem = u64::from_parts(0, urem!(n.high(), d.high()));
|
||||
}
|
||||
return u64::from(udiv!(n.high(), d.high()));
|
||||
}
|
||||
|
||||
// K K
|
||||
// ---
|
||||
// K 0
|
||||
|
||||
if d.high().is_power_of_two() {
|
||||
if let Some(rem) = rem {
|
||||
*rem = u64::from_parts(n.low(), n.high() & (d.high() - 1));
|
||||
}
|
||||
return u64::from(n.high() >> d.high().trailing_zeros());
|
||||
}
|
||||
|
||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||
|
||||
// D > N
|
||||
if sr > u32::bits() - 2 {
|
||||
if let Some(rem) = rem {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sr += 1;
|
||||
|
||||
// 1 <= sr <= u32::bits() - 1
|
||||
q = n << (u64::bits() - sr);
|
||||
r = n >> sr;
|
||||
} else if d.high() == 0 {
|
||||
// K X
|
||||
// ---
|
||||
// 0 K
|
||||
if d.low().is_power_of_two() {
|
||||
if let Some(rem) = rem {
|
||||
*rem = u64::from(n.low() & (d.low() - 1));
|
||||
}
|
||||
|
||||
if d.low() == 1 {
|
||||
return n;
|
||||
if let Some(rem) = rem {
|
||||
*rem = <$ty>::from(urem!(n.low(), d.low()));
|
||||
}
|
||||
return <$ty>::from(udiv!(n.low(), d.low()));
|
||||
} else {
|
||||
let sr = d.low().trailing_zeros();
|
||||
return n >> sr;
|
||||
// 0 X
|
||||
// ---
|
||||
// K X
|
||||
if let Some(rem) = rem {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros();
|
||||
let mut sr;
|
||||
let mut q;
|
||||
let mut r;
|
||||
|
||||
// 2 <= sr <= u64::bits() - 1
|
||||
q = n << (u64::bits() - sr);
|
||||
r = n >> sr;
|
||||
} else {
|
||||
// K X
|
||||
// ---
|
||||
// K K
|
||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||
|
||||
// D > N
|
||||
if sr > u32::bits() - 1 {
|
||||
if let Some(rem) = rem {
|
||||
*rem = n;
|
||||
if d.low() == 0 {
|
||||
if d.high() == 0 {
|
||||
// K X
|
||||
// ---
|
||||
// 0 0
|
||||
// NOTE This should be unreachable in safe Rust because the program will panic before
|
||||
// this intrinsic is called
|
||||
unsafe {
|
||||
intrinsics::abort()
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
if n.low() == 0 {
|
||||
// K 0
|
||||
// ---
|
||||
// K 0
|
||||
if let Some(rem) = rem {
|
||||
*rem = <$ty>::from_parts(0, urem!(n.high(), d.high()));
|
||||
}
|
||||
return <$ty>::from(udiv!(n.high(), d.high()));
|
||||
}
|
||||
|
||||
// K K
|
||||
// ---
|
||||
// K 0
|
||||
|
||||
if d.high().is_power_of_two() {
|
||||
if let Some(rem) = rem {
|
||||
*rem = <$ty>::from_parts(n.low(), n.high() & (d.high() - 1));
|
||||
}
|
||||
return <$ty>::from(n.high() >> d.high().trailing_zeros());
|
||||
}
|
||||
|
||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||
|
||||
// D > N
|
||||
if sr > <hty!($ty)>::bits() - 2 {
|
||||
if let Some(rem) = rem {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sr += 1;
|
||||
|
||||
// 1 <= sr <= <hty!($ty)>::bits() - 1
|
||||
q = n << (<$ty>::bits() - sr);
|
||||
r = n >> sr;
|
||||
} else if d.high() == 0 {
|
||||
// K X
|
||||
// ---
|
||||
// 0 K
|
||||
if d.low().is_power_of_two() {
|
||||
if let Some(rem) = rem {
|
||||
*rem = <$ty>::from(n.low() & (d.low() - 1));
|
||||
}
|
||||
|
||||
if d.low() == 1 {
|
||||
return n;
|
||||
} else {
|
||||
let sr = d.low().trailing_zeros();
|
||||
return n >> sr;
|
||||
};
|
||||
}
|
||||
|
||||
sr = 1 + <hty!($ty)>::bits() + d.low().leading_zeros() - n.high().leading_zeros();
|
||||
|
||||
// 2 <= sr <= u64::bits() - 1
|
||||
q = n << (<$ty>::bits() - sr);
|
||||
r = n >> sr;
|
||||
} else {
|
||||
// K X
|
||||
// ---
|
||||
// K K
|
||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||
|
||||
// D > N
|
||||
if sr > <hty!($ty)>::bits() - 1 {
|
||||
if let Some(rem) = rem {
|
||||
*rem = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sr += 1;
|
||||
|
||||
// 1 <= sr <= <hty!($ty)>::bits()
|
||||
q = n << (<$ty>::bits() - sr);
|
||||
r = n >> sr;
|
||||
}
|
||||
|
||||
sr += 1;
|
||||
// Not a special case
|
||||
// q and r are initialized with
|
||||
// q = n << (u64::bits() - sr)
|
||||
// r = n >> sr
|
||||
// 1 <= sr <= u64::bits() - 1
|
||||
let mut carry = 0;
|
||||
|
||||
// 1 <= sr <= u32::bits()
|
||||
q = n << (u64::bits() - sr);
|
||||
r = n >> sr;
|
||||
}
|
||||
for _ in 0..sr {
|
||||
// r:q = ((r:q) << 1) | carry
|
||||
r = (r << 1) | (q >> (<$ty>::bits() - 1));
|
||||
q = (q << 1) | carry as $ty;
|
||||
|
||||
// Not a special case
|
||||
// q and r are initialized with
|
||||
// q = n << (u64::bits() - sr)
|
||||
// r = n >> sr
|
||||
// 1 <= sr <= u64::bits() - 1
|
||||
let mut carry = 0;
|
||||
// carry = 0
|
||||
// if r >= d {
|
||||
// r -= d;
|
||||
// carry = 1;
|
||||
// }
|
||||
let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1);
|
||||
carry = (s & 1) as hty!($ty);
|
||||
r -= d & s as $ty;
|
||||
}
|
||||
|
||||
for _ in 0..sr {
|
||||
// r:q = ((r:q) << 1) | carry
|
||||
r = (r << 1) | (q >> (u64::bits() - 1));
|
||||
q = (q << 1) | carry as u64;
|
||||
if let Some(rem) = rem {
|
||||
*rem = r;
|
||||
}
|
||||
(q << 1) | carry as $ty
|
||||
}}
|
||||
}
|
||||
|
||||
// carry = 0
|
||||
// if r >= d {
|
||||
// r -= d;
|
||||
// carry = 1;
|
||||
// }
|
||||
let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1);
|
||||
carry = (s & 1) as u32;
|
||||
r -= d & s as u64;
|
||||
}
|
||||
|
||||
if let Some(rem) = rem {
|
||||
*rem = r;
|
||||
}
|
||||
(q << 1) | carry as u64
|
||||
/// Returns `n / d` and sets `*rem = n % d`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||
udivmod_inner!(n, d, rem, u64)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Reference in New Issue