Ver Fonte

port __udivmodsi4, aeabi_uidivmod and udivsi3

also rewrite these last two new aeabi intrinsics as naked functions
Jorge Aparicio há 8 anos atrás
pai
commit
cc9d3e8e5f
3 ficheiros alterados com 100 adições e 11 exclusões
  1. 26 11
      src/arm.rs
  2. 61 0
      src/lib.rs
  3. 13 0
      src/test.rs

+ 26 - 11
src/arm.rs

@@ -1,18 +1,33 @@
-use core::mem;
+use core::intrinsics;
 
-#[repr(C)]
-pub struct u64x2 {
-    a: u64,
-    b: u64,
+// TODO use `global_asm!`
+#[naked]
+#[no_mangle]
+pub unsafe extern "aapcs" fn __aeabi_uidivmod() {
+    asm!("push    { lr }
+          sub     sp, sp, #4
+          mov     r2, sp
+          bl      __udivmodsi4
+          ldr     r1, [sp]
+          add     sp, sp, #4
+          pop     { pc }");
+    intrinsics::unreachable();
 }
 
+// TODO use `global_asm!`
+#[naked]
 #[no_mangle]
-pub unsafe extern "aapcs" fn __aeabi_uldivmod(num: u64, den: u64) -> u64x2 {
-
-    let mut rem = mem::uninitialized();
-    let quot = ::__udivmoddi4(num, den, &mut rem);
-
-    u64x2 { a: quot, b: rem }
+pub unsafe extern "aapcs" fn __aeabi_uldivmod() {
+    asm!("push	{r11, lr}
+          sub	sp, sp, #16
+          add	r12, sp, #8
+          str	r12, [sp]
+          bl	__udivmoddi4
+          ldr	r2, [sp, #8]
+          ldr	r3, [sp, #12]
+          add	sp, sp, #16
+          pop	{r11, pc}");
+    intrinsics::unreachable();
 }
 
 extern "C" {

+ 61 - 0
src/lib.rs

@@ -352,3 +352,64 @@ pub extern "C" fn __udivmoddi4(a: u64, b: u64, rem: *mut u64) -> u64 {
     }
     q.u64()
 }
+
+#[no_mangle]
+pub extern "C" fn __udivmodsi4(a: u32, b: u32, rem: *mut u32) -> u32 {
+    let d = __udivsi3(a, b);
+    if let Some(rem) = unsafe {rem.as_mut()} {
+        *rem = a - (d*b);
+    }
+    return d;
+}
+
+#[no_mangle]
+pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
+    let u32_bits = u32::bits() as u32;
+
+    // Special cases
+    if d == 0 {
+        return 0; // ?!
+    }
+
+    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 = 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 = (q << 1) | carry;
+    q
+}

+ 13 - 0
src/test.rs

@@ -42,3 +42,16 @@ quickcheck! {
         }
     }
 }
+
+quickcheck! {
+    fn udivmodsi4(a: u32, b: u32) -> TestResult {
+        if b == 0 {
+            TestResult::discard()
+        } else {
+            let mut r = 0;
+            let q = ::__udivmodsi4(a, b, &mut r);
+
+            TestResult::from_bool(q * b + r == a)
+        }
+    }
+}