@@ -185,3 +185,133 @@ macro_rules! impl_delegate {
185
185
}
186
186
} ;
187
187
}
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