compiler_builtins/int/
udiv.rs

1#[cfg(not(feature = "unstable-public-internals"))]
2pub(crate) use crate::int::specialized_div_rem::*;
3#[cfg(feature = "unstable-public-internals")]
4pub use crate::int::specialized_div_rem::*;
5
6intrinsics! {
7    #[maybe_use_optimized_c_shim]
8    #[arm_aeabi_alias = __aeabi_uidiv]
9    /// Returns `n / d`
10    pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
11        u32_div_rem(n, d).0
12    }
13
14    #[maybe_use_optimized_c_shim]
15    /// Returns `n % d`
16    pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 {
17        u32_div_rem(n, d).1
18    }
19}
20
21#[cfg(not(target_arch = "avr"))]
22intrinsics! {
23    #[maybe_use_optimized_c_shim]
24    /// Returns `n / d` and sets `*rem = n % d`
25    pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
26        let quo_rem = u32_div_rem(n, d);
27        if let Some(rem) = rem {
28            *rem = quo_rem.1;
29        }
30        quo_rem.0
31    }
32}
33
34#[cfg(target_arch = "avr")]
35intrinsics! {
36    /// Returns `n / d` and `n % d` packed together.
37    ///
38    /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but
39    /// both force a stack allocation, while our result has to be in R18:R26.
40    pub extern "C" fn __udivmodsi4(n: u32, d: u32) -> u64 {
41        let (div, rem) = u32_div_rem(n, d);
42
43        ((rem as u64) << 32) | (div as u64)
44    }
45
46    #[unsafe(naked)]
47    pub unsafe extern "C" fn __udivmodqi4() {
48        // compute unsigned 8-bit `n / d` and `n % d`.
49        //
50        // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
51        // Inputs:
52        //     R24: dividend
53        //     R22: divisor
54        // Outputs:
55        //     R24: quotient  (dividend / divisor)
56        //     R25: remainder (dividend % divisor)
57        // Clobbers:
58        //     R23: loop counter
59        core::arch::naked_asm!(
60            // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm.
61            // Bits shift out of the dividend and into the quotient, so R24 is used for both.
62            "clr R25",      // remainder = 0
63
64            "ldi R23, 8",   // for each bit
65            "1:",
66            "lsl R24",      //     shift the dividend MSb
67            "rol R25",      //     into the remainder LSb
68
69            "cp  R25, R22", //     if remainder >= divisor
70            "brlo 2f",
71            "sub R25, R22", //         remainder -= divisor
72            "sbr R24, 1",   //         quotient |= 1
73            "2:",
74
75            "dec R23",      // end loop
76            "brne 1b",
77            "ret",
78        );
79    }
80
81    #[unsafe(naked)]
82    pub unsafe extern "C" fn __udivmodhi4() {
83        // compute unsigned 16-bit `n / d` and `n % d`.
84        //
85        // Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
86        // Inputs:
87        //     R24: dividend [low]
88        //     R25: dividend [high]
89        //     R22: divisor [low]
90        //     R23: divisor [high]
91        // Outputs:
92        //     R22: quotient [low]  (dividend / divisor)
93        //     R23: quotient [high]
94        //     R24: remainder [low] (dividend % divisor)
95        //     R25: remainder [high]
96        // Clobbers:
97        //     R21: loop counter
98        //     R26: divisor [low]
99        //     R27: divisor [high]
100        core::arch::naked_asm!(
101            // This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm.
102            // Bits shift out of the dividend and into the quotient, so R24+R25 are used for both.
103            "mov R26, R22",     // move divisor to make room for quotient
104            "mov R27, R23",
105            "mov R22, R24",     // move dividend to output location (becomes quotient)
106            "mov R23, R25",
107            "clr R24",          // remainder = 0
108            "clr R25",
109
110            "ldi R21, 16",      // for each bit
111            "1:",
112            "lsl R22",          //     shift the dividend MSb
113            "rol R23",
114            "rol R24",          //     into the remainder LSb
115            "rol R25",
116
117            "cp  R24, R26",     //     if remainder >= divisor
118            "cpc R25, R27",
119            "brlo 2f",
120            "sub R24, R26",     //         remainder -= divisor
121            "sbc R25, R27",
122            "sbr R22, 1",       //         quotient |= 1
123            "2:",
124
125            "dec R21",          // end loop
126            "brne 1b",
127            "ret",
128        );
129    }
130
131}
132
133intrinsics! {
134    #[maybe_use_optimized_c_shim]
135    /// Returns `n / d`
136    pub extern "C" fn __udivdi3(n: u64, d: u64) -> u64 {
137        u64_div_rem(n, d).0
138    }
139
140    #[maybe_use_optimized_c_shim]
141    /// Returns `n % d`
142    pub extern "C" fn __umoddi3(n: u64, d: u64) -> u64 {
143        u64_div_rem(n, d).1
144    }
145
146    #[maybe_use_optimized_c_shim]
147    /// Returns `n / d` and sets `*rem = n % d`
148    pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
149        let quo_rem = u64_div_rem(n, d);
150        if let Some(rem) = rem {
151            *rem = quo_rem.1;
152        }
153        quo_rem.0
154    }
155
156    // Note: we use block configuration and not `if cfg!(...)`, because we need to entirely disable
157    // the existence of `u128_div_rem` to get 32-bit SPARC to compile, see `u128_divide_sparc` docs.
158
159    /// Returns `n / d`
160    pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 {
161        #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] {
162            u128_div_rem(n, d).0
163        }
164        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] {
165            u128_divide_sparc(n, d, &mut 0)
166        }
167    }
168
169    /// Returns `n % d`
170    pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 {
171        #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] {
172            u128_div_rem(n, d).1
173        }
174        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] {
175            let mut rem = 0;
176            u128_divide_sparc(n, d, &mut rem);
177            rem
178        }
179    }
180
181    /// Returns `n / d` and sets `*rem = n % d`
182    pub extern "C" fn __udivmodti4(n: u128, d: u128, rem: Option<&mut u128>) -> u128 {
183        #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] {
184            let quo_rem = u128_div_rem(n, d);
185            if let Some(rem) = rem {
186                *rem = quo_rem.1;
187            }
188            quo_rem.0
189        }
190        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] {
191            let mut tmp = 0;
192            let quo = u128_divide_sparc(n, d, &mut tmp);
193            if let Some(rem) = rem {
194                *rem = tmp;
195            }
196            quo
197        }
198    }
199}