From cc9d3e8e5ff74ef2379239a7229f1991f4084495 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 10 Aug 2016 23:40:35 -0500 Subject: [PATCH] port __udivmodsi4, aeabi_uidivmod and udivsi3 also rewrite these last two new aeabi intrinsics as naked functions --- src/arm.rs | 37 ++++++++++++++++++++++---------- src/lib.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/test.rs | 13 ++++++++++++ 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/src/arm.rs b/src/arm.rs index 55e9bb9..bcfc6c8 100644 --- a/src/arm.rs +++ b/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" { diff --git a/src/lib.rs b/src/lib.rs index e5caa83..2c016a7 100644 --- a/src/lib.rs +++ b/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 +} diff --git a/src/test.rs b/src/test.rs index 8d5a42c..40e2885 100644 --- a/src/test.rs +++ b/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) + } + } +}