@@ -185,3 +185,133 @@ macro_rules! impl_delegate {
185185 }
186186 } ;
187187}
188+
189+ /// Returns `n / d` and sets `*rem = n % d`.
190+ ///
191+ /// This specialization exists because:
192+ /// - The LLVM backend for 32-bit SPARC cannot compile functions that return `(u128, u128)`,
193+ /// so we have to use an old fashioned `&mut u128` argument to return the remainder.
194+ /// - 64-bit SPARC does not have u64 * u64 => u128 widening multiplication, which makes the
195+ /// delegate algorithm strategy the only reasonably fast way to perform `u128` division.
196+ #[ doc( hidden) ]
197+ pub fn u128_divide_sparc ( duo : u128 , div : u128 , rem : & mut u128 ) -> u128 {
198+ use super :: * ;
199+ let duo_lo = duo as u64 ;
200+ let duo_hi = ( duo >> 64 ) as u64 ;
201+ let div_lo = div as u64 ;
202+ let div_hi = ( div >> 64 ) as u64 ;
203+
204+ match ( div_lo == 0 , div_hi == 0 , duo_hi == 0 ) {
205+ ( true , true , _) => zero_div_fn ( ) ,
206+ ( _, false , true ) => {
207+ * rem = duo;
208+ return 0 ;
209+ }
210+ ( false , true , true ) => {
211+ let tmp = u64_by_u64_div_rem ( duo_lo, div_lo) ;
212+ * rem = tmp. 1 as u128 ;
213+ return tmp. 0 as u128 ;
214+ }
215+ ( false , true , false ) => {
216+ if duo_hi < div_lo {
217+ let norm_shift = u64_normalization_shift ( div_lo, duo_hi, false ) ;
218+ let shl = if norm_shift == 0 {
219+ 64 - 1
220+ } else {
221+ 64 - norm_shift
222+ } ;
223+
224+ let mut div: u128 = div << shl;
225+ let mut pow_lo: u64 = 1 << shl;
226+ let mut quo_lo: u64 = 0 ;
227+ let mut duo = duo;
228+ loop {
229+ let sub = duo. wrapping_sub ( div) ;
230+ if 0 <= ( sub as i128 ) {
231+ duo = sub;
232+ quo_lo |= pow_lo;
233+ let duo_hi = ( duo >> 64 ) as u64 ;
234+ if duo_hi == 0 {
235+ let tmp = u64_by_u64_div_rem ( duo as u64 , div_lo) ;
236+ * rem = tmp. 1 as u128 ;
237+ return ( quo_lo | tmp. 0 ) as u128 ;
238+ }
239+ }
240+ div >>= 1 ;
241+ pow_lo >>= 1 ;
242+ }
243+ } else if duo_hi == div_lo {
244+ let tmp = u64_by_u64_div_rem ( duo as u64 , div as u64 ) ;
245+ * rem = tmp. 1 as u128 ;
246+ return ( 1 << 64 ) | ( tmp. 0 as u128 ) ;
247+ } else {
248+ if ( div_lo >> 32 ) == 0 {
249+ let div_0 = div_lo as u32 as u64 ;
250+ let ( quo_hi, rem_3) = u64_by_u64_div_rem ( duo_hi, div_0) ;
251+
252+ let duo_mid = ( ( duo >> 32 ) as u32 as u64 ) | ( rem_3 << 32 ) ;
253+ let ( quo_1, rem_2) = u64_by_u64_div_rem ( duo_mid, div_0) ;
254+
255+ let duo_lo = ( duo as u32 as u64 ) | ( rem_2 << 32 ) ;
256+ let ( quo_0, rem_1) = u64_by_u64_div_rem ( duo_lo, div_0) ;
257+
258+ * rem = rem_1 as u128 ;
259+ return ( quo_0 as u128 ) | ( ( quo_1 as u128 ) << 32 ) | ( ( quo_hi as u128 ) << 64 ) ;
260+ }
261+
262+ let duo_lo = duo as u64 ;
263+ let tmp = u64_by_u64_div_rem ( duo_hi, div_lo) ;
264+ let quo_hi = tmp. 0 ;
265+ let mut duo = ( duo_lo as u128 ) | ( ( tmp. 1 as u128 ) << 64 ) ;
266+ if duo < div {
267+ * rem = duo;
268+ return ( quo_hi as u128 ) << 64 ;
269+ }
270+
271+ let mut div: u128 = div << ( 64 - 1 ) ;
272+ let mut pow_lo: u64 = 1 << ( 64 - 1 ) ;
273+ let mut quo_lo: u64 = 0 ;
274+ loop {
275+ let sub = duo. wrapping_sub ( div) ;
276+ if 0 <= ( sub as i128 ) {
277+ duo = sub;
278+ quo_lo |= pow_lo;
279+ let duo_hi = ( duo >> 64 ) as u64 ;
280+ if duo_hi == 0 {
281+ let tmp = u64_by_u64_div_rem ( duo as u64 , div_lo) ;
282+ * rem = tmp. 1 as u128 ;
283+ return ( tmp. 0 ) as u128 | ( quo_lo as u128 ) | ( ( quo_hi as u128 ) << 64 ) ;
284+ }
285+ }
286+ div >>= 1 ;
287+ pow_lo >>= 1 ;
288+ }
289+ }
290+ }
291+ ( _, false , false ) => {
292+ if duo < div {
293+ * rem = duo;
294+ return 0 ;
295+ }
296+ let div_original = div;
297+ let shl = u64_normalization_shift ( duo_hi, div_hi, false ) ;
298+ let mut duo = duo;
299+ let mut div: u128 = div << shl;
300+ let mut pow_lo: u64 = 1 << shl;
301+ let mut quo_lo: u64 = 0 ;
302+ loop {
303+ let sub = duo. wrapping_sub ( div) ;
304+ if 0 <= ( sub as i128 ) {
305+ duo = sub;
306+ quo_lo |= pow_lo;
307+ if duo < div_original {
308+ * rem = duo;
309+ return quo_lo as u128 ;
310+ }
311+ }
312+ div >>= 1 ;
313+ pow_lo >>= 1 ;
314+ }
315+ }
316+ }
317+ }
0 commit comments