Skip to content

Commit

Permalink
replace old soft division code with new functions
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronKutch committed May 4, 2020
1 parent 6c6304d commit 20c567c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 76 deletions.
26 changes: 17 additions & 9 deletions src/int/sdiv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,55 +57,63 @@ trait Divmod: Int {

impl Divmod for i32 {}
impl Divmod for i64 {}
// NOTE: there are aborts inside the specialized_div_rem functions if division by 0
// is encountered, however these should be unreachable and optimized away unless
// uses of `std/core::intrinsics::unchecked_div/rem` do not have a 0 check in front
// of them.

intrinsics! {
#[maybe_use_optimized_c_shim]
#[arm_aeabi_alias = __aeabi_idiv]
/// Returns `n / d`
pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 {
a.div(b)
i32_div_rem(a, b).0
}

#[maybe_use_optimized_c_shim]
/// Returns `n % d`
pub extern "C" fn __modsi3(a: i32, b: i32) -> i32 {
a.mod_(b)
i32_div_rem(a, b).1
}

#[maybe_use_optimized_c_shim]
/// Returns `n / d` and sets `*rem = n % d`
pub extern "C" fn __divmodsi4(a: i32, b: i32, rem: &mut i32) -> i32 {
a.divmod(b, rem, |a, b| __divsi3(a, b))
let quo_rem = i32_div_rem(a, b);
*rem = quo_rem.1;
quo_rem.0
}

#[maybe_use_optimized_c_shim]
/// Returns `n / d`
pub extern "C" fn __divdi3(a: i64, b: i64) -> i64 {
a.div(b)
i64_div_rem(a, b).0
}

#[maybe_use_optimized_c_shim]
/// Returns `n % d`
pub extern "C" fn __moddi3(a: i64, b: i64) -> i64 {
a.mod_(b)
i64_div_rem(a, b).1
}

#[aapcs_on_arm]
/// Returns `n / d` and sets `*rem = n % d`
pub extern "C" fn __divmoddi4(a: i64, b: i64, rem: &mut i64) -> i64 {
a.divmod(b, rem, |a, b| __divdi3(a, b))
let quo_rem = i64_div_rem(a, b);
*rem = quo_rem.1;
quo_rem.0
}

#[win64_128bit_abi_hack]
/// Returns `n / d`
pub extern "C" fn __divti3(a: i128, b: i128) -> i128 {
a.div(b)
i128_div_rem(a, b).0
}

#[win64_128bit_abi_hack]
/// Returns `n % d`
pub extern "C" fn __modti3(a: i128, b: i128) -> i128 {
a.mod_(b)
i128_div_rem(a, b).1
}

// there is no `__divmodti4`
Expand Down
90 changes: 23 additions & 67 deletions src/int/udiv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,119 +151,75 @@ macro_rules! udivmod_inner {
(q << 1) | carry as $ty
}}
}
// NOTE: there are aborts inside the specialized_div_rem functions if division by 0
// is encountered, however these should be unreachable and optimized away unless
// uses of `std/core::intrinsics::unchecked_div/rem` do not have a 0 check in front
// of them.

intrinsics! {
#[maybe_use_optimized_c_shim]
#[arm_aeabi_alias = __aeabi_uidiv]
/// Returns `n / d`
pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
// Special cases
if d == 0 {
// NOTE This should be unreachable in safe Rust because the program will panic before
// this intrinsic is called
::abort();
}

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 += 1;

// 1 <= sr <= u32::BITS - 1
let mut q = n << (u32::BITS - sr);
let mut r = n >> sr;

let mut carry = 0;

// Don't use a range because they may generate references to memcpy in unoptimized code
let mut i = 0;
while i < sr {
i += 1;

// 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 << 1) | carry
u32_div_rem(n, d).0
}

#[maybe_use_optimized_c_shim]
/// Returns `n % d`
pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 {
let q = __udivsi3(n, d);
n - q * d
u32_div_rem(n, d).1
}

#[maybe_use_optimized_c_shim]
/// Returns `n / d` and sets `*rem = n % d`
pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
let q = __udivsi3(n, d);
let quo_rem = u32_div_rem(n, d);
if let Some(rem) = rem {
*rem = n - (q * d);
*rem = quo_rem.1;
}
q
quo_rem.0
}

#[maybe_use_optimized_c_shim]
/// Returns `n / d`
pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 {
__udivmoddi4(n, d, None)
u64_div_rem(n, d).0
}

#[maybe_use_optimized_c_shim]
/// Returns `n % d`
pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 {
let mut rem = 0;
__udivmoddi4(n, d, Some(&mut rem));
rem
u64_div_rem(n, d).1
}

/// Returns `n / d` and sets `*rem = n % d`
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
udivmod_inner!(n, d, rem, u64)
let quo_rem = u64_div_rem(n, d);
if let Some(rem) = rem {
*rem = quo_rem.1;
}
quo_rem.0
}

#[win64_128bit_abi_hack]
/// Returns `n / d`
pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 {
__udivmodti4(n, d, None)
u128_div_rem(n, d).0
}

#[win64_128bit_abi_hack]
/// Returns `n % d`
pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 {
let mut rem = 0;
__udivmodti4(n, d, Some(&mut rem));
rem
u128_div_rem(n, d).1
}

#[win64_128bit_abi_hack]
/// Returns `n / d` and sets `*rem = n % d`
pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 {
udivmod_inner!(n, d, rem, u128)
let quo_rem = u128_div_rem(n, d);
if let Some(rem) = rem {
*rem = quo_rem.1;
}
quo_rem.0
}
}

0 comments on commit 20c567c

Please sign in to comment.