ソースを参照

refactor: use Int traits, words -> U64, fmt

Jorge Aparicio 8 年 前
コミット
a84579d3c1
1 ファイル変更109 行追加111 行削除
  1. 109 111
      src/lib.rs

+ 109 - 111
src/lib.rs

@@ -18,8 +18,6 @@ pub mod arm;
 #[cfg(test)]
 mod test;
 
-use core::mem;
-
 /// Trait for some basic operations on integers
 trait Int {
     fn bits() -> usize;
@@ -27,16 +25,24 @@ trait Int {
 
 // TODO: Once i128/u128 support lands, we'll want to add impls for those as well
 impl Int for u32 {
-    fn bits() -> usize { 32 }
+    fn bits() -> usize {
+        32
+    }
 }
 impl Int for i32 {
-    fn bits() -> usize { 32 }
+    fn bits() -> usize {
+        32
+    }
 }
 impl Int for u64 {
-    fn bits() -> usize { 64 }
+    fn bits() -> usize {
+        64
+    }
 }
 impl Int for i64 {
-    fn bits() -> usize { 64 }
+    fn bits() -> usize {
+        64
+    }
 }
 
 /// Trait to convert an integer to/from smaller parts
@@ -99,131 +105,124 @@ absv_i2!(__absvdi2: i64);
 // TODO(rust-lang/35118)?
 // absv_i2!(__absvti2, i128);
 
+/// Return `n / d` and `*rem = n % d`
 #[no_mangle]
-pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 {
+pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
+    use core::ops::{Index, IndexMut, RangeFull};
+
     #[cfg(target_endian = "little")]
     #[repr(C)]
-    #[derive(Debug)]
-    struct words {
+    struct U64 {
         low: u32,
         high: u32,
     }
 
     #[cfg(target_endian = "big")]
     #[repr(C)]
-    #[derive(Debug)]
-    struct words {
+    struct U64 {
         high: u32,
         low: u32,
     }
 
-    impl words {
-        fn all(&mut self) -> &mut u64 {
-            unsafe { mem::transmute(self) }
-        }
+    impl Index<RangeFull> for U64 {
+        type Output = u64;
 
-        fn u64(&self) -> u64 {
-            unsafe { *(self as *const _ as *const u64) }
+        fn index(&self, _: RangeFull) -> &u64 {
+            unsafe { &*(self as *const _ as *const u64) }
         }
     }
 
-    impl From<u64> for words {
-        fn from(x: u64) -> words {
-            unsafe { mem::transmute(x) }
+    impl IndexMut<RangeFull> for U64 {
+        fn index_mut(&mut self, _: RangeFull) -> &mut u64 {
+            unsafe { &mut *(self as *const _ as *mut u64) }
         }
     }
 
     let u32_bits = u32::bits() as u32;
     let u64_bits = u64::bits() as u32;
 
-    let n = words::from(a);
-    let d = words::from(b);
-
     // NOTE X is unknown, K != 0
-    if n.high == 0 {
-        if d.high == 0 {
+    if n.high() == 0 {
+        if d.high() == 0 {
             // 0 X
             // ---
             // 0 X
 
             if let Some(rem) = rem {
-                *rem = u64::from(n.low % d.low);
+                *rem = u64::from(n.low() % d.low());
             }
-            return u64::from(n.low / d.low);
+            return u64::from(n.low() / d.low());
         } else
-               // d.high != 0
-               {
+        // d.high() != 0
+        {
             // 0 X
             // ---
             // K X
 
             if let Some(rem) = rem {
-                *rem = u64::from(n.low);
+                *rem = u64::from(n.low());
             }
             return 0;
         };
     }
 
     let mut sr;
-    // NOTE IMO it should be possible to leave these "uninitialized" (just declare them here)
-    // because these variables get initialized below, but if I do that the compiler complains about
-    // them being used before being initialized.
-    let mut q = words { low: 0, high: 0 };
-    let mut r = words { low: 0, high: 0 };
-
-    // n.high != 0
-    if d.low == 0 {
-        if d.high == 0 {
+    let mut q = U64 { low: 0, high: 0 };
+    let mut r = U64 { low: 0, high: 0 };
+
+    // n.high() != 0
+    if d.low() == 0 {
+        if d.high() == 0 {
             // K X
             // ---
             // 0 0
 
-            // NOTE copied verbatim from compiler-rt, but does division by zero even make sense?
+            // NOTE copied verbatim from compiler-rt. This probably lets the intrinsic decide how to
+            // handle the division by zero (SIGFPE, 0, etc.). But this part shouldn't be reachable
+            // from safe code.
             if let Some(rem) = rem {
-                *rem = u64::from(n.high % d.low);
+                *rem = u64::from(n.high() % d.low());
             }
-            return u64::from(n.high / d.low);
+            return u64::from(n.high() / d.low());
         }
 
-        // d.high != 0
-        if n.low == 0 {
+        // d.high() != 0
+        if n.low() == 0 {
             // K 0
             // ---
             // K 0
 
             if let Some(rem) = rem {
-                *rem = words {
-                        low: 0,
-                        high: n.high % d.high,
-                    }
-                    .u64();
+                *rem = U64 {
+                    low: 0,
+                    high: n.high() % d.high(),
+                }[..];
             }
-            return u64::from(n.high / d.high);
+            return u64::from(n.high() / d.high());
         }
 
-        // n.low != 0
+        // n.low() != 0
         // K K
         // ---
         // K 0
 
-        if d.high.is_power_of_two() {
+        if d.high().is_power_of_two() {
             if let Some(rem) = rem {
-                *rem = words {
-                        low: n.low,
-                        high: n.high & (d.high - 1),
-                    }
-                    .u64()
+                *rem = U64 {
+                    low: n.low(),
+                    high: n.high() & (d.high() - 1),
+                }[..];
             }
 
-            return u64::from(n.high >> d.high.trailing_zeros());
+            return u64::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
         if sr > u32_bits - 2 {
             if let Some(rem) = rem {
-                *rem = n.u64();
+                *rem = n;
             }
             return 0;
         }
@@ -231,75 +230,74 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 {
         sr = sr + 1;
 
         // 1 <= sr <= u32_bits - 1
-        // *q.all() = n.u64() << (u64_bits - sr);
+        // q = n << (u64_bits - sr);
         q.low = 0;
-        q.high = n.low << (u32_bits - sr);
-        // *r.all() = n.u64() >> sr
-        r.high = n.high >> sr;
-        r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
+        q.high = n.low() << (u32_bits - sr);
+        // r = n >> sr
+        r.high = n.high() >> sr;
+        r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
     } else
-    // d.low != 0
+    // d.low() != 0
     {
-        if d.high == 0 {
+        if d.high() == 0 {
             // K X
             // ---
             // 0 K
-            if d.low.is_power_of_two() {
+            if d.low().is_power_of_two() {
                 if let Some(rem) = rem {
-                    *rem = u64::from(n.low & (d.low - 1));
+                    *rem = u64::from(n.low() & (d.low() - 1));
                 }
 
-                return if d.low == 1 {
-                    n.u64()
+                if d.low() == 1 {
+                    return n;
                 } else {
-                    let sr = d.low.trailing_zeros();
-                    words {
-                            low: (n.high << (u32_bits - sr)) | (n.low >> sr),
-                            high: n.high >> sr,
-                        }
-                        .u64()
+                    let sr = d.low().trailing_zeros();
+                    return U64 {
+                        low: (n.high() << (u32_bits - sr)) | (n.low() >> sr),
+                        high: n.high() >> sr,
+                    }[..];
                 };
             }
 
-            sr = 1 + u32_bits + d.low.leading_zeros() - n.high.leading_zeros();
+            sr = 1 + u32_bits + d.low().leading_zeros() - n.high().leading_zeros();
 
             // 2 <= sr <= u64_bits - 1
-            // *q.all() = n.u64() << (u64_bits - sr)
-            // *r.all() = n.u64() >> sr;
+            // q = n << (u64_bits - sr)
+            // r = n >> sr;
             if sr == u32_bits {
                 q.low = 0;
-                q.high = n.low;
+                q.high = n.low();
                 r.high = 0;
-                r.low = n.high;
+                r.low = n.high();
             } else if sr < u32_bits
             // 2 <= sr <= u32_bits - 1
             {
                 q.low = 0;
-                q.high = n.low << (u32_bits - sr);
-                r.high = n.high >> sr;
-                r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
+                q.high = n.low() << (u32_bits - sr);
+                r.high = n.high() >> sr;
+                r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
             } else
             // u32_bits + 1 <= sr <= u64_bits - 1
             {
-                q.low = n.low << (u64_bits - sr);
-                q.high = (n.high << (u64_bits - sr)) | (n.low >> (sr - u32_bits));
+                q.low = n.low() << (u64_bits - sr);
+                q.high = (n.high() << (u64_bits - sr)) | (n.low() >> (sr - u32_bits));
                 r.high = 0;
-                r.low = n.high >> (sr - u32_bits);
+                r.low = n.high() >> (sr - u32_bits);
             }
 
         } else
-        // d.high != 0
+        // d.high() != 0
         {
             // K X
             // ---
             // K K
 
-            sr = d.high.leading_zeros().wrapping_sub(n.high.leading_zeros());
+            sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
 
             // D > N
             if sr > u32_bits - 1 {
                 if let Some(rem) = rem {
-                    *rem = a;
+                    *rem = n;
                     return 0;
                 }
             }
@@ -307,61 +305,61 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: Option<&mut u64>) -> u64 {
             sr += 1;
 
             // 1 <= sr <= u32_bits
-            // *q.all() = n.u64() << (u64_bits - sr)
+            // q = n << (u64_bits - sr)
             q.low = 0;
             if sr == u32_bits {
-                q.high = n.low;
+                q.high = n.low();
                 r.high = 0;
-                r.low = n.high;
+                r.low = n.high();
             } else {
-                q.high = n.low << (u32_bits - sr);
-                r.high = n.high >> sr;
-                r.low = (n.high << (u32_bits - sr)) | (n.low >> sr);
+                q.high = n.low() << (u32_bits - sr);
+                r.high = n.high() >> sr;
+                r.low = (n.high() << (u32_bits - sr)) | (n.low() >> sr);
             }
         }
     }
 
     // Not a special case
     // q and r are initialized with
-    // *q.all() = n.u64() << (u64_bits - sr)
-    // *.r.all() = n.u64() >> sr
+    // 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.high = (r.high << 1) | (r.low >> (u32_bits - 1));
-        r.low = (r.low << 1) | (q.high >> (u32_bits - 1));
-        q.high = (q.high << 1) | (q.low >> (u32_bits - 1));
-        q.low = (q.low << 1) | carry;
+        r[..] = (r[..] << 1) | (q[..] >> 63);
+        q[..] = (q[..] << 1) | carry as u64;
 
         // carry = 0
-        // if r.u64() >= d.u64() {
-        //     *r.all() -= d.u64();
+        // if r >= d {
+        //     r -= d;
         //     carry = 1;
         // }
 
-        let s = (d.u64().wrapping_sub(r.u64()).wrapping_sub(1)) as i64 >> (u64_bits - 1);
+        let s = (d.wrapping_sub(r[..]).wrapping_sub(1)) as i64 >> (u64_bits - 1);
         carry = (s & 1) as u32;
-        *r.all() -= d.u64() & s as u64;
+        r[..] -= d & s as u64;
     }
 
-    *q.all() = (q.u64() << 1) | carry as u64;
+    q[..] = (q[..] << 1) | carry as u64;
     if let Some(rem) = rem {
-        *rem = r.u64();
+        *rem = r[..];
     }
-    q.u64()
+    q[..]
 }
 
+/// Return `n / d` and `*rem = n % d`
 #[no_mangle]
 pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: Option<&mut u32>) -> u32 {
     let d = __udivsi3(a, b);
     if let Some(rem) = rem {
-        *rem = a - (d*b);
+        *rem = a - (d * b);
     }
     return d;
 }
 
+/// Return `n / d`
 #[no_mangle]
 pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
     let u32_bits = u32::bits() as u32;