1 | #[cfg (not(feature = "unstable-public-internals" ))] |
2 | pub(crate) use crate::int::specialized_div_rem::*; |
3 | #[cfg (feature = "unstable-public-internals" )] |
4 | pub use crate::int::specialized_div_rem::*; |
5 | |
6 | intrinsics! { |
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" ))] |
22 | intrinsics! { |
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" )] |
35 | intrinsics! { |
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 | |
133 | intrinsics! { |
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 | } |
200 | |