Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native support for AVR instrinsics #711

Open
Patryk27 opened this issue Oct 14, 2024 · 7 comments
Open

Native support for AVR instrinsics #711

Patryk27 opened this issue Oct 14, 2024 · 7 comments

Comments

@Patryk27
Copy link
Contributor

At the moment compiler-builtins isn't useful for AVR, because that platform uses a custom calling convention for intrinsics - supporting AVR here would require:

  1. Implementing this custom calling convention in LLVM.
  2. Exposing it in rustc.
  3. Finally, using it within compiler-builtins.

There are no ongoing plans to do so yet, but over rust-lang/rust#131651 it was pointed out it would be nice to have some kind of message of this issue left, so here we go 🙂

@tgross35
Copy link
Contributor

tgross35 commented Oct 14, 2024

Thanks for filing this. I don't think we are blocked on LLVM having support for the calling convention, instead we should be able to use naked functions to translate the cc like we do for aeabi intrinsics

// NOTE This function and the ones below are implemented using assembly because they are using a
// custom calling convention which can't be implemented using a normal Rust function.
#[naked]
#[cfg(not(target_env = "msvc"))]
pub unsafe extern "C" fn __aeabi_uidivmod() {
core::arch::naked_asm!(
"push {{lr}}",
"sub sp, sp, #4",
"mov r2, sp",
bl!("__udivmodsi4"),
"ldr r1, [sp]",
"add sp, sp, #4",
"pop {{pc}}",
);
}
.

I'm not positive how this would interact with the clobbers, however.

@Patryk27
Copy link
Contributor Author

Oh, sure, that seems like a good idea 🙂

@tgross35
Copy link
Contributor

tgross35 commented Oct 14, 2024

Separately you may be interested in getting AVR asm to stable. This isn't a blocker for this crate but it may be useful in user code rust-lang/rust#93335

@tgross35
Copy link
Contributor

Also, do you know if there is a version of these symbols in assembly that don't come from libgcc? Some of these are probably easy enough that we could provide our own assembly implementations, but we need to be careful with licensing.

@Patryk27
Copy link
Contributor Author

Also, do you know if there is a version of these symbols in assembly that don't come from libgcc?

I'm aware only of the libgcc implementation, unfortunately.

@tgross35
Copy link
Contributor

tgross35 commented Feb 5, 2025

After rust-lang/rust#131651 merges it should be possible to fix the AVRTiny asm convention, at which point I think we will be okay to start using AVR assembly in this repo. The #[naked] wrapper to convert the ABI and forward to our implementations is probably still the best option.

@tgross35
Copy link
Contributor

tgross35 commented Mar 4, 2025

@Patryk27 do you happen to know which intrinsics we are actually missing? Testing with the below:

#![no_std]

#[unsafe(no_mangle)]
pub fn call_umulhisi3(a: &u16, b: &u16, r: &mut u32) {
    *r = *a as u32 * *b as u32;
}

#[unsafe(no_mangle)]
pub fn call_mulhisi3(a: &i16, b: &i16, r: &mut i32) {
    *r = *a as i32 * *b as i32;
}

#[unsafe(no_mangle)]
pub fn call_udivmodqi4(a: &u8, b: &u8, r1: &mut u8, r2: &mut u8) {
    (*r1, *r2) = (*a / *b, *a % *b);
}

#[unsafe(no_mangle)]
pub fn call_divmodqi4(a: &i8, b: &i8, r1: &mut i8, r2: &mut i8) {
    (*r1, *r2) = (*a / *b, *a % *b);
}

#[unsafe(no_mangle)]
pub fn call_udivmodhi4(a: &u16, b: &u16, r1: &mut u16, r2: &mut u16) {
    (*r1, *r2) = (*a / *b, *a % *b);
}

#[unsafe(no_mangle)]
pub fn call_divmodhi4(a: &i16, b: &i16, r1: &mut i16, r2: &mut i16) {
    (*r1, *r2) = (*a / *b, *a % *b);
}

On the atmega328p target-cpu (unsure whether this makes a difference), the only intrinsics from the list at https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention are the 8- and 16-bit integer division __u?divmod[hq]i4. For the multiplication, LLVM seems to widen the integers to u32 and call the default builtin __mulsi3 which I don't think would have the special ABI. Do you typically see more missing symbols (beyond small int division) when you try linking projects without the AVR libgcc?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants