Bläddra i källkod

Macro-ify udivmod

est31 8 år sedan
förälder
incheckning
8fe50d813c
3 ändrade filer med 154 tillägg och 132 borttagningar
  1. 15 0
      src/int/mod.rs
  2. 8 8
      src/int/mul.rs
  3. 131 124
      src/int/udiv.rs

+ 15 - 0
src/int/mod.rs

@@ -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
             }

+ 8 - 8
src/int/mul.rs

@@ -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);

+ 131 - 124
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 = <$ty>::from(urem!(n.low(), d.low()));
+                }
+                return <$ty>::from(udiv!(n.low(), d.low()));
+            } else {
+                // 0 X
+                // ---
+                // K X
+                if let Some(rem) = rem {
+                    *rem = n;
+                }
+                return 0;
+            };
+        }
 
-            if let Some(rem) = rem {
-                *rem = u64::from(urem!(n.low(), d.low()));
+        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()
+                }
             }
-            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 = <$ty>::from_parts(0, urem!(n.high(), d.high()));
+                }
+                return <$ty>::from(udiv!(n.high(), d.high()));
             }
-        }
 
-        if n.low() == 0 {
-            // K 0
+            // K K
             // ---
             // K 0
-            if let Some(rem) = rem {
-                *rem = u64::from_parts(0, urem!(n.high(), d.high()));
+
+            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());
             }
-            return u64::from(udiv!(n.high(), d.high()));
-        }
 
-        // K K
-        // ---
-        // K 0
+            sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
 
-        if d.high().is_power_of_two() {
-            if let Some(rem) = rem {
-                *rem = u64::from_parts(n.low(), n.high() & (d.high() - 1));
+            // D > N
+            if sr > <hty!($ty)>::bits() - 2 {
+                if let Some(rem) = rem {
+                    *rem = n;
+                }
+                return 0;
             }
-            return u64::from(n.high() >> d.high().trailing_zeros());
-        }
 
-        sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
+            sr += 1;
 
-        // D > N
-        if sr > u32::bits() - 2 {
-            if let Some(rem) = rem {
-                *rem = n;
+            // 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;
+                };
             }
-            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));
-            }
+            sr = 1 + <hty!($ty)>::bits() + d.low().leading_zeros() - n.high().leading_zeros();
 
-            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;
+            // 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;
             }
-            return 0;
-        }
 
-        sr += 1;
+            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;
+            // 1 <= sr <= <hty!($ty)>::bits()
+            q = n << (<$ty>::bits() - sr);
+            r = n >> sr;
+        }
 
-    for _ in 0..sr {
-        // r:q = ((r:q) << 1) | carry
-        r = (r << 1) | (q >> (u64::bits() - 1));
-        q = (q << 1) | carry as u64;
+        // 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 >> (<$ty>::bits() - 1));
+            q = (q << 1) | carry as $ty;
+
+            // 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;
+        }
 
-        // 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 $ty
+    }}
+}
 
-    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)]