Skip to content

Commit 02a05b1

Browse files
committed
cleanup: Reuse MinInt and Int from libm in compiler-builtins
1 parent b5f8003 commit 02a05b1

File tree

12 files changed

+166
-344
lines changed

12 files changed

+166
-344
lines changed

builtins-test/src/lib.rs

+72-5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,74 @@ pub const N: u32 = if cfg!(target_arch = "x86_64") && !cfg!(debug_assertions) {
4040
10_000
4141
};
4242

43+
trait FuzzInt: MinInt {
44+
/// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing
45+
/// in `builtins-test`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,
46+
/// 111,112,119,120,125,126,127].
47+
const FUZZ_LENGTHS: [u8; 20] = make_fuzz_lengths(<Self as MinInt>::BITS);
48+
49+
/// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128.
50+
const FUZZ_NUM: usize = {
51+
let log2 = (<Self as MinInt>::BITS - 1).count_ones() as usize;
52+
if log2 == 3 {
53+
// case for u8
54+
6
55+
} else {
56+
// 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate
57+
// boundaries.
58+
8 + (4 * (log2 - 4))
59+
}
60+
};
61+
}
62+
63+
impl<I> FuzzInt for I where I: MinInt {}
64+
65+
const fn make_fuzz_lengths(bits: u32) -> [u8; 20] {
66+
let mut v = [0u8; 20];
67+
v[0] = 0;
68+
v[1] = 1;
69+
v[2] = 2; // important for parity and the iX::MIN case when reversed
70+
let mut i = 3;
71+
72+
// No need for any more until the byte boundary, because there should be no algorithms
73+
// that are sensitive to anything not next to byte boundaries after 2. We also scale
74+
// in powers of two, which is important to prevent u128 corner tests from getting too
75+
// big.
76+
let mut l = 8;
77+
loop {
78+
if l >= ((bits / 2) as u8) {
79+
break;
80+
}
81+
// get both sides of the byte boundary
82+
v[i] = l - 1;
83+
i += 1;
84+
v[i] = l;
85+
i += 1;
86+
l *= 2;
87+
}
88+
89+
if bits != 8 {
90+
// add the lower side of the middle boundary
91+
v[i] = ((bits / 2) - 1) as u8;
92+
i += 1;
93+
}
94+
95+
// We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS
96+
// boundary because of algorithms that split the high part up. We reverse the scaling
97+
// as we go to Self::BITS.
98+
let mid = i;
99+
let mut j = 1;
100+
loop {
101+
v[i] = (bits as u8) - (v[mid - j]) - 1;
102+
if j == mid {
103+
break;
104+
}
105+
i += 1;
106+
j += 1;
107+
}
108+
v
109+
}
110+
43111
/// Random fuzzing step. When run several times, it results in excellent fuzzing entropy such as:
44112
/// 11110101010101011110111110011111
45113
/// 10110101010100001011101011001010
@@ -92,10 +160,9 @@ fn fuzz_step<I: Int>(rng: &mut Xoshiro128StarStar, x: &mut I) {
92160
macro_rules! edge_cases {
93161
($I:ident, $case:ident, $inner:block) => {
94162
for i0 in 0..$I::FUZZ_NUM {
95-
let mask_lo = (!$I::UnsignedInt::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32);
163+
let mask_lo = (!$I::Unsigned::ZERO).wrapping_shr($I::FUZZ_LENGTHS[i0] as u32);
96164
for i1 in i0..I::FUZZ_NUM {
97-
let mask_hi =
98-
(!$I::UnsignedInt::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32);
165+
let mask_hi = (!$I::Unsigned::ZERO).wrapping_shl($I::FUZZ_LENGTHS[i1 - i0] as u32);
99166
let $case = I::from_unsigned(mask_lo & mask_hi);
100167
$inner
101168
}
@@ -107,7 +174,7 @@ macro_rules! edge_cases {
107174
/// edge cases, followed by a more random fuzzer that runs `n` times.
108175
pub fn fuzz<I: Int, F: FnMut(I)>(n: u32, mut f: F)
109176
where
110-
<I as MinInt>::UnsignedInt: Int,
177+
<I as MinInt>::Unsigned: Int,
111178
{
112179
// edge case tester. Calls `f` 210 times for u128.
113180
// zero gets skipped by the loop
@@ -128,7 +195,7 @@ where
128195
/// The same as `fuzz`, except `f` has two inputs.
129196
pub fn fuzz_2<I: Int, F: Fn(I, I)>(n: u32, f: F)
130197
where
131-
<I as MinInt>::UnsignedInt: Int,
198+
<I as MinInt>::Unsigned: Int,
132199
{
133200
// Check cases where the first and second inputs are zero. Both call `f` 210 times for `u128`.
134201
edge_cases!(I, case, {

compiler-builtins/src/float/add.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::float::Float;
2-
use crate::int::{CastInto, Int, MinInt};
2+
use crate::int::{CastFrom, CastInto, Int, MinInt};
33

44
/// Returns `a + b`
55
fn add<F: Float>(a: F, b: F) -> F
@@ -12,7 +12,7 @@ where
1212
let one = F::Int::ONE;
1313
let zero = F::Int::ZERO;
1414

15-
let bits = F::BITS.cast();
15+
let bits: F::Int = F::BITS.cast();
1616
let significand_bits = F::SIG_BITS;
1717
let max_exponent = F::EXP_SAT;
1818

@@ -115,9 +115,10 @@ where
115115
let align = a_exponent.wrapping_sub(b_exponent).cast();
116116
if align != MinInt::ZERO {
117117
if align < bits {
118-
let sticky =
119-
F::Int::from_bool(b_significand << bits.wrapping_sub(align).cast() != MinInt::ZERO);
120-
b_significand = (b_significand >> align.cast()) | sticky;
118+
let sticky = F::Int::from_bool(
119+
b_significand << u32::cast_from(bits.wrapping_sub(align)) != MinInt::ZERO,
120+
);
121+
b_significand = (b_significand >> u32::cast_from(align)) | sticky;
121122
} else {
122123
b_significand = one; // sticky; b is known to be non-zero.
123124
}
@@ -132,8 +133,8 @@ where
132133
// If partial cancellation occured, we need to left-shift the result
133134
// and adjust the exponent:
134135
if a_significand < implicit_bit << 3 {
135-
let shift =
136-
a_significand.leading_zeros() as i32 - (implicit_bit << 3).leading_zeros() as i32;
136+
let shift = a_significand.leading_zeros() as i32
137+
- (implicit_bit << 3u32).leading_zeros() as i32;
137138
a_significand <<= shift;
138139
a_exponent -= shift;
139140
}
@@ -159,9 +160,10 @@ where
159160
// Result is denormal before rounding; the exponent is zero and we
160161
// need to shift the significand.
161162
let shift = (1 - a_exponent).cast();
162-
let sticky =
163-
F::Int::from_bool((a_significand << bits.wrapping_sub(shift).cast()) != MinInt::ZERO);
164-
a_significand = (a_significand >> shift.cast()) | sticky;
163+
let sticky = F::Int::from_bool(
164+
(a_significand << u32::cast_from(bits.wrapping_sub(shift))) != MinInt::ZERO,
165+
);
166+
a_significand = (a_significand >> u32::cast_from(shift)) | sticky;
165167
a_exponent = 0;
166168
}
167169

compiler-builtins/src/float/conv.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ mod int_to_float {
7272
F: Float,
7373
I: Int,
7474
F::Int: CastFrom<I>,
75-
Conv: Fn(I::UnsignedInt) -> F::Int,
75+
Conv: Fn(I::Unsigned) -> F::Int,
7676
{
7777
let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1);
7878
F::from_bits(conv(i.unsigned_abs()) | sign_bit)
@@ -313,10 +313,10 @@ intrinsics! {
313313
fn float_to_unsigned_int<F, U>(f: F) -> U
314314
where
315315
F: Float,
316-
U: Int<UnsignedInt = U>,
316+
U: Int<Unsigned = U>,
317317
F::Int: CastInto<U>,
318318
F::Int: CastFrom<u32>,
319-
F::Int: CastInto<U::UnsignedInt>,
319+
F::Int: CastInto<U::Unsigned>,
320320
u32: CastFrom<F::Int>,
321321
{
322322
float_to_int_inner::<F, U, _, _>(f.to_bits(), |i: U| i, || U::MAX)
@@ -327,8 +327,8 @@ fn float_to_signed_int<F, I>(f: F) -> I
327327
where
328328
F: Float,
329329
I: Int + Neg<Output = I>,
330-
I::UnsignedInt: Int,
331-
F::Int: CastInto<I::UnsignedInt>,
330+
I::Unsigned: Int,
331+
F::Int: CastInto<I::Unsigned>,
332332
F::Int: CastFrom<u32>,
333333
u32: CastFrom<F::Int>,
334334
{
@@ -355,27 +355,27 @@ where
355355
I: Int,
356356
FnFoo: FnOnce(I) -> I,
357357
FnOob: FnOnce() -> I,
358-
I::UnsignedInt: Int,
359-
F::Int: CastInto<I::UnsignedInt>,
358+
I::Unsigned: Int,
359+
F::Int: CastInto<I::Unsigned>,
360360
F::Int: CastFrom<u32>,
361361
u32: CastFrom<F::Int>,
362362
{
363363
let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1;
364-
let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1;
364+
let foobar = F::EXP_BIAS + I::Unsigned::BITS - 1;
365365

366366
if fbits < F::ONE.to_bits() {
367367
// < 0 gets rounded to 0
368368
I::ZERO
369369
} else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS {
370370
// >= 1, < integer max
371-
let m_base = if I::UnsignedInt::BITS >= F::Int::BITS {
372-
I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1)
371+
let m_base = if I::Unsigned::BITS >= F::Int::BITS {
372+
I::Unsigned::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1)
373373
} else {
374-
I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1))
374+
I::Unsigned::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1))
375375
};
376376

377377
// Set the implicit 1-bit.
378-
let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base;
378+
let m: I::Unsigned = (I::Unsigned::ONE << (I::BITS - 1)) | m_base;
379379

380380
// Shift based on the exponent and bias.
381381
let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS);

compiler-builtins/src/float/div.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ where
370370
let hi_corr: F::Int = corr_uq1 >> hw;
371371

372372
// x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1
373-
let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1)
373+
let mut x_uq0: F::Int = ((F::Int::from(x_uq0_hw) * hi_corr) << 1u32)
374374
.wrapping_add((F::Int::from(x_uq0_hw) * lo_corr) >> (hw - 1))
375375
// 1 to account for the highest bit of corr_UQ1 can be 1
376376
// 1 to account for possible carry

compiler-builtins/src/float/mul.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ where
143143
// a zero of the appropriate sign. Mathematically there is no need to
144144
// handle this case separately, but we make it a special case to
145145
// simplify the shift logic.
146-
let shift = one.wrapping_sub(product_exponent.cast()).cast();
146+
let shift: u32 = one.wrapping_sub(product_exponent.cast()).cast();
147147
if shift >= bits {
148148
return F::from_bits(product_sign);
149149
}

compiler-builtins/src/float/traits.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ pub trait Float:
2020
+ ops::Rem<Output = Self>
2121
{
2222
/// A uint of the same width as the float
23-
type Int: Int<OtherSign = Self::SignedInt, UnsignedInt = Self::Int>;
23+
type Int: Int<OtherSign = Self::SignedInt, Unsigned = Self::Int>;
2424

2525
/// A int of the same width as the float
26-
type SignedInt: Int + MinInt<OtherSign = Self::Int, UnsignedInt = Self::Int>;
26+
type SignedInt: Int + MinInt<OtherSign = Self::Int, Unsigned = Self::Int>;
2727

2828
/// An int capable of containing the exponent bits plus a sign bit. This is signed.
2929
type ExpInt: Int;

compiler-builtins/src/int/addsub.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl UAddSub for u128 {}
2222

2323
trait AddSub: Int
2424
where
25-
<Self as MinInt>::UnsignedInt: UAddSub,
25+
<Self as MinInt>::Unsigned: UAddSub,
2626
{
2727
fn add(self, other: Self) -> Self {
2828
Self::from_unsigned(self.unsigned().uadd(other.unsigned()))
@@ -37,7 +37,7 @@ impl AddSub for i128 {}
3737

3838
trait Addo: AddSub
3939
where
40-
<Self as MinInt>::UnsignedInt: UAddSub,
40+
<Self as MinInt>::Unsigned: UAddSub,
4141
{
4242
fn addo(self, other: Self) -> (Self, bool) {
4343
let sum = AddSub::add(self, other);
@@ -50,7 +50,7 @@ impl Addo for u128 {}
5050

5151
trait Subo: AddSub
5252
where
53-
<Self as MinInt>::UnsignedInt: UAddSub,
53+
<Self as MinInt>::Unsigned: UAddSub,
5454
{
5555
fn subo(self, other: Self) -> (Self, bool) {
5656
let sum = AddSub::sub(self, other);

compiler-builtins/src/int/big.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl i256 {
4545
impl MinInt for u256 {
4646
type OtherSign = i256;
4747

48-
type UnsignedInt = u256;
48+
type Unsigned = u256;
4949

5050
const SIGNED: bool = false;
5151
const BITS: u32 = 256;
@@ -58,7 +58,7 @@ impl MinInt for u256 {
5858
impl MinInt for i256 {
5959
type OtherSign = u256;
6060

61-
type UnsignedInt = u256;
61+
type Unsigned = u256;
6262

6363
const SIGNED: bool = false;
6464
const BITS: u32 = 256;

0 commit comments

Comments
 (0)