commit
8603e64554
24
README.md
24
README.md
|
@ -40,9 +40,9 @@ See [rust-lang/rust#35437][0].
|
|||
- [x] arm/aeabi_uidivmod.S
|
||||
- [x] arm/aeabi_uldivmod.S
|
||||
- [ ] arm/divdf3vfp.S
|
||||
- [ ] arm/divmodsi4.S
|
||||
- [ ] arm/divmodsi4.S (generic version is done)
|
||||
- [ ] arm/divsf3vfp.S
|
||||
- [ ] arm/divsi3.S
|
||||
- [ ] arm/divsi3.S (generic version is done)
|
||||
- [ ] arm/eqdf2vfp.S
|
||||
- [ ] arm/eqsf2vfp.S
|
||||
- [ ] arm/extendsfdf2vfp.S
|
||||
|
@ -62,7 +62,7 @@ See [rust-lang/rust#35437][0].
|
|||
- [ ] arm/lesf2vfp.S
|
||||
- [ ] arm/ltdf2vfp.S
|
||||
- [ ] arm/ltsf2vfp.S
|
||||
- [ ] arm/modsi3.S
|
||||
- [ ] arm/modsi3.S (generic version is done)
|
||||
- [ ] arm/muldf3vfp.S
|
||||
- [ ] arm/mulsf3vfp.S
|
||||
- [ ] arm/nedf2vfp.S
|
||||
|
@ -73,17 +73,19 @@ See [rust-lang/rust#35437][0].
|
|||
- [ ] arm/subdf3vfp.S
|
||||
- [ ] arm/subsf3vfp.S
|
||||
- [ ] arm/truncdfsf2vfp.S
|
||||
- [ ] arm/udivmodsi4.S
|
||||
- [ ] arm/udivsi3.S
|
||||
- [ ] arm/umodsi3.S
|
||||
- [ ] arm/udivmodsi4.S (generic version is done)
|
||||
- [ ] arm/udivsi3.S (generic version is done)
|
||||
- [ ] arm/umodsi3.S (generic version is done)
|
||||
- [ ] arm/unorddf2vfp.S
|
||||
- [ ] arm/unordsf2vfp.S
|
||||
- [x] ashldi3.c
|
||||
- [x] ashrdi3.c
|
||||
- [ ] divdf3.c
|
||||
- [ ] divdi3.c
|
||||
- [x] divdi3.c
|
||||
- [x] divmoddi4.c
|
||||
- [x] divmodsi4.c
|
||||
- [ ] divsf3.c
|
||||
- [ ] divsi3.c
|
||||
- [x] divsi3.c
|
||||
- [ ] extendhfsf2.c
|
||||
- [ ] extendsfdf2.c
|
||||
- [ ] fixdfdi.c
|
||||
|
@ -113,8 +115,8 @@ See [rust-lang/rust#35437][0].
|
|||
- [ ] i386/udivdi3.S
|
||||
- [ ] i386/umoddi3.S
|
||||
- [x] lshrdi3.c
|
||||
- [ ] moddi3.c
|
||||
- [ ] modsi3.c
|
||||
- [x] moddi3.c
|
||||
- [x] modsi3.c
|
||||
- [ ] muldf3.c
|
||||
- [x] muldi3.c
|
||||
- [x] mulodi4.c
|
||||
|
@ -251,8 +253,6 @@ These builtins are never called by LLVM.
|
|||
- ~~ctzdi2.c~~
|
||||
- ~~ctzsi2.c~~
|
||||
- ~~ctzti2.c~~
|
||||
- ~~divmoddi4.c~~
|
||||
- ~~divmodsi4.c~~
|
||||
- ~~ffsdi2.c~~
|
||||
- ~~ffsti2.c~~
|
||||
- ~~mulvdi3.c~~
|
||||
|
|
121
src/arm.rs
121
src/arm.rs
|
@ -1,6 +1,6 @@
|
|||
use core::intrinsics;
|
||||
|
||||
// NOTE This function and the one below are implemented using assembly because they using a custom
|
||||
// NOTE This function and the ones below are implemented using assembly because they using a custom
|
||||
// calling convention which can't be implemented using a normal Rust function
|
||||
#[naked]
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
|
@ -30,6 +30,44 @@ pub unsafe fn __aeabi_uldivmod() {
|
|||
intrinsics::unreachable();
|
||||
}
|
||||
|
||||
#[naked]
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub unsafe fn __aeabi_idivmod() {
|
||||
asm!("push {r0, r1, r4, lr}
|
||||
bl __divsi3
|
||||
pop {r1, r2}
|
||||
muls r2, r2, r0
|
||||
subs r1, r1, r2
|
||||
pop {r4, pc}");
|
||||
intrinsics::unreachable();
|
||||
}
|
||||
|
||||
#[naked]
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub unsafe fn __aeabi_ldivmod() {
|
||||
asm!("push {r4, lr}
|
||||
sub sp, sp, #16
|
||||
add r4, sp, #8
|
||||
str r4, [sp]
|
||||
bl __divmoddi4
|
||||
ldr r2, [sp, #8]
|
||||
ldr r3, [sp, #12]
|
||||
add sp, sp, #16
|
||||
pop {r4, pc}");
|
||||
intrinsics::unreachable();
|
||||
}
|
||||
|
||||
// TODO: These two functions should be defined as aliases
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
|
||||
::udiv::__udivsi3(a, b)
|
||||
}
|
||||
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
|
||||
::sdiv::__divsi3(a, b)
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
||||
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
||||
|
@ -90,3 +128,84 @@ pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
|
|||
pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
|
||||
memset(dest, 0, n);
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use quickcheck::TestResult;
|
||||
use qc::{U32, U64};
|
||||
|
||||
quickcheck!{
|
||||
fn uldivmod(n: U64, d: U64) -> TestResult {
|
||||
let (n, d) = (n.0, d.0);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let q: u64;
|
||||
let r: u64;
|
||||
unsafe {
|
||||
// The inline asm is a bit tricky here, LLVM will allocate
|
||||
// both r0 and r1 when we specify a 64-bit value for {r0}.
|
||||
asm!("bl __aeabi_uldivmod"
|
||||
: "={r0}" (q), "={r2}" (r)
|
||||
: "{r0}" (n), "{r2}" (d)
|
||||
: "r12", "lr", "flags");
|
||||
}
|
||||
TestResult::from_bool(q == n / d && r == n % d)
|
||||
}
|
||||
}
|
||||
|
||||
fn uidivmod(n: U32, d: U32) -> TestResult {
|
||||
let (n, d) = (n.0, d.0);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let q: u32;
|
||||
let r: u32;
|
||||
unsafe {
|
||||
asm!("bl __aeabi_uidivmod"
|
||||
: "={r0}" (q), "={r1}" (r)
|
||||
: "{r0}" (n), "{r1}" (d)
|
||||
: "r2", "r3", "r12", "lr", "flags");
|
||||
}
|
||||
TestResult::from_bool(q == n / d && r == n % d)
|
||||
}
|
||||
}
|
||||
|
||||
fn ldivmod(n: U64, d: U64) -> TestResult {
|
||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let q: i64;
|
||||
let r: i64;
|
||||
unsafe {
|
||||
// The inline asm is a bit tricky here, LLVM will allocate
|
||||
// both r0 and r1 when we specify a 64-bit value for {r0}.
|
||||
asm!("bl __aeabi_ldivmod"
|
||||
: "={r0}" (q), "={r2}" (r)
|
||||
: "{r0}" (n), "{r2}" (d)
|
||||
: "r12", "lr", "flags");
|
||||
}
|
||||
TestResult::from_bool(q == n / d && r == n % d)
|
||||
}
|
||||
}
|
||||
|
||||
fn idivmod(n: U32, d: U32) -> TestResult {
|
||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let q: i32;
|
||||
let r: i32;
|
||||
unsafe {
|
||||
asm!("bl __aeabi_idivmod"
|
||||
: "={r0}" (q), "={r1}" (r)
|
||||
: "{r0}" (n), "{r1}" (d)
|
||||
: "r2", "r3", "r12", "lr", "flags");
|
||||
}
|
||||
TestResult::from_bool(q == n / d && r == n % d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ pub mod arm;
|
|||
pub mod x86_64;
|
||||
|
||||
pub mod udiv;
|
||||
pub mod sdiv;
|
||||
pub mod mul;
|
||||
pub mod shift;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ macro_rules! mul {
|
|||
($intrinsic:ident: $ty:ty) => {
|
||||
/// Returns `a * b`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||
let half_bits = <$ty>::bits() / 4;
|
||||
let lower_mask = !0 >> half_bits;
|
||||
let mut low = (a.low() & lower_mask) * (b.low() & lower_mask);
|
||||
|
@ -29,7 +29,7 @@ macro_rules! mulo {
|
|||
($intrinsic:ident: $ty:ty) => {
|
||||
/// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty {
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty, overflow: &mut i32) -> $ty {
|
||||
*overflow = 0;
|
||||
let result = a.wrapping_mul(b);
|
||||
if a == <$ty>::min_value() {
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
use Int;
|
||||
|
||||
macro_rules! div {
|
||||
($intrinsic:ident: $ty:ty, $uty:ty) => {
|
||||
/// Returns `a / b`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||
let s_a = a >> (<$ty>::bits() - 1);
|
||||
let s_b = b >> (<$ty>::bits() - 1);
|
||||
let a = (a ^ s_a) - s_a;
|
||||
let b = (b ^ s_b) - s_b;
|
||||
let s = s_a ^ s_b;
|
||||
let r = (a as $uty) / (b as $uty);
|
||||
(r as $ty ^ s) - s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mod_ {
|
||||
($intrinsic:ident: $ty:ty, $uty:ty) => {
|
||||
/// Returns `a % b`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty) -> $ty {
|
||||
let s = b >> (<$ty>::bits() - 1);
|
||||
let b = (b ^ s) - s;
|
||||
let s = a >> (<$ty>::bits() - 1);
|
||||
let a = (a ^ s) - s;
|
||||
let r = (a as $uty) % (b as $uty);
|
||||
(r as $ty ^ s) - s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! divmod {
|
||||
($intrinsic:ident, $div:ident: $ty:ty) => {
|
||||
/// Returns `a / b` and sets `*rem = n % d`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: $ty, rem: &mut $ty) -> $ty {
|
||||
let r = $div(a, b);
|
||||
*rem = a - (r * b);
|
||||
r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div!(__divsi3: i32, u32);
|
||||
div!(__divdi3: i64, u64);
|
||||
mod_!(__modsi3: i32, u32);
|
||||
mod_!(__moddi3: i64, u64);
|
||||
divmod!(__divmodsi4, __divsi3: i32);
|
||||
divmod!(__divmoddi4, __divdi3: i64);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use quickcheck::TestResult;
|
||||
use qc::{U32, U64};
|
||||
|
||||
quickcheck!{
|
||||
fn divdi3(n: U64, d: U64) -> TestResult {
|
||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let q = super::__divdi3(n, d);
|
||||
TestResult::from_bool(q == n / d)
|
||||
}
|
||||
}
|
||||
|
||||
fn moddi3(n: U64, d: U64) -> TestResult {
|
||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let r = super::__moddi3(n, d);
|
||||
TestResult::from_bool(r == n % d)
|
||||
}
|
||||
}
|
||||
|
||||
fn divmoddi4(n: U64, d: U64) -> TestResult {
|
||||
let (n, d) = (n.0 as i64, d.0 as i64);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let mut r = 0;
|
||||
let q = super::__divmoddi4(n, d, &mut r);
|
||||
TestResult::from_bool(q == n / d && r == n % d)
|
||||
}
|
||||
}
|
||||
|
||||
fn divsi3(n: U32, d: U32) -> TestResult {
|
||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let q = super::__divsi3(n, d);
|
||||
TestResult::from_bool(q == n / d)
|
||||
}
|
||||
}
|
||||
|
||||
fn modsi3(n: U32, d: U32) -> TestResult {
|
||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let r = super::__modsi3(n, d);
|
||||
TestResult::from_bool(r == n % d)
|
||||
}
|
||||
}
|
||||
|
||||
fn divmodsi4(n: U32, d: U32) -> TestResult {
|
||||
let (n, d) = (n.0 as i32, d.0 as i32);
|
||||
if d == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
let mut r = 0;
|
||||
let q = super::__divmodsi4(n, d, &mut r);
|
||||
TestResult::from_bool(q == n / d && r == n % d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ macro_rules! ashl {
|
|||
($intrinsic:ident: $ty:ty) => {
|
||||
/// Returns `a << b`, requires `b < $ty::bits()`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||
let half_bits = <$ty>::bits() / 2;
|
||||
if b & half_bits != 0 {
|
||||
<$ty>::from_parts(0, a.low() << (b - half_bits))
|
||||
|
@ -21,7 +21,7 @@ macro_rules! ashr {
|
|||
($intrinsic:ident: $ty:ty) => {
|
||||
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||
let half_bits = <$ty>::bits() / 2;
|
||||
if b & half_bits != 0 {
|
||||
<$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf,
|
||||
|
@ -41,7 +41,7 @@ macro_rules! lshr {
|
|||
($intrinsic:ident: $ty:ty) => {
|
||||
/// Returns logical `a >> b`, requires `b < $ty::bits()`
|
||||
#[cfg_attr(not(test), no_mangle)]
|
||||
pub extern fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
||||
let half_bits = <$ty>::bits() / 2;
|
||||
if b & half_bits != 0 {
|
||||
<$ty>::from_parts(a.high() >> (b - half_bits), 0)
|
||||
|
|
Loading…
Reference in New Issue