Skip to content

avr: implement unsigned division intrinsics #816

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

tones111
Copy link

This PR adds a missing AVR intrinsic for 8-bit unsigned division (see #711) and is based on the popular [long division](https://en.wikipedia.org/wiki/Divisio n_algorithm#Long_division) algorithm.

GCC uses a special calling convention for multiplication and division primitives, requiring a naked_asm implementation.

This implementation attempts to be an assembly port of the following Rust implementation of the long division algorithm.

pub fn long_div_u8(mut num_quo: u8, divisor: u8) -> (u8, u8) {
    let mut remainder = 0u8;
    for _ in 0..8u8 {
        let overflow;
        (num_quo, overflow) = num_quo.overflowing_add(num_quo);
        (remainder, _) = remainder.carrying_add(remainder, overflow);

        if let Some(rem) = remainder.checked_sub(divisor) {
            remainder = rem;
            num_quo += 1;
        }
    }
    (num_quo, remainder)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_long_div_u8() {
        for n in 0..=u8::MAX {
            for d in 1..=u8::MAX {
                assert_eq!(long_div_u8(n, d), (n / d, n % d));
            }
        }
    }

@tones111
Copy link
Author

Pinging @Patryk27 for testing assistance. As indicated in the description, I've validated the algorithm with cargo test on x86-64, however, I haven't executed the code on AVR hardware or equivalent simulator. Hopefully you can run it through your AVR math fuzzer.

@tones111 tones111 changed the title avr: __udivmodqi4 avr: implement unsigned division intrinsics Apr 13, 2025
@Patryk27
Copy link
Contributor

Ok, I've checked the code under avr-tester's testsuite and it seems to work, nice job!

One thing left to check is whether all AVRs support the instructions here (don't know by heart which ones belong to the base instruction set).

@tones111
Copy link
Author

Thanks for testing @Patryk27 .

I referenced Microchip's AVR ISA for the opcodes. I think we should be good since none of the instructions used are listed as "N/A" in the chapter 5 tables.

The gcc implementation uses macros to conditionally switch between mov and movw. They also switch between call and rcall in the signed functions. I would hope this could be implemented via an optimization pass, but that doesn't appear to be the case with current rustc.

If you're willing to mentor a bit I'd be interested in trying to help improve the AVR codegen (but don't have any LLVM-specific dev experience).

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

Successfully merging this pull request may close these issues.

2 participants