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 mul;
|
||||||
pub mod sdiv;
|
pub mod sdiv;
|
||||||
|
@ -6,6 +17,8 @@ pub mod udiv;
|
||||||
|
|
||||||
/// Trait for some basic operations on integers
|
/// Trait for some basic operations on integers
|
||||||
pub trait Int {
|
pub trait Int {
|
||||||
|
/// Type with the same width but other signedness
|
||||||
|
type OtherSign;
|
||||||
/// Returns the bitwidth of the int type
|
/// Returns the bitwidth of the int type
|
||||||
fn bits() -> u32;
|
fn bits() -> u32;
|
||||||
}
|
}
|
||||||
|
@ -13,11 +26,13 @@ pub trait Int {
|
||||||
macro_rules! int_impl {
|
macro_rules! int_impl {
|
||||||
($ity:ty, $sty:ty, $bits:expr) => {
|
($ity:ty, $sty:ty, $bits:expr) => {
|
||||||
impl Int for $ity {
|
impl Int for $ity {
|
||||||
|
type OtherSign = $sty;
|
||||||
fn bits() -> u32 {
|
fn bits() -> u32 {
|
||||||
$bits
|
$bits
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Int for $sty {
|
impl Int for $sty {
|
||||||
|
type OtherSign = $ity;
|
||||||
fn bits() -> u32 {
|
fn bits() -> u32 {
|
||||||
$bits
|
$bits
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use int::LargeInt;
|
||||||
use int::Int;
|
use int::Int;
|
||||||
|
|
||||||
macro_rules! mul {
|
macro_rules! mul {
|
||||||
($intrinsic:ident: $ty:ty, $tyh:ty) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns `a * b`
|
/// Returns `a * b`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||||
|
@ -13,15 +13,15 @@ macro_rules! mul {
|
||||||
low &= lower_mask;
|
low &= lower_mask;
|
||||||
t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask);
|
t += (a.low() >> half_bits).wrapping_mul(b.low() & lower_mask);
|
||||||
low += (t & lower_mask) << half_bits;
|
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;
|
t = low >> half_bits;
|
||||||
low &= lower_mask;
|
low &= lower_mask;
|
||||||
t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask);
|
t += (b.low() >> half_bits).wrapping_mul(a.low() & lower_mask);
|
||||||
low += (t & lower_mask) << half_bits;
|
low += (t & lower_mask) << half_bits;
|
||||||
high += (t >> half_bits) as $tyh;
|
high += (t >> half_bits) as hty!($ty);
|
||||||
high += (a.low() >> half_bits).wrapping_mul(b.low() >> half_bits) as $tyh;
|
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 $tyh))
|
high = high.wrapping_add(a.high().wrapping_mul(b.low() as hty!($ty)))
|
||||||
.wrapping_add((a.low() as $tyh).wrapping_mul(b.high()));
|
.wrapping_add((a.low() as hty!($ty)).wrapping_mul(b.high()));
|
||||||
<$ty>::from_parts(low, high)
|
<$ty>::from_parts(low, high)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,9 +73,9 @@ macro_rules! mulo {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
#[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!(__mulosi4: i32);
|
||||||
mulo!(__mulodi4: i64);
|
mulo!(__mulodi4: i64);
|
||||||
|
|
|
@ -114,9 +114,9 @@ pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 {
|
||||||
rem
|
rem
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `n / d` and sets `*rem = n % d`
|
macro_rules! udivmod_inner {
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
($n:expr, $d:expr, $rem:expr, $ty:ty) => {{
|
||||||
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
let (n, d, rem) = ($n, $d, $rem);
|
||||||
// NOTE X is unknown, K != 0
|
// NOTE X is unknown, K != 0
|
||||||
if n.high() == 0 {
|
if n.high() == 0 {
|
||||||
if d.high() == 0 {
|
if d.high() == 0 {
|
||||||
|
@ -125,9 +125,9 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
// 0 X
|
// 0 X
|
||||||
|
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
*rem = u64::from(urem!(n.low(), d.low()));
|
*rem = <$ty>::from(urem!(n.low(), d.low()));
|
||||||
}
|
}
|
||||||
return u64::from(udiv!(n.low(), d.low()));
|
return <$ty>::from(udiv!(n.low(), d.low()));
|
||||||
} else {
|
} else {
|
||||||
// 0 X
|
// 0 X
|
||||||
// ---
|
// ---
|
||||||
|
@ -160,9 +160,9 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
// ---
|
// ---
|
||||||
// K 0
|
// K 0
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
*rem = u64::from_parts(0, urem!(n.high(), d.high()));
|
*rem = <$ty>::from_parts(0, urem!(n.high(), d.high()));
|
||||||
}
|
}
|
||||||
return u64::from(udiv!(n.high(), d.high()));
|
return <$ty>::from(udiv!(n.high(), d.high()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// K K
|
// K K
|
||||||
|
@ -171,15 +171,15 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
|
|
||||||
if d.high().is_power_of_two() {
|
if d.high().is_power_of_two() {
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
*rem = u64::from_parts(n.low(), n.high() & (d.high() - 1));
|
*rem = <$ty>::from_parts(n.low(), n.high() & (d.high() - 1));
|
||||||
}
|
}
|
||||||
return u64::from(n.high() >> d.high().trailing_zeros());
|
return <$ty>::from(n.high() >> d.high().trailing_zeros());
|
||||||
}
|
}
|
||||||
|
|
||||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||||
|
|
||||||
// D > N
|
// D > N
|
||||||
if sr > u32::bits() - 2 {
|
if sr > <hty!($ty)>::bits() - 2 {
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
*rem = n;
|
*rem = n;
|
||||||
}
|
}
|
||||||
|
@ -188,8 +188,8 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
|
|
||||||
sr += 1;
|
sr += 1;
|
||||||
|
|
||||||
// 1 <= sr <= u32::bits() - 1
|
// 1 <= sr <= <hty!($ty)>::bits() - 1
|
||||||
q = n << (u64::bits() - sr);
|
q = n << (<$ty>::bits() - sr);
|
||||||
r = n >> sr;
|
r = n >> sr;
|
||||||
} else if d.high() == 0 {
|
} else if d.high() == 0 {
|
||||||
// K X
|
// K X
|
||||||
|
@ -197,7 +197,7 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
// 0 K
|
// 0 K
|
||||||
if d.low().is_power_of_two() {
|
if d.low().is_power_of_two() {
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
*rem = u64::from(n.low() & (d.low() - 1));
|
*rem = <$ty>::from(n.low() & (d.low() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.low() == 1 {
|
if d.low() == 1 {
|
||||||
|
@ -208,10 +208,10 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros();
|
sr = 1 + <hty!($ty)>::bits() + d.low().leading_zeros() - n.high().leading_zeros();
|
||||||
|
|
||||||
// 2 <= sr <= u64::bits() - 1
|
// 2 <= sr <= u64::bits() - 1
|
||||||
q = n << (u64::bits() - sr);
|
q = n << (<$ty>::bits() - sr);
|
||||||
r = n >> sr;
|
r = n >> sr;
|
||||||
} else {
|
} else {
|
||||||
// K X
|
// K X
|
||||||
|
@ -220,7 +220,7 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
|
||||||
|
|
||||||
// D > N
|
// D > N
|
||||||
if sr > u32::bits() - 1 {
|
if sr > <hty!($ty)>::bits() - 1 {
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
*rem = n;
|
*rem = n;
|
||||||
}
|
}
|
||||||
|
@ -229,8 +229,8 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
|
|
||||||
sr += 1;
|
sr += 1;
|
||||||
|
|
||||||
// 1 <= sr <= u32::bits()
|
// 1 <= sr <= <hty!($ty)>::bits()
|
||||||
q = n << (u64::bits() - sr);
|
q = n << (<$ty>::bits() - sr);
|
||||||
r = n >> sr;
|
r = n >> sr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,23 +243,30 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
|
||||||
|
|
||||||
for _ in 0..sr {
|
for _ in 0..sr {
|
||||||
// r:q = ((r:q) << 1) | carry
|
// r:q = ((r:q) << 1) | carry
|
||||||
r = (r << 1) | (q >> (u64::bits() - 1));
|
r = (r << 1) | (q >> (<$ty>::bits() - 1));
|
||||||
q = (q << 1) | carry as u64;
|
q = (q << 1) | carry as $ty;
|
||||||
|
|
||||||
// carry = 0
|
// carry = 0
|
||||||
// if r >= d {
|
// if r >= d {
|
||||||
// r -= d;
|
// r -= d;
|
||||||
// carry = 1;
|
// carry = 1;
|
||||||
// }
|
// }
|
||||||
let s = (d.wrapping_sub(r).wrapping_sub(1)) as i64 >> (u64::bits() - 1);
|
let s = (d.wrapping_sub(r).wrapping_sub(1)) as os_ty!($ty) >> (<$ty>::bits() - 1);
|
||||||
carry = (s & 1) as u32;
|
carry = (s & 1) as hty!($ty);
|
||||||
r -= d & s as u64;
|
r -= d & s as $ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rem) = rem {
|
if let Some(rem) = rem {
|
||||||
*rem = r;
|
*rem = r;
|
||||||
}
|
}
|
||||||
(q << 1) | carry as u64
|
(q << 1) | carry as $ty
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue