Jelajahi Sumber

Port udiv to the `intrinsics!` macro

Alex Crichton 7 tahun lalu
induk
melakukan
d17042106f
1 mengubah file dengan 112 tambahan dan 156 penghapusan
  1. 112 156
      src/int/udiv.rs

+ 112 - 156
src/int/udiv.rs

@@ -1,140 +1,6 @@
 use core::intrinsics;
-use int::{Int, LargeInt};
-
-/// Returns `n / d`
-#[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
-#[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)]
-#[cfg_attr(all(not(test), target_arch = "arm"), inline(always))]
-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;
-    }
-
-    let q = match () {
-        #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios")))]
-        () => unsafe { __udivsi3(n, d) },
-        #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"))))]
-        () => __udivsi3(n, d),
-    };
-
-    n - q * 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"), not(thumbv6m)))]
-    extern "C" {
-        fn __udivsi3(n: u32, d: u32) -> u32;
-    }
-
-    let q = match () {
-        #[cfg(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m)))]
-        () => unsafe { __udivsi3(n, d) },
-        #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))]
-        () => __udivsi3(n, d),
-    };
-    if let Some(rem) = rem {
-        *rem = n - (q * d);
-    }
-    q
-}
-
-macro_rules! div_mod_intrinsics {
-    ($udiv_intr:ident, $umod_intr:ident : $ty:ty) => {
-        div_mod_intrinsics!($udiv_intr, $umod_intr : $ty,
-                            __udivmoddi4);
-    };
-    ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr) => {
-        div_mod_intrinsics!($udiv_intr, $umod_intr : $ty,
-                            $divmod_intr, $ty, |i|{ i });
-    };
-    ($udiv_intr:ident, $umod_intr:ident : $ty:ty, $divmod_intr:expr,
-     $tyret:ty, $conv:expr) => {
-        /// Returns `n / d`
-        #[cfg_attr(not(test), no_mangle)]
-        pub extern "C" fn $udiv_intr(n: $ty, d: $ty) -> $tyret {
-            let r = $divmod_intr(n, d, None);
-            ($conv)(r)
-        }
-
-        /// Returns `n % d`
-        #[cfg_attr(not(test), no_mangle)]
-        pub extern "C" fn $umod_intr(a: $ty, b: $ty) -> $tyret {
-            use core::mem;
-
-            let mut rem = unsafe { mem::uninitialized() };
-            $divmod_intr(a, b, Some(&mut rem));
-            ($conv)(rem)
-        }
-    }
-}
-
-#[cfg(not(all(feature = "c", target_arch = "x86")))]
-div_mod_intrinsics!(__udivdi3, __umoddi3: u64);
-
-#[cfg(not(all(windows, target_pointer_width="64")))]
-div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod);
-
-#[cfg(all(windows, target_pointer_width="64"))]
-div_mod_intrinsics!(__udivti3, __umodti3: u128, u128_div_mod, ::U64x2, ::conv);
+use int::{Int, LargeInt};
 
 macro_rules! udivmod_inner {
     ($n:expr, $d:expr, $rem:expr, $ty:ty) => {{
@@ -285,30 +151,120 @@ macro_rules! udivmod_inner {
     }}
 }
 
-/// 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)
-}
+intrinsics! {
+    #[use_c_shim_if(all(target_arch = "arm",
+                        not(target_os = "ios"),
+                        not(thumbv6m)))]
+    /// Returns `n / d`
+    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;
+            // }
 
-macro_rules! udivmodti4 {
-    ($tyret:ty, $conv:expr) => {
-        /// Returns `n / d` and sets `*rem = n % d`
-        #[cfg_attr(not(test), no_mangle)]
-        pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> $tyret {
-            let r = u128_div_mod(n, d, rem);
-            ($conv)(r)
+            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` and sets `*rem = n % d`
-fn u128_div_mod(n: u128, d: u128, rem: Option<&mut u128>) -> u128 {
-    udivmod_inner!(n, d, rem, u128)
-}
+    #[use_c_shim_if(all(target_arch = "arm", not(target_os = "ios")))]
+    /// Returns `n % d`
+    pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 {
+        let q = __udivsi3(n, d);
+        n - q * d
+    }
+
+    #[use_c_shim_if(all(target_arch = "arm",
+                        not(target_os = "ios"),
+                        not(thumbv6m)))]
+    /// Returns `n / d` and sets `*rem = n % d`
+    pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
+        let q = __udivsi3(n, d);
+        if let Some(rem) = rem {
+            *rem = n - (q * d);
+        }
+        q
+    }
 
-#[cfg(all(windows, target_pointer_width="64"))]
-udivmodti4!(::U64x2, ::conv);
+    #[use_c_shim_if(target_arch = "x86")]
+    /// Returns `n / d`
+    pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 {
+        __udivmoddi4(n, d, None)
+    }
 
-#[cfg(not(all(windows, target_pointer_width="64")))]
-udivmodti4!(u128, |i|{ i });
+    #[use_c_shim_if(target_arch = "x86")]
+    /// Returns `n % d`
+    pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 {
+        let mut rem = 0;
+        __udivmoddi4(n, d, Some(&mut rem));
+        rem
+    }
+
+    #[win64_128bit_abi_hack]
+    /// Returns `n / d`
+    pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 {
+        __udivmodti4(n, d, None)
+    }
+
+    #[win64_128bit_abi_hack]
+    /// Returns `n % d`
+    pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 {
+        let mut rem = 0;
+        __udivmodti4(n, d, Some(&mut rem));
+        rem
+    }
+
+    /// Returns `n / d` and sets `*rem = n % d`
+    pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
+        udivmod_inner!(n, d, rem, u64)
+    }
+
+    #[win64_128bit_abi_hack]
+    /// Returns `n / d` and sets `*rem = n % d`
+    pub extern "C" fn __udivmodti4(n: u128,
+                                   d: u128,
+                                   rem: Option<&mut u128>) -> u128 {
+        udivmod_inner!(n, d, rem, u128)
+    }
+}