Rollup merge of #149539 - quaternic:gather-scatter-bits, r=Mark-Simulacrum

Additional test for uN::{gather,scatter}_bits

Feature gate: #![feature(uint_gather_scatter_bits)]
Tracking issue: https://github.com/rust-lang/rust/issues/149069
Accepted ACP: https://github.com/rust-lang/libs-team/issues/695#issuecomment-3549284861

Adds an additional runtime test for `uN::gather_bits` and `uN::scatter_bits` in coretests. They are each other's inverses in a sense, so a shared test can test both with relative ease.

I plan to follow up with optimized implementations for these functions.
This commit is contained in:
Matthias Krüger 2025-12-04 08:46:22 +01:00 committed by GitHub
commit 8fe12253f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -387,6 +387,68 @@ macro_rules! uint_module {
}
}
#[cfg(not(miri))] // Miri is too slow
#[test]
fn test_lots_of_gather_scatter() {
// Generate a handful of bit patterns to use as inputs
let xs = {
let mut xs = vec![];
let mut x: $T = !0;
let mut w = $T::BITS;
while w > 0 {
w >>= 1;
xs.push(x);
xs.push(!x);
x ^= x << w;
}
xs
};
if $T::BITS == 8 {
assert_eq!(&xs, &[0xff, 0x00, 0x0f, 0xf0, 0x33, 0xcc, 0x55, 0xaa]);
}
// `256 * (BITS / 5)` masks
let sparse_masks = (i8::MIN..=i8::MAX)
.map(|i| (i as i128 as $T).rotate_right(4))
.flat_map(|x| (0..$T::BITS).step_by(5).map(move |r| x.rotate_right(r)));
for sparse in sparse_masks {
// Collect the set bits to sequential low bits
let dense = sparse.gather_bits(sparse);
let count = sparse.count_ones();
assert_eq!(count, dense.count_ones());
assert_eq!(count, dense.trailing_ones());
// Check that each bit is individually mapped correctly
let mut t = sparse;
let mut bit = 1 as $T;
for _ in 0..count {
let lowest_one = t.isolate_lowest_one();
assert_eq!(lowest_one, bit.scatter_bits(sparse));
assert_eq!(bit, lowest_one.gather_bits(sparse));
t ^= lowest_one;
bit <<= 1;
}
// Other bits are ignored
assert_eq!(0, bit.wrapping_neg().scatter_bits(sparse));
assert_eq!(0, (!sparse).gather_bits(sparse));
for &x in &xs {
// Gather bits from `x & sparse` to `dense`
let dx = x.gather_bits(sparse);
assert_eq!(dx & !dense, 0);
// Scatter bits from `x & dense` to `sparse`
let sx = x.scatter_bits(sparse);
assert_eq!(sx & !sparse, 0);
// The other recovers the input (within the mask)
assert_eq!(dx.scatter_bits(sparse), x & sparse);
assert_eq!(sx.gather_bits(sparse), x & dense);
}
}
}
test_runtime_and_compiletime! {
fn test_div_floor() {
assert_eq_const_safe!($T: (8 as $T).div_floor(3), 2);