Skip to content

Commit fbf1586

Browse files
committed
Fix division on AVRs
For division and modulo, AVR uses a custom calling convention that does not match compiler_builtins' expectations, leading to non-working code¹. Ideally we'd just use hand-written naked functions (as, afair, ARM does), but that's a lot of code to port², so hopefully we'll be able to do it gradually later. For the time being, I'd suggest not compiling problematic functions for AVR target - this causes avr-gcc (which is a mandatory part of Rust+AVR toolchain anyway) to link hand-written assembly from libgcc, which is confirmed to work. I've tested the code locally on simavr and the patch seems to be working correctly :-) ¹ rust-lang/rust#82242, rust-lang/rust#83281 ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S Closes rust-lang/rust#82242 Closes rust-lang/rust#83281
1 parent 4117da3 commit fbf1586

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

src/int/sdiv.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ macro_rules! sdivmod {
99
$($attr:tt),* // attributes
1010
) => {
1111
intrinsics! {
12+
#[avr_skip]
1213
$(
1314
#[$attr]
1415
)*

src/int/udiv.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ intrinsics! {
1818
u32_div_rem(n, d).1
1919
}
2020

21+
#[avr_skip]
2122
#[maybe_use_optimized_c_shim]
2223
/// Returns `n / d` and sets `*rem = n % d`
2324
pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
@@ -40,6 +41,7 @@ intrinsics! {
4041
u64_div_rem(n, d).1
4142
}
4243

44+
#[avr_skip]
4345
#[maybe_use_optimized_c_shim]
4446
/// Returns `n / d` and sets `*rem = n % d`
4547
pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
@@ -77,6 +79,7 @@ intrinsics! {
7779
}
7880
}
7981

82+
#[avr_skip]
8083
#[win64_128bit_abi_hack]
8184
/// Returns `n / d` and sets `*rem = n % d`
8285
pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 {

src/macros.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ macro_rules! intrinsics {
8282

8383
$($rest:tt)*
8484
) => (
85-
8685
#[cfg($name = "optimized-c")]
8786
pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
8887
extern $abi {
@@ -304,6 +303,36 @@ macro_rules! intrinsics {
304303
intrinsics!($($rest)*);
305304
);
306305

306+
// For division and modulo, AVR uses a custom calling convention¹ that does
307+
// not match our definitions here. Ideally we would just use hand-written
308+
// naked functions, but that's quite a lot of code to port² - so for the
309+
// time being we are just ignoring the problematic functions, letting
310+
// avr-gcc (which is required to compile to AVR anyway) link them from
311+
// libgcc.
312+
//
313+
// ¹ https://gcc.gnu.org/wiki/avr-gcc (see "Exceptions to the Calling
314+
// Convention")
315+
// ² https://github.com/gcc-mirror/gcc/blob/31048012db98f5ec9c2ba537bfd850374bdd771f/libgcc/config/avr/lib1funcs.S
316+
(
317+
#[avr_skip]
318+
$(#[$($attr:tt)*])*
319+
pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) $(-> $ret:ty)? {
320+
$($body:tt)*
321+
}
322+
323+
$($rest:tt)*
324+
) => (
325+
#[cfg(not(target_arch = "avr"))]
326+
intrinsics! {
327+
$(#[$($attr)*])*
328+
pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
329+
$($body)*
330+
}
331+
}
332+
333+
intrinsics!($($rest)*);
334+
);
335+
307336
// This is the final catch-all rule. At this point we generate an
308337
// intrinsic with a conditional `#[no_mangle]` directive to avoid
309338
// interfering with duplicate symbols and whatnot during testing.

0 commit comments

Comments
 (0)