123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- use core::{intrinsics, mem};
- use int::{Int, LargeInt};
- /// Returns `n / d`
- #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
- #[cfg_attr(not(test), no_mangle)]
- pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
- // Special cases
- if d == 0 {
- // NOTE This should be unreachable in safe Rust because the program will panic before
- // this intrinsic is called
- unsafe {
- intrinsics::abort()
- }
- }
- if n == 0 {
- return 0;
- }
- let mut sr = d.leading_zeros().wrapping_sub(n.leading_zeros());
- // d > n
- if sr > u32::bits() - 1 {
- return 0;
- }
- // d == 1
- if sr == u32::bits() - 1 {
- return n;
- }
- sr += 1;
- // 1 <= sr <= u32::bits() - 1
- let mut q = n << (u32::bits() - sr);
- let mut r = n >> sr;
- let mut carry = 0;
- for _ in 0..sr {
- // r:q = ((r:q) << 1) | carry
- r = (r << 1) | (q >> (u32::bits() - 1));
- q = (q << 1) | carry;
- // carry = 0;
- // if r > d {
- // r -= d;
- // carry = 1;
- // }
- let s = (d.wrapping_sub(r).wrapping_sub(1)) as i32 >> (u32::bits() - 1);
- carry = (s & 1) as u32;
- r -= d & s as u32;
- }
- (q << 1) | carry
- }
- /// Returns `n % d`
- #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))]
- #[cfg_attr(not(test), no_mangle)]
- pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 {
- #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))]
- extern "C" {
- fn __udivsi3(n: u32, d: u32) -> u32;
- }
- n - unsafe { __udivsi3(n, d) * d }
- }
- /// Returns `n / d` and sets `*rem = n % d`
- #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
- #[cfg_attr(not(test), no_mangle)]
- pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
- #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))]
- extern "C" {
- fn __udivsi3(n: u32, d: u32) -> u32;
- }
- let q = unsafe { __udivsi3(n, d) };
- if let Some(rem) = rem {
- *rem = n - (q * d);
- }
- q
- }
- /// Returns `n / d`
- #[cfg_attr(not(test), no_mangle)]
- #[cfg(not(all(feature = "c", target_arch = "x86")))]
- pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 {
- __udivmoddi4(n, d, None)
- }
- /// Returns `n % d`
- #[cfg(not(all(feature = "c", target_arch = "x86")))]
- #[cfg_attr(not(test), no_mangle)]
- pub extern "C" fn __umoddi3(a: u64, b: u64) -> u64 {
- let mut rem = unsafe { mem::uninitialized() };
- __udivmoddi4(a, b, Some(&mut rem));
- 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
- 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;
- } else {
- let sr = d.low().trailing_zeros();
- return n >> sr;
- };
- }
- sr = 1 + u32::bits() + d.low().leading_zeros() - n.high().leading_zeros();
- // 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;
- }
- return 0;
- }
- sr += 1;
- // 1 <= sr <= u32::bits()
- q = n << (u64::bits() - sr);
- r = n >> sr;
- }
- }
- // 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;
- for _ in 0..sr {
- // r:q = ((r:q) << 1) | carry
- r = (r << 1) | (q >> (u64::bits() - 1));
- q = (q << 1) | carry as u64;
- // 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
- }
- #[cfg(test)]
- mod tests {
- use qc::{U32, U64};
- check! {
- fn __udivdi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
- let (n, d) = (n.0, d.0);
- if d == 0 {
- None
- } else {
- Some(f(n, d))
- }
- }
- fn __umoddi3(f: extern fn(u64, u64) -> u64, n: U64, d: U64) -> Option<u64> {
- let (n, d) = (n.0, d.0);
- if d == 0 {
- None
- } else {
- Some(f(n, d))
- }
- }
- fn __udivmoddi4(f: extern fn(u64, u64, Option<&mut u64>) -> u64,
- n: U64,
- d: U64) -> Option<(u64, u64)> {
- let (n, d) = (n.0, d.0);
- if d == 0 {
- None
- } else {
- let mut r = 0;
- let q = f(n, d, Some(&mut r));
- Some((q, r))
- }
- }
- fn __udivsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
- let (n, d) = (n.0, d.0);
- if d == 0 {
- None
- } else {
- Some(f(n, d))
- }
- }
- fn __umodsi3(f: extern fn(u32, u32) -> u32, n: U32, d: U32) -> Option<u32> {
- let (n, d) = (n.0, d.0);
- if d == 0 {
- None
- } else {
- Some(f(n, d))
- }
- }
- fn __udivmodsi4(f: extern fn(u32, u32, Option<&mut u32>) -> u32,
- n: U32,
- d: U32) -> Option<(u32, u32)> {
- let (n, d) = (n.0, d.0);
- if d == 0 {
- None
- } else {
- let mut r = 0;
- let q = f(n, d, Some(&mut r));
- Some((q, r))
- }
- }
- }
- }
|