Skip to content

Commit b1a7a00

Browse files
committed
Introduce the DInt and HInt traits
and add various methods that will be used for improved fuzzing
1 parent 080f6d3 commit b1a7a00

File tree

1 file changed

+202
-1
lines changed

1 file changed

+202
-1
lines changed

src/int/mod.rs

Lines changed: 202 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ pub mod udiv;
1212
pub use self::leading_zeros::__clzsi2;
1313

1414
/// Trait for some basic operations on integers
15-
pub(crate) trait Int:
15+
#[doc(hidden)]
16+
pub trait Int:
1617
Copy
1718
+ PartialEq
1819
+ PartialOrd
1920
+ ops::AddAssign
2021
+ ops::BitAndAssign
2122
+ ops::BitOrAssign
23+
+ ops::BitXorAssign
2224
+ ops::ShlAssign<i32>
2325
+ ops::ShrAssign<u32>
2426
+ ops::Add<Output = Self>
@@ -41,6 +43,14 @@ pub(crate) trait Int:
4143

4244
const ZERO: Self;
4345
const ONE: Self;
46+
const MIN: Self;
47+
48+
/// LUT used for maximizing the space covered and minimizing the computational cost of fuzzing
49+
/// in `testcrate`. For example, Self = u128 produces [0,1,2,7,8,15,16,31,32,63,64,95,96,111,
50+
/// 112,119,120,125,126,127].
51+
const FUZZ_LENGTHS: [u8; 20];
52+
/// The number of entries of `FUZZ_LENGTHS` actually used. The maximum is 20 for u128.
53+
const FUZZ_NUM: usize;
4454

4555
/// Extracts the sign from self and returns a tuple.
4656
///
@@ -59,17 +69,25 @@ pub(crate) trait Int:
5969

6070
fn from_bool(b: bool) -> Self;
6171

72+
/// Prevents the need for excessive conversions between signed and unsigned
73+
fn logical_shr(self, other: u32) -> Self;
74+
6275
// copied from primitive integers, but put in a trait
76+
fn is_zero(self) -> bool;
6377
fn max_value() -> Self;
6478
fn min_value() -> Self;
79+
fn wrapping_neg(self) -> Self;
6580
fn wrapping_add(self, other: Self) -> Self;
6681
fn wrapping_mul(self, other: Self) -> Self;
6782
fn wrapping_sub(self, other: Self) -> Self;
6883
fn wrapping_shl(self, other: u32) -> Self;
84+
fn wrapping_shr(self, other: u32) -> Self;
85+
fn rotate_left(self, other: u32) -> Self;
6986
fn overflowing_add(self, other: Self) -> (Self, bool);
7087
fn aborting_div(self, other: Self) -> Self;
7188
fn aborting_rem(self, other: Self) -> Self;
7289
fn leading_zeros(self) -> u32;
90+
fn count_ones(self) -> u32;
7391
}
7492

7593
fn unwrap<T>(t: Option<T>) -> T {
@@ -85,11 +103,78 @@ macro_rules! int_impl_common {
85103

86104
const ZERO: Self = 0;
87105
const ONE: Self = 1;
106+
const MIN: Self = <Self>::MIN;
107+
108+
const FUZZ_LENGTHS: [u8; 20] = {
109+
let bits = <Self as Int>::BITS;
110+
let mut v = [0u8; 20];
111+
v[0] = 0;
112+
v[1] = 1;
113+
v[2] = 2; // important for parity and the iX::MIN case when reversed
114+
let mut i = 3;
115+
// No need for any more until the byte boundary, because there should be no algorithms
116+
// that are sensitive to anything not next to byte boundaries after 2. We also scale
117+
// in powers of two, which is important to prevent u128 corner tests from getting too
118+
// big.
119+
let mut l = 8;
120+
loop {
121+
if l >= ((bits / 2) as u8) {
122+
break;
123+
}
124+
// get both sides of the byte boundary
125+
v[i] = l - 1;
126+
i += 1;
127+
v[i] = l;
128+
i += 1;
129+
l *= 2;
130+
}
131+
132+
if bits != 8 {
133+
// add the lower side of the middle boundary
134+
v[i] = ((bits / 2) - 1) as u8;
135+
i += 1;
136+
}
137+
138+
// We do not want to jump directly from the Self::BITS/2 boundary to the Self::BITS
139+
// boundary because of algorithms that split the high part up. We reverse the scaling
140+
// as we go to Self::BITS.
141+
let mid = i;
142+
let mut j = 1;
143+
loop {
144+
v[i] = (bits as u8) - (v[mid - j]) - 1;
145+
if j == mid {
146+
break;
147+
}
148+
i += 1;
149+
j += 1;
150+
}
151+
v
152+
};
153+
154+
const FUZZ_NUM: usize = {
155+
let log2 = (<Self as Int>::BITS - 1).count_ones() as usize;
156+
if log2 == 3 {
157+
// case for u8
158+
6
159+
} else {
160+
// 3 entries on each extreme, 2 in the middle, and 4 for each scale of intermediate
161+
// boundaries.
162+
8 + (4 * (log2 - 4))
163+
}
164+
};
88165

89166
fn from_bool(b: bool) -> Self {
90167
b as $ty
91168
}
92169

170+
fn logical_shr(self, other: u32) -> Self {
171+
Self::from_unsigned(self.unsigned().wrapping_shr(other))
172+
}
173+
174+
fn is_zero(self) -> bool {
175+
self == Self::ZERO
176+
}
177+
93178
fn max_value() -> Self {
94179
<Self>::max_value()
95180
}
@@ -98,6 +183,10 @@ macro_rules! int_impl_common {
98183
<Self>::min_value()
99184
}
100185

186+
fn wrapping_neg(self) -> Self {
187+
<Self>::wrapping_neg(self)
188+
}
189+
101190
fn wrapping_add(self, other: Self) -> Self {
102191
<Self>::wrapping_add(self, other)
103192
}
@@ -114,6 +203,14 @@ macro_rules! int_impl_common {
114203
<Self>::wrapping_shl(self, other)
115204
}
116205

206+
fn wrapping_shr(self, other: u32) -> Self {
207+
<Self>::wrapping_shr(self, other)
208+
}
209+
210+
fn rotate_left(self, other: u32) -> Self {
211+
<Self>::rotate_left(self, other)
212+
}
213+
117214
fn overflowing_add(self, other: Self) -> (Self, bool) {
118215
<Self>::overflowing_add(self, other)
119216
}
@@ -129,6 +226,10 @@ macro_rules! int_impl_common {
129226
fn leading_zeros(self) -> u32 {
130227
<Self>::leading_zeros(self)
131228
}
229+
230+
fn count_ones(self) -> u32 {
231+
<Self>::count_ones(self)
232+
}
132233
};
133234
}
134235

@@ -178,11 +279,111 @@ macro_rules! int_impl {
178279
};
179280
}
180281

282+
int_impl!(isize, usize, usize::MAX.count_ones());
283+
int_impl!(i8, u8, 8);
181284
int_impl!(i16, u16, 16);
182285
int_impl!(i32, u32, 32);
183286
int_impl!(i64, u64, 64);
184287
int_impl!(i128, u128, 128);
185288

289+
/// Trait for integers twice the bit width of another integer. This is implemented for all
290+
/// primitives except for `u8`, because there is not a smaller primitive.
291+
#[doc(hidden)]
292+
pub trait DInt: Int {
293+
/// Integer that is half the bit width of the integer this trait is implemented for
294+
type H: HInt<D = Self> + Int;
295+
296+
/// Returns the low half of `self`
297+
fn lo(self) -> Self::H;
298+
/// Returns the high half of `self`
299+
fn hi(self) -> Self::H;
300+
/// Returns the low and high halves of `self` as a tuple
301+
fn lo_hi(self) -> (Self::H, Self::H);
302+
/// Constructs an integer using lower and higher half parts
303+
fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self;
304+
}
305+
306+
/// Trait for integers half the bit width of another integer. This is implemented for all
307+
/// primitives except for `u128`, because it there is not a larger primitive.
308+
#[doc(hidden)]
309+
pub trait HInt: Int {
310+
/// Integer that is double the bit width of the integer this trait is implemented for
311+
type D: DInt<H = Self> + Int;
312+
313+
/// Widens (using default extension) the integer to have double bit width
314+
fn widen(self) -> Self::D;
315+
/// Widens (zero extension only) the integer to have double bit width. This is needed to get
316+
/// around problems with associated type bounds (such as `Int<Othersign: DInt>`) being unstable
317+
fn zero_widen(self) -> Self::D;
318+
/// Widens the integer to have double bit width and shifts the integer into the higher bits
319+
fn widen_hi(self) -> Self::D;
320+
/// Widening multiplication with zero widening. This cannot overflow.
321+
fn zero_widen_mul(self, rhs: Self) -> Self::D;
322+
/// Widening multiplication. This cannot overflow.
323+
fn widen_mul(self, rhs: Self) -> Self::D;
324+
}
325+
326+
macro_rules! impl_d_int {
327+
($($X:ident $D:ident),*) => {
328+
$(
329+
impl DInt for $D {
330+
type H = $X;
331+
332+
fn lo(self) -> Self::H {
333+
self as $X
334+
}
335+
fn hi(self) -> Self::H {
336+
(self >> <$X as Int>::BITS) as $X
337+
}
338+
fn lo_hi(self) -> (Self::H, Self::H) {
339+
(self.lo(), self.hi())
340+
}
341+
fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self {
342+
lo.zero_widen() | hi.widen_hi()
343+
}
344+
}
345+
)*
346+
};
347+
}
348+
349+
macro_rules! impl_h_int {
350+
($($H:ident $uH:ident $X:ident),*) => {
351+
$(
352+
impl HInt for $H {
353+
type D = $X;
354+
355+
fn widen(self) -> Self::D {
356+
self as $X
357+
}
358+
fn zero_widen(self) -> Self::D {
359+
(self as $uH) as $X
360+
}
361+
fn widen_hi(self) -> Self::D {
362+
(self as $X) << <$H as Int>::BITS
363+
}
364+
fn zero_widen_mul(self, rhs: Self) -> Self::D {
365+
self.zero_widen().wrapping_mul(rhs.zero_widen())
366+
}
367+
fn widen_mul(self, rhs: Self) -> Self::D {
368+
self.widen().wrapping_mul(rhs.widen())
369+
}
370+
}
371+
)*
372+
};
373+
}
374+
375+
impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128);
376+
impl_h_int!(
377+
u8 u8 u16,
378+
u16 u16 u32,
379+
u32 u32 u64,
380+
u64 u64 u128,
381+
i8 u8 i16,
382+
i16 u16 i32,
383+
i32 u32 i64,
384+
i64 u64 i128
385+
);
386+
186387
/// Trait to convert an integer to/from smaller parts
187388
pub(crate) trait LargeInt: Int {
188389
type LowHalf: Int;

0 commit comments

Comments
 (0)