diff --git a/src/int/sdiv.rs b/src/int/sdiv.rs index e1e3f33bb..f1822f0f8 100644 --- a/src/int/sdiv.rs +++ b/src/int/sdiv.rs @@ -9,6 +9,7 @@ macro_rules! sdivmod { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* @@ -50,6 +51,7 @@ macro_rules! sdiv { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* @@ -85,6 +87,7 @@ macro_rules! smod { $($attr:tt),* // attributes ) => { intrinsics! { + #[avr_skip] $( #[$attr] )* diff --git a/src/int/udiv.rs b/src/int/udiv.rs index 2f236346d..c5ef4a6b1 100644 --- a/src/int/udiv.rs +++ b/src/int/udiv.rs @@ -18,6 +18,7 @@ intrinsics! { u32_div_rem(n, d).1 } + #[avr_skip] #[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 { @@ -28,18 +29,21 @@ intrinsics! { quo_rem.0 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).0 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n % d` pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 { u64_div_rem(n, d).1 } + #[avr_skip] #[maybe_use_optimized_c_shim] /// Returns `n / d` and sets `*rem = n % d` pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 { @@ -77,6 +81,7 @@ intrinsics! { } } + #[avr_skip] #[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 { diff --git a/src/macros.rs b/src/macros.rs index 6926feac0..4c1d8af62 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -82,7 +82,6 @@ macro_rules! intrinsics { $($rest:tt)* ) => ( - #[cfg($name = "optimized-c")] pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { extern $abi { @@ -304,6 +303,36 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); + // For division and modulo, AVR uses a custom calling convention¹ that does + // not match our definitions here. Ideally we would just use hand-written + // naked functions, but that's quite a lot of code to port² - so for the + // time being we are just ignoring the problematic functions, letting + // avr-gcc (which is required to compile to AVR anyway) link them from + // libgcc. + // + // ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling + // Convention") + // ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S + ( + #[avr_skip] + $(#[$($attr:tt)*])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + #[cfg(not(target_arch = "avr"))] + intrinsics! { + $(#[$($attr)*])* + pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + // This is the final catch-all rule. At this point we generate an // intrinsic with a conditional `#[no_mangle]` directive to avoid // interfering with duplicate symbols and whatnot during testing.