Skip to content

Commit 3f719a3

Browse files
committed
Fix intrinsics and expand tests
1 parent 016a0d4 commit 3f719a3

File tree

3 files changed

+84
-54
lines changed

3 files changed

+84
-54
lines changed

src/libcompiler_builtins/lib.rs

Lines changed: 68 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@
2424

2525
#![allow(non_camel_case_types, unused_variables)]
2626

27-
2827
#[cfg(any(target_pointer_width="32", target_pointer_width="16"))]
2928
pub mod reimpls {
29+
3030
#![allow(unused_comparisons)]
31+
32+
use core::intrinsics::unchecked_div;
33+
use core::intrinsics::unchecked_rem;
34+
use core::ptr;
35+
3136
// C API is expected to tolerate some amount of size mismatch in ABI. Hopefully the amount of
3237
// handling is sufficient for bootstrapping.
3338
#[cfg(stage0)]
@@ -112,26 +117,27 @@ pub mod reimpls {
112117
pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ {
113118
unsafe {
114119
if !rem.is_null() {
115-
*rem = n % d;
120+
*rem = unchecked_rem(n, d);
116121
}
117-
n / d
122+
unchecked_div(n, d)
118123
}
119124
}
120125

121126
#[cfg(not(stage0))]
122127
#[export_name="__udivmodti4"]
123128
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
124130
unsafe {
125-
// NOTE X is unknown, K != 0
131+
// special cases, X is unknown, K != 0
126132
if n.high() == 0 {
127133
if d.high() == 0 {
128134
// 0 X
129135
// ---
130136
// 0 X
131137
if !rem.is_null() {
132-
*rem = u128::from(n.low() % d.low());
138+
*rem = u128::from(unchecked_rem(n.low(), d.low()));
133139
}
134-
return u128::from(n.low() / d.low());
140+
return u128::from(unchecked_div(n.low(), d.low()));
135141
} else {
136142
// 0 X
137143
// ---
@@ -152,17 +158,20 @@ pub mod reimpls {
152158
// K X
153159
// ---
154160
// 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()));
156165
}
157166

158167
if n.low() == 0 {
159168
// K 0
160169
// ---
161170
// K 0
162171
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()));
164173
}
165-
return u128::from(n.high() / d.high());
174+
return u128::from(unchecked_div(n.high(), d.high()));
166175
}
167176

168177
// K K
@@ -176,6 +185,9 @@ pub mod reimpls {
176185
return u128::from(n.high() >> d.high().trailing_zeros());
177186
}
178187

188+
// K K
189+
// ---
190+
// K 0
179191
sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());
180192

181193
// D > N
@@ -188,8 +200,8 @@ pub mod reimpls {
188200

189201
sr += 1;
190202

191-
// 1 <= sr <= u32::bits() - 1
192-
q = n << (128 - sr);
203+
// 1 <= sr <= u64::bits() - 1
204+
q = n << (64 - sr);
193205
r = n >> sr;
194206
} else {
195207
if d.high() == 0 {
@@ -214,6 +226,10 @@ pub mod reimpls {
214226
// 2 <= sr <= u64::bits() - 1
215227
q = n << (128 - sr);
216228
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.
217233
} else {
218234
// K X
219235
// ---
@@ -292,23 +308,17 @@ pub mod reimpls {
292308
let sb = b.signum();
293309
let a = a.abs();
294310
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_
303316
}
304317
}
305318

306319
#[export_name="__udivti3"]
307320
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())
312322
}
313323

314324
macro_rules! mulo {
@@ -329,37 +339,32 @@ pub mod reimpls {
329339
return result;
330340
}
331341

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();
337346
if abs_a < 2 || abs_b < 2 {
338347
return result;
339348
}
349+
unsafe {
340350
if sa == sb {
341-
if abs_a > <$ty>::max_value() / abs_b {
351+
if abs_a > unchecked_div(<$ty>::max_value(), abs_b) {
342352
*overflow = 1;
343353
}
344354
} else {
345-
if abs_a > <$ty>::min_value() / -abs_b {
355+
if abs_a > unchecked_div(<$ty>::min_value(), -abs_b) {
346356
*overflow = 1;
347357
}
348358
}
359+
}
349360
result
350361
}}
351362
}
352363

353364
// FIXME: i32 here should be c_int.
354365
#[export_name="__muloti4"]
355366
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_)
363368
}
364369

365370
pub trait LargeInt {
@@ -407,7 +412,7 @@ pub mod reimpls {
407412
self as u64
408413
}
409414
fn high(self) -> u64 {
410-
unsafe { *(&self as *const u128 as *const u64) }
415+
unsafe { *(&self as *const u128 as *const u64).offset(1) }
411416
}
412417
fn from_parts(low: u64, high: u64) -> u128 {
413418
#[repr(C, packed)] struct Parts(u64, u64);
@@ -423,45 +428,49 @@ pub mod reimpls {
423428
self as u64
424429
}
425430
fn high(self) -> i64 {
426-
unsafe { *(&self as *const i128 as *const i64) }
431+
unsafe { *(&self as *const i128 as *const i64).offset(1) }
427432
}
428433
fn from_parts(low: u64, high: i64) -> i128 {
429434
u128::from_parts(low, high as u64) as i128
430435
}
431436
}
432437

433438
macro_rules! mul {
434-
($a:expr, $b:expr, $ty: ty) => {{
439+
($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{
435440
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;
438442
let lower_mask = !0 >> half_bits;
439443
let mut low = (a.low() & lower_mask) * (b.low() & lower_mask);
440444
let mut t = low >> half_bits;
441445
low &= lower_mask;
442446
t += (a.low() >> half_bits) * (b.low() & lower_mask);
443447
low += (t & lower_mask) << half_bits;
444-
let mut high = t >> half_bits;
448+
let mut high = (t >> half_bits) as $tyh;
445449
t = low >> half_bits;
446450
low &= lower_mask;
447451
t += (b.low() >> half_bits) * (a.low() & lower_mask);
448452
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;
451455
high = high
452456
.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()));
456460
<$ty>::from_parts(low, high)
457461
}}
458462
}
459463

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+
}
460469

470+
#[cfg(not(stage0))]
461471
#[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)
465474
}
466475

467476
trait FloatStuff: Sized {
@@ -471,6 +480,7 @@ pub mod reimpls {
471480
const MAX_EXP: i32;
472481
const EXP_MASK: Self::ToBytes;
473482
const MANTISSA_MASK: Self::ToBytes;
483+
const MANTISSA_LEAD_BIT: Self::ToBytes;
474484

475485
fn to_bytes(self) -> Self::ToBytes;
476486
fn get_exponent(self) -> i32;
@@ -480,8 +490,9 @@ pub mod reimpls {
480490
type ToBytes = u32;
481491
const MANTISSA_BITS: u32 = 23;
482492
const MAX_EXP: i32 = 127;
483-
const MANTISSA_MASK: u32 = 0x007F_FFFF;
484493
const EXP_MASK: u32 = 0x7F80_0000;
494+
const MANTISSA_MASK: u32 = 0x007F_FFFF;
495+
const MANTISSA_LEAD_BIT: u32 = 0x0080_0000;
485496

486497
fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } }
487498
fn get_exponent(self) -> i32 {
@@ -495,6 +506,7 @@ pub mod reimpls {
495506
const MAX_EXP: i32 = 1023;
496507
const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
497508
const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;
509+
const MANTISSA_LEAD_BIT: u64 = 0x0010_0000_0000_0000;
498510

499511
fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } }
500512
fn get_exponent(self) -> i32 {
@@ -508,7 +520,8 @@ pub mod reimpls {
508520
let repr = $from.to_bytes();
509521
let sign = $from.signum();
510522
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;
512525
if sign == -1.0 || exponent < 0 { return 0; }
513526
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
514527
return !0;
@@ -537,7 +550,8 @@ pub mod reimpls {
537550
let repr = $from.to_bytes();
538551
let sign = $from.signum();
539552
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;
541555

542556
if exponent < 0 { return 0; }
543557
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {

src/test/run-pass/i128.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ fn main() {
1818
let y: i128 = -2;
1919
assert_eq!(!1, y);
2020
let z: i128 = 0xABCD_EF;
21+
assert_eq!(z * z, 0x734C_C2F2_A521);
22+
assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41);
23+
assert_eq!(-z * -z, 0x734C_C2F2_A521);
2124
assert_eq!(-z * -z * -z * -z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41);
2225
assert_eq!(-z + -z + -z + -z, -0x2AF3_7BC);
2326
let k: i128 = -0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210;
@@ -38,6 +41,10 @@ fn main() {
3841
assert_eq!(k as i64, -0xFEDC_BA98_7654_3210);
3942
assert_eq!(k as u128, 0xFEDC_BA98_7654_3210_0123_4567_89AB_CDF0);
4043
assert_eq!(-k as u128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210);
44+
assert_eq!((-z as f64) as i128, -z);
45+
assert_eq!((-z as f32) as i128, -z);
46+
assert_eq!((-z as f64 * 16.0) as i128, -z * 16);
47+
assert_eq!((-z as f32 * 16.0) as i128, -z * 16);
4148
// formatting
4249
let j: i128 = -(1 << 67);
4350
assert_eq!("-147573952589676412928", format!("{}", j));

src/test/run-pass/u128.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fn main() {
2323
y &
2424
0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF);
2525
let z: u128 = 0xABCD_EF;
26+
assert_eq!(z * z, 0x734C_C2F2_A521);
2627
assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41);
2728
assert_eq!(z + z + z + z, 0x2AF3_7BC);
2829
let k: u128 = 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210;
@@ -34,6 +35,7 @@ fn main() {
3435
assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42);
3536
assert_eq!(0, k % 42);
3637
assert_eq!(15, z % 42);
38+
assert_eq!(0x169D_A8020_CEC18, k % 0x3ACB_FE49_FF24_AC);
3739
assert_eq!(0x91A2_B3C4_D5E6_F7, k >> 65);
3840
assert_eq!(0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65);
3941
assert!(k > z);
@@ -43,6 +45,13 @@ fn main() {
4345
assert_eq!(z as u64, 0xABCD_EF);
4446
assert_eq!(k as u64, 0xFEDC_BA98_7654_3210);
4547
assert_eq!(k as i128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210);
48+
assert_eq!((z as f64) as u128, z);
49+
assert_eq!((z as f32) as u128, z);
50+
assert_eq!((z as f64 * 16.0) as u128, z * 16);
51+
assert_eq!((z as f32 * 16.0) as u128, z * 16);
52+
let l :u128 = 432 << 100;
53+
assert_eq!((l as f32) as u128, l);
54+
assert_eq!((l as f64) as u128, l);
4655
// formatting
4756
let j: u128 = 1 << 67;
4857
assert_eq!("147573952589676412928", format!("{}", j));

0 commit comments

Comments
 (0)