24
24
25
25
#![ allow( non_camel_case_types, unused_variables) ]
26
26
27
-
28
27
#[ cfg( any( target_pointer_width="32" , target_pointer_width="16" ) ) ]
29
28
pub mod reimpls {
29
+
30
30
#![ allow( unused_comparisons) ]
31
+
32
+ use core:: intrinsics:: unchecked_div;
33
+ use core:: intrinsics:: unchecked_rem;
34
+ use core:: ptr;
35
+
31
36
// C API is expected to tolerate some amount of size mismatch in ABI. Hopefully the amount of
32
37
// handling is sufficient for bootstrapping.
33
38
#[ cfg( stage0) ]
@@ -112,26 +117,27 @@ pub mod reimpls {
112
117
pub extern fn u128_div_mod ( n : u128_ , d : u128_ , rem : * mut u128_ ) -> u128_ {
113
118
unsafe {
114
119
if !rem. is_null ( ) {
115
- * rem = n % d ;
120
+ * rem = unchecked_rem ( n , d ) ;
116
121
}
117
- n / d
122
+ unchecked_div ( n , d )
118
123
}
119
124
}
120
125
121
126
#[ cfg( not( stage0) ) ]
122
127
#[ export_name="__udivmodti4" ]
123
128
pub extern fn u128_div_mod ( n : u128_ , d : u128_ , rem : * mut u128_ ) -> u128_ {
129
+ // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
124
130
unsafe {
125
- // NOTE X is unknown, K != 0
131
+ // special cases, X is unknown, K != 0
126
132
if n. high ( ) == 0 {
127
133
if d. high ( ) == 0 {
128
134
// 0 X
129
135
// ---
130
136
// 0 X
131
137
if !rem. is_null ( ) {
132
- * rem = u128:: from ( n. low ( ) % d. low ( ) ) ;
138
+ * rem = u128:: from ( unchecked_rem ( n. low ( ) , d. low ( ) ) ) ;
133
139
}
134
- return u128:: from ( n. low ( ) / d. low ( ) ) ;
140
+ return u128:: from ( unchecked_div ( n. low ( ) , d. low ( ) ) ) ;
135
141
} else {
136
142
// 0 X
137
143
// ---
@@ -152,17 +158,20 @@ pub mod reimpls {
152
158
// K X
153
159
// ---
154
160
// 0 0
155
- unimplemented ( )
161
+ if !rem. is_null ( ) {
162
+ * rem = u128:: from ( unchecked_rem ( n. high ( ) , d. low ( ) ) ) ;
163
+ }
164
+ return u128:: from ( unchecked_div ( n. high ( ) , d. low ( ) ) ) ;
156
165
}
157
166
158
167
if n. low ( ) == 0 {
159
168
// K 0
160
169
// ---
161
170
// K 0
162
171
if !rem. is_null ( ) {
163
- * rem = u128:: from_parts ( 0 , n. high ( ) % d. high ( ) ) ;
172
+ * rem = u128:: from_parts ( 0 , unchecked_rem ( n. high ( ) , d. high ( ) ) ) ;
164
173
}
165
- return u128:: from ( n. high ( ) / d. high ( ) ) ;
174
+ return u128:: from ( unchecked_div ( n. high ( ) , d. high ( ) ) ) ;
166
175
}
167
176
168
177
// K K
@@ -176,6 +185,9 @@ pub mod reimpls {
176
185
return u128:: from ( n. high ( ) >> d. high ( ) . trailing_zeros ( ) ) ;
177
186
}
178
187
188
+ // K K
189
+ // ---
190
+ // K 0
179
191
sr = d. high ( ) . leading_zeros ( ) . wrapping_sub ( n. high ( ) . leading_zeros ( ) ) ;
180
192
181
193
// D > N
@@ -188,8 +200,8 @@ pub mod reimpls {
188
200
189
201
sr += 1 ;
190
202
191
- // 1 <= sr <= u32 ::bits() - 1
192
- q = n << ( 128 - sr) ;
203
+ // 1 <= sr <= u64 ::bits() - 1
204
+ q = n << ( 64 - sr) ;
193
205
r = n >> sr;
194
206
} else {
195
207
if d. high ( ) == 0 {
@@ -214,6 +226,10 @@ pub mod reimpls {
214
226
// 2 <= sr <= u64::bits() - 1
215
227
q = n << ( 128 - sr) ;
216
228
r = n >> sr;
229
+ // FIXME the C compiler-rt implementation has something here
230
+ // that looks like a speed optimisation.
231
+ // It would be worth a try to port it to Rust too and
232
+ // compare the speed.
217
233
} else {
218
234
// K X
219
235
// ---
@@ -292,23 +308,17 @@ pub mod reimpls {
292
308
let sb = b. signum ( ) ;
293
309
let a = a. abs ( ) ;
294
310
let b = b. abs ( ) ;
295
- let sr = sa ^ sb;
296
- unsafe {
297
- let mut r = :: core:: mem:: zeroed ( ) ;
298
- if sa == -1 {
299
- -( u128_div_mod ( a as u128_ , b as u128_ , & mut r) as i128_ )
300
- } else {
301
- u128_div_mod ( a as u128_ , b as u128_ , & mut r) as i128_
302
- }
311
+ let sr = sa * sb; // sign of quotient
312
+ if sr == -1 {
313
+ -( u128_div_mod ( a as u128_ , b as u128_ , ptr:: null_mut ( ) ) as i128_ )
314
+ } else {
315
+ u128_div_mod ( a as u128_ , b as u128_ , ptr:: null_mut ( ) ) as i128_
303
316
}
304
317
}
305
318
306
319
#[ export_name="__udivti3" ]
307
320
pub extern fn u128_div ( a : u128_ , b : u128_ ) -> u128_ {
308
- unsafe {
309
- let mut r = :: core:: mem:: zeroed ( ) ;
310
- u128_div_mod ( a, b, & mut r)
311
- }
321
+ u128_div_mod ( a, b, ptr:: null_mut ( ) )
312
322
}
313
323
314
324
macro_rules! mulo {
@@ -329,37 +339,32 @@ pub mod reimpls {
329
339
return result;
330
340
}
331
341
332
- let bits = :: core:: mem:: size_of:: <$ty>( ) * 8 ;
333
- let sa = a >> ( bits - 1 ) ;
334
- let abs_a = ( a ^ sa) - sa;
335
- let sb = b >> ( bits - 1 ) ;
336
- let abs_b = ( b ^ sb) - sb;
342
+ let sa = a. signum( ) ;
343
+ let abs_a = a. abs( ) ;
344
+ let sb = b. signum( ) ;
345
+ let abs_b = b. abs( ) ;
337
346
if abs_a < 2 || abs_b < 2 {
338
347
return result;
339
348
}
349
+ unsafe {
340
350
if sa == sb {
341
- if abs_a > <$ty>:: max_value( ) / abs_b {
351
+ if abs_a > unchecked_div ( <$ty>:: max_value( ) , abs_b) {
342
352
* overflow = 1 ;
343
353
}
344
354
} else {
345
- if abs_a > <$ty>:: min_value( ) / -abs_b {
355
+ if abs_a > unchecked_div ( <$ty>:: min_value( ) , -abs_b) {
346
356
* overflow = 1 ;
347
357
}
348
358
}
359
+ }
349
360
result
350
361
} }
351
362
}
352
363
353
364
// FIXME: i32 here should be c_int.
354
365
#[ export_name="__muloti4" ]
355
366
pub extern fn i128_mul_oflow ( a : i128_ , b : i128_ , o : & mut i32 ) -> i128_ {
356
- if let Some ( v) = ( a as i64 ) . checked_mul ( b as i64 ) {
357
- * o = 0 ;
358
- v as i128_
359
- } else {
360
- * o = 1 ;
361
- 0
362
- }
367
+ mulo ! ( a, b, o, i128_)
363
368
}
364
369
365
370
pub trait LargeInt {
@@ -407,7 +412,7 @@ pub mod reimpls {
407
412
self as u64
408
413
}
409
414
fn high ( self ) -> u64 {
410
- unsafe { * ( & self as * const u128 as * const u64 ) }
415
+ unsafe { * ( & self as * const u128 as * const u64 ) . offset ( 1 ) }
411
416
}
412
417
fn from_parts ( low : u64 , high : u64 ) -> u128 {
413
418
#[ repr( C , packed) ] struct Parts ( u64 , u64 ) ;
@@ -423,45 +428,49 @@ pub mod reimpls {
423
428
self as u64
424
429
}
425
430
fn high ( self ) -> i64 {
426
- unsafe { * ( & self as * const i128 as * const i64 ) }
431
+ unsafe { * ( & self as * const i128 as * const i64 ) . offset ( 1 ) }
427
432
}
428
433
fn from_parts ( low : u64 , high : i64 ) -> i128 {
429
434
u128:: from_parts ( low, high as u64 ) as i128
430
435
}
431
436
}
432
437
433
438
macro_rules! mul {
434
- ( $a: expr, $b: expr, $ty: ty) => { {
439
+ ( $a: expr, $b: expr, $ty: ty, $tyh : ty ) => { {
435
440
let ( a, b) = ( $a, $b) ;
436
- let bits = :: core:: mem:: size_of:: <$ty>( ) * 8 ;
437
- let half_bits = bits / 4 ;
441
+ let half_bits = ( :: core:: mem:: size_of:: <$tyh>( ) * 8 ) / 2 ;
438
442
let lower_mask = !0 >> half_bits;
439
443
let mut low = ( a. low( ) & lower_mask) * ( b. low( ) & lower_mask) ;
440
444
let mut t = low >> half_bits;
441
445
low &= lower_mask;
442
446
t += ( a. low( ) >> half_bits) * ( b. low( ) & lower_mask) ;
443
447
low += ( t & lower_mask) << half_bits;
444
- let mut high = t >> half_bits;
448
+ let mut high = ( t >> half_bits) as $tyh ;
445
449
t = low >> half_bits;
446
450
low &= lower_mask;
447
451
t += ( b. low( ) >> half_bits) * ( a. low( ) & lower_mask) ;
448
452
low += ( t & lower_mask) << half_bits;
449
- high += t >> half_bits;
450
- high += ( a. low( ) >> half_bits) * ( b. low( ) >> half_bits) ;
453
+ high += ( t >> half_bits) as $tyh ;
454
+ high += ( ( a. low( ) >> half_bits) * ( b. low( ) >> half_bits) ) as $tyh ;
451
455
high = high
452
456
. wrapping_add( a. high( )
453
- . wrapping_mul( b. low( ) )
454
- . wrapping_add( a. low( )
455
- . wrapping_mul( b. high( ) ) ) ) ;
457
+ . wrapping_mul( b. low( ) as $tyh ) )
458
+ . wrapping_add( ( a. low( ) as $tyh )
459
+ . wrapping_mul( b. high( ) ) ) ;
456
460
<$ty>:: from_parts( low, high)
457
461
} }
458
462
}
459
463
464
+ #[ cfg( stage0) ]
465
+ #[ export_name="__multi3" ]
466
+ pub extern fn u128_mul ( a : i128_ , b : i128_ ) -> i128_ {
467
+ ( a as i64 * b as i64 ) as i128_
468
+ }
460
469
470
+ #[ cfg( not( stage0) ) ]
461
471
#[ export_name="__multi3" ]
462
- pub extern fn u128_mul ( a : u128_ , b : u128_ ) -> u128_ {
463
- ( a as u64 * b as u64 ) as u128_
464
- // mul!(a, b, u128_)
472
+ pub extern fn u128_mul ( a : i128_ , b : i128_ ) -> i128_ {
473
+ mul ! ( a, b, i128_, i64 )
465
474
}
466
475
467
476
trait FloatStuff : Sized {
@@ -471,6 +480,7 @@ pub mod reimpls {
471
480
const MAX_EXP : i32 ;
472
481
const EXP_MASK : Self :: ToBytes ;
473
482
const MANTISSA_MASK : Self :: ToBytes ;
483
+ const MANTISSA_LEAD_BIT : Self :: ToBytes ;
474
484
475
485
fn to_bytes ( self ) -> Self :: ToBytes ;
476
486
fn get_exponent ( self ) -> i32 ;
@@ -480,8 +490,9 @@ pub mod reimpls {
480
490
type ToBytes = u32 ;
481
491
const MANTISSA_BITS : u32 = 23 ;
482
492
const MAX_EXP : i32 = 127 ;
483
- const MANTISSA_MASK : u32 = 0x007F_FFFF ;
484
493
const EXP_MASK : u32 = 0x7F80_0000 ;
494
+ const MANTISSA_MASK : u32 = 0x007F_FFFF ;
495
+ const MANTISSA_LEAD_BIT : u32 = 0x0080_0000 ;
485
496
486
497
fn to_bytes ( self ) -> u32 { unsafe { :: core:: mem:: transmute ( self ) } }
487
498
fn get_exponent ( self ) -> i32 {
@@ -495,6 +506,7 @@ pub mod reimpls {
495
506
const MAX_EXP : i32 = 1023 ;
496
507
const EXP_MASK : u64 = 0x7FF0_0000_0000_0000 ;
497
508
const MANTISSA_MASK : u64 = 0x000F_FFFF_FFFF_FFFF ;
509
+ const MANTISSA_LEAD_BIT : u64 = 0x0010_0000_0000_0000 ;
498
510
499
511
fn to_bytes ( self ) -> u64 { unsafe { :: core:: mem:: transmute ( self ) } }
500
512
fn get_exponent ( self ) -> i32 {
@@ -508,7 +520,8 @@ pub mod reimpls {
508
520
let repr = $from. to_bytes( ) ;
509
521
let sign = $from. signum( ) ;
510
522
let exponent = $from. get_exponent( ) ;
511
- let mantissa = repr & <$fromty as FloatStuff >:: MANTISSA_MASK ;
523
+ let mantissa_fraction = repr & <$fromty as FloatStuff >:: MANTISSA_MASK ;
524
+ let mantissa = mantissa_fraction | <$fromty as FloatStuff >:: MANTISSA_LEAD_BIT ;
512
525
if sign == -1.0 || exponent < 0 { return 0 ; }
513
526
if exponent > :: core:: mem:: size_of:: <$outty>( ) as i32 * 8 {
514
527
return !0 ;
@@ -537,7 +550,8 @@ pub mod reimpls {
537
550
let repr = $from. to_bytes( ) ;
538
551
let sign = $from. signum( ) ;
539
552
let exponent = $from. get_exponent( ) ;
540
- let mantissa = repr & <$fromty as FloatStuff >:: MANTISSA_MASK ;
553
+ let mantissa_fraction = repr & <$fromty as FloatStuff >:: MANTISSA_MASK ;
554
+ let mantissa = mantissa_fraction | <$fromty as FloatStuff >:: MANTISSA_LEAD_BIT ;
541
555
542
556
if exponent < 0 { return 0 ; }
543
557
if exponent > :: core:: mem:: size_of:: <$outty>( ) as i32 * 8 {
0 commit comments