port __udivmodsi4, aeabi_uidivmod and udivsi3

also rewrite these last two new aeabi intrinsics as naked functions
This commit is contained in:
Jorge Aparicio 2016-08-10 23:40:35 -05:00
parent 39ede7ee27
commit cc9d3e8e5f
3 changed files with 100 additions and 11 deletions

View File

@ -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" {

View File

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

View File

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