55 lines
2.0 KiB
Rust
55 lines
2.0 KiB
Rust
use rand_xoshiro::rand_core::{RngCore, SeedableRng};
|
|
use rand_xoshiro::Xoshiro128StarStar;
|
|
|
|
use compiler_builtins::int::__clzsi2;
|
|
use compiler_builtins::int::leading_zeros::{
|
|
usize_leading_zeros_default, usize_leading_zeros_riscv,
|
|
};
|
|
|
|
#[test]
|
|
fn __clzsi2_test() {
|
|
// Binary fuzzer. We cannot just send a random number directly to `__clzsi2()`, because we need
|
|
// large sequences of zeros to test. This XORs, ANDs, and ORs random length strings of 1s to
|
|
// `x`. ORs insure sequences of ones, ANDs insures sequences of zeros, and XORs are not often
|
|
// destructive but add entropy.
|
|
let mut rng = Xoshiro128StarStar::seed_from_u64(0);
|
|
let mut x = 0usize;
|
|
// creates a mask for indexing the bits of the type
|
|
let bit_indexing_mask = usize::MAX.count_ones() - 1;
|
|
// 10000 iterations is enough to make sure edge cases like single set bits are tested and to go
|
|
// through many paths.
|
|
for _ in 0..10_000 {
|
|
let r0 = bit_indexing_mask & rng.next_u32();
|
|
// random length of ones
|
|
let ones: usize = !0 >> r0;
|
|
let r1 = bit_indexing_mask & rng.next_u32();
|
|
// random circular shift
|
|
let mask = ones.rotate_left(r1);
|
|
match rng.next_u32() % 4 {
|
|
0 => x |= mask,
|
|
1 => x &= mask,
|
|
// both 2 and 3 to make XORs as common as ORs and ANDs combined
|
|
_ => x ^= mask,
|
|
}
|
|
let lz = x.leading_zeros() as usize;
|
|
let lz0 = __clzsi2(x);
|
|
let lz1 = usize_leading_zeros_default(x);
|
|
let lz2 = usize_leading_zeros_riscv(x);
|
|
if lz0 != lz {
|
|
panic!("__clzsi2({}): expected: {}, found: {}", x, lz, lz0);
|
|
}
|
|
if lz1 != lz {
|
|
panic!(
|
|
"usize_leading_zeros_default({}): expected: {}, found: {}",
|
|
x, lz, lz1
|
|
);
|
|
}
|
|
if lz2 != lz {
|
|
panic!(
|
|
"usize_leading_zeros_riscv({}): expected: {}, found: {}",
|
|
x, lz, lz2
|
|
);
|
|
}
|
|
}
|
|
}
|