blob: f1822f0f86e87e1bb5bea2ec9f307873c8782045 [file] [log] [blame]
use int::udiv::*;
macro_rules! sdivmod {
(
$unsigned_fn:ident, // name of the unsigned division function
$signed_fn:ident, // name of the signed division function
$uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
$iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
$($attr:tt),* // attributes
) => {
intrinsics! {
#[avr_skip]
$(
#[$attr]
)*
/// Returns `n / d` and sets `*rem = n % d`
pub extern "C" fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX {
let a_neg = a < 0;
let b_neg = b < 0;
let mut a = a;
let mut b = b;
if a_neg {
a = a.wrapping_neg();
}
if b_neg {
b = b.wrapping_neg();
}
let mut r = *rem as $uX;
let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX;
let mut r = r as $iX;
if a_neg {
r = r.wrapping_neg();
}
*rem = r;
if a_neg != b_neg {
t.wrapping_neg()
} else {
t
}
}
}
}
}
macro_rules! sdiv {
(
$unsigned_fn:ident, // name of the unsigned division function
$signed_fn:ident, // name of the signed division function
$uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
$iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
$($attr:tt),* // attributes
) => {
intrinsics! {
#[avr_skip]
$(
#[$attr]
)*
/// Returns `n / d`
pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX {
let a_neg = a < 0;
let b_neg = b < 0;
let mut a = a;
let mut b = b;
if a_neg {
a = a.wrapping_neg();
}
if b_neg {
b = b.wrapping_neg();
}
let t = $unsigned_fn(a as $uX, b as $uX) as $iX;
if a_neg != b_neg {
t.wrapping_neg()
} else {
t
}
}
}
}
}
macro_rules! smod {
(
$unsigned_fn:ident, // name of the unsigned division function
$signed_fn:ident, // name of the signed division function
$uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
$iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
$($attr:tt),* // attributes
) => {
intrinsics! {
#[avr_skip]
$(
#[$attr]
)*
/// Returns `n % d`
pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX {
let a_neg = a < 0;
let b_neg = b < 0;
let mut a = a;
let mut b = b;
if a_neg {
a = a.wrapping_neg();
}
if b_neg {
b = b.wrapping_neg();
}
let r = $unsigned_fn(a as $uX, b as $uX) as $iX;
if a_neg {
r.wrapping_neg()
} else {
r
}
}
}
}
}
sdivmod!(
__udivmodsi4,
__divmodsi4,
u32,
i32,
maybe_use_optimized_c_shim
);
// The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros
intrinsics! {
#[maybe_use_optimized_c_shim]
#[arm_aeabi_alias = __aeabi_idiv]
/// Returns `n / d`
pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 {
let a_neg = a < 0;
let b_neg = b < 0;
let mut a = a;
let mut b = b;
if a_neg {
a = a.wrapping_neg();
}
if b_neg {
b = b.wrapping_neg();
}
let t = __udivsi3(a as u32, b as u32) as i32;
if a_neg != b_neg {
t.wrapping_neg()
} else {
t
}
}
}
smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim);
sdivmod!(
__udivmoddi4,
__divmoddi4,
u64,
i64,
maybe_use_optimized_c_shim
);
sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim);
smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim);
// LLVM does not currently have a `__divmodti4` function, but GCC does
sdivmod!(
__udivmodti4,
__divmodti4,
u128,
i128,
maybe_use_optimized_c_shim
);
sdiv!(__udivti3, __divti3, u128, i128, win64_128bit_abi_hack);
smod!(__umodti3, __modti3, u128, i128, win64_128bit_abi_hack);