Add signed division functions
This commit is contained in:
parent
999d82a0df
commit
f919660be5
24
README.md
24
README.md
|
@ -40,9 +40,9 @@ See [rust-lang/rust#35437][0].
|
||||||
- [x] arm/aeabi_uidivmod.S
|
- [x] arm/aeabi_uidivmod.S
|
||||||
- [x] arm/aeabi_uldivmod.S
|
- [x] arm/aeabi_uldivmod.S
|
||||||
- [ ] arm/divdf3vfp.S
|
- [ ] arm/divdf3vfp.S
|
||||||
- [ ] arm/divmodsi4.S
|
- [ ] arm/divmodsi4.S (generic version is done)
|
||||||
- [ ] arm/divsf3vfp.S
|
- [ ] arm/divsf3vfp.S
|
||||||
- [ ] arm/divsi3.S
|
- [ ] arm/divsi3.S (generic version is done)
|
||||||
- [ ] arm/eqdf2vfp.S
|
- [ ] arm/eqdf2vfp.S
|
||||||
- [ ] arm/eqsf2vfp.S
|
- [ ] arm/eqsf2vfp.S
|
||||||
- [ ] arm/extendsfdf2vfp.S
|
- [ ] arm/extendsfdf2vfp.S
|
||||||
|
@ -62,7 +62,7 @@ See [rust-lang/rust#35437][0].
|
||||||
- [ ] arm/lesf2vfp.S
|
- [ ] arm/lesf2vfp.S
|
||||||
- [ ] arm/ltdf2vfp.S
|
- [ ] arm/ltdf2vfp.S
|
||||||
- [ ] arm/ltsf2vfp.S
|
- [ ] arm/ltsf2vfp.S
|
||||||
- [ ] arm/modsi3.S
|
- [ ] arm/modsi3.S (generic version is done)
|
||||||
- [ ] arm/muldf3vfp.S
|
- [ ] arm/muldf3vfp.S
|
||||||
- [ ] arm/mulsf3vfp.S
|
- [ ] arm/mulsf3vfp.S
|
||||||
- [ ] arm/nedf2vfp.S
|
- [ ] arm/nedf2vfp.S
|
||||||
|
@ -73,17 +73,19 @@ See [rust-lang/rust#35437][0].
|
||||||
- [ ] arm/subdf3vfp.S
|
- [ ] arm/subdf3vfp.S
|
||||||
- [ ] arm/subsf3vfp.S
|
- [ ] arm/subsf3vfp.S
|
||||||
- [ ] arm/truncdfsf2vfp.S
|
- [ ] arm/truncdfsf2vfp.S
|
||||||
- [ ] arm/udivmodsi4.S
|
- [ ] arm/udivmodsi4.S (generic version is done)
|
||||||
- [ ] arm/udivsi3.S
|
- [ ] arm/udivsi3.S (generic version is done)
|
||||||
- [ ] arm/umodsi3.S
|
- [ ] arm/umodsi3.S (generic version is done)
|
||||||
- [ ] arm/unorddf2vfp.S
|
- [ ] arm/unorddf2vfp.S
|
||||||
- [ ] arm/unordsf2vfp.S
|
- [ ] arm/unordsf2vfp.S
|
||||||
- [x] ashldi3.c
|
- [x] ashldi3.c
|
||||||
- [x] ashrdi3.c
|
- [x] ashrdi3.c
|
||||||
- [ ] divdf3.c
|
- [ ] divdf3.c
|
||||||
- [ ] divdi3.c
|
- [x] divdi3.c
|
||||||
|
- [x] divmoddi4.c
|
||||||
|
- [x] divmodsi4.c
|
||||||
- [ ] divsf3.c
|
- [ ] divsf3.c
|
||||||
- [ ] divsi3.c
|
- [x] divsi3.c
|
||||||
- [ ] extendhfsf2.c
|
- [ ] extendhfsf2.c
|
||||||
- [ ] extendsfdf2.c
|
- [ ] extendsfdf2.c
|
||||||
- [ ] fixdfdi.c
|
- [ ] fixdfdi.c
|
||||||
|
@ -113,8 +115,8 @@ See [rust-lang/rust#35437][0].
|
||||||
- [ ] i386/udivdi3.S
|
- [ ] i386/udivdi3.S
|
||||||
- [ ] i386/umoddi3.S
|
- [ ] i386/umoddi3.S
|
||||||
- [x] lshrdi3.c
|
- [x] lshrdi3.c
|
||||||
- [ ] moddi3.c
|
- [x] moddi3.c
|
||||||
- [ ] modsi3.c
|
- [x] modsi3.c
|
||||||
- [ ] muldf3.c
|
- [ ] muldf3.c
|
||||||
- [x] muldi3.c
|
- [x] muldi3.c
|
||||||
- [x] mulodi4.c
|
- [x] mulodi4.c
|
||||||
|
@ -251,8 +253,6 @@ These builtins are never called by LLVM.
|
||||||
- ~~ctzdi2.c~~
|
- ~~ctzdi2.c~~
|
||||||
- ~~ctzsi2.c~~
|
- ~~ctzsi2.c~~
|
||||||
- ~~ctzti2.c~~
|
- ~~ctzti2.c~~
|
||||||
- ~~divmoddi4.c~~
|
|
||||||
- ~~divmodsi4.c~~
|
|
||||||
- ~~ffsdi2.c~~
|
- ~~ffsdi2.c~~
|
||||||
- ~~ffsti2.c~~
|
- ~~ffsti2.c~~
|
||||||
- ~~mulvdi3.c~~
|
- ~~mulvdi3.c~~
|
||||||
|
|
40
src/arm.rs
40
src/arm.rs
|
@ -1,6 +1,6 @@
|
||||||
use core::intrinsics;
|
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
|
// calling convention which can't be implemented using a normal Rust function
|
||||||
#[naked]
|
#[naked]
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[cfg_attr(not(test), no_mangle)]
|
||||||
|
@ -30,6 +30,44 @@ pub unsafe fn __aeabi_uldivmod() {
|
||||||
intrinsics::unreachable();
|
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" {
|
extern "C" {
|
||||||
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
||||||
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
||||||
|
|
|
@ -24,6 +24,7 @@ extern crate rlibc;
|
||||||
pub mod arm;
|
pub mod arm;
|
||||||
|
|
||||||
pub mod udiv;
|
pub mod udiv;
|
||||||
|
pub mod sdiv;
|
||||||
pub mod mul;
|
pub mod mul;
|
||||||
pub mod shift;
|
pub mod shift;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ macro_rules! mul {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns `a * b`
|
/// Returns `a * b`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[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 half_bits = <$ty>::bits() / 4;
|
||||||
let lower_mask = !0 >> half_bits;
|
let lower_mask = !0 >> half_bits;
|
||||||
let mut low = (a.low() & lower_mask) * (b.low() & lower_mask);
|
let mut low = (a.low() & lower_mask) * (b.low() & lower_mask);
|
||||||
|
@ -29,7 +29,7 @@ macro_rules! mulo {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows
|
/// Returns `a * b` and sets `*overflow = 1` if `a * b` overflows
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[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;
|
*overflow = 0;
|
||||||
let result = a.wrapping_mul(b);
|
let result = a.wrapping_mul(b);
|
||||||
if a == <$ty>::min_value() {
|
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) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns `a << b`, requires `b < $ty::bits()`
|
/// Returns `a << b`, requires `b < $ty::bits()`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[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;
|
let half_bits = <$ty>::bits() / 2;
|
||||||
if b & half_bits != 0 {
|
if b & half_bits != 0 {
|
||||||
<$ty>::from_parts(0, a.low() << (b - half_bits))
|
<$ty>::from_parts(0, a.low() << (b - half_bits))
|
||||||
|
@ -21,7 +21,7 @@ macro_rules! ashr {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()`
|
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[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;
|
let half_bits = <$ty>::bits() / 2;
|
||||||
if b & half_bits != 0 {
|
if b & half_bits != 0 {
|
||||||
<$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf,
|
<$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf,
|
||||||
|
@ -41,7 +41,7 @@ macro_rules! lshr {
|
||||||
($intrinsic:ident: $ty:ty) => {
|
($intrinsic:ident: $ty:ty) => {
|
||||||
/// Returns logical `a >> b`, requires `b < $ty::bits()`
|
/// Returns logical `a >> b`, requires `b < $ty::bits()`
|
||||||
#[cfg_attr(not(test), no_mangle)]
|
#[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;
|
let half_bits = <$ty>::bits() / 2;
|
||||||
if b & half_bits != 0 {
|
if b & half_bits != 0 {
|
||||||
<$ty>::from_parts(a.high() >> (b - half_bits), 0)
|
<$ty>::from_parts(a.high() >> (b - half_bits), 0)
|
||||||
|
|
Loading…
Reference in New Issue