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}