| 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); |