use super::*;
use crate::test_support::simd_levels;
const EDGES: [i64; 15] = [
0,
1,
-1,
2,
i64::MIN,
i64::MAX,
i64::MIN + 1,
f64::NAN.to_bits() as i64,
(-f64::NAN).to_bits() as i64,
(-0.0f64).to_bits() as i64,
f64::INFINITY.to_bits() as i64,
f64::NEG_INFINITY.to_bits() as i64,
1.5f64.to_bits() as i64,
(-1.5f64).to_bits() as i64,
f64::MIN_POSITIVE.to_bits() as i64,
];
fn operand_lanes() -> (Vec<i64>, Vec<i64>) {
let (mut a, mut b) = (Vec::new(), Vec::new());
for &x in &EDGES {
for &y in &EDGES {
a.push(x);
b.push(y);
}
}
let mut state = 0x9e37_79b9_7f4a_7c15u64;
let mut next = move || {
state ^= state << 13;
state ^= state >> 7;
state ^= state << 17;
state as i64
};
while !a.len().is_multiple_of(64) || a.len() < 512 {
let (x, y) = (next(), next());
let small = a.len().is_multiple_of(3);
a.push(if small { x % 4 } else { x });
b.push(if small { y % 4 } else { y });
}
(a, b)
}
fn packed(n: usize, bit: impl Fn(usize) -> bool) -> Vec<u64> {
let mut out = vec![0u64; n / 64];
for i in (0..n).filter(|&i| bit(i)) {
out[i / 64] |= 1 << (i % 64);
}
out
}
fn check_pred<P: LanePred>(name: &str, holds: impl Fn(i64, i64) -> bool) {
let (a, b) = operand_lanes();
for (&x, &y) in a.iter().zip(&b) {
assert_eq!(P::scalar(x, y), holds(x, y), "{name} of {x:#x}, {y:#x}");
}
let want = packed(a.len(), |i| holds(a[i], b[i]));
for (level_name, level) in simd_levels() {
let mut got = vec![0u64; want.len()];
pred_bits::<P>(level, &a, &b, &mut got);
assert_eq!(got, want, "{name} at {level_name}");
}
}
#[test]
fn a_predicate_is_its_operator_per_row_and_per_vector() {
let f = |x: i64| f64::from_bits(x as u64);
let wide = |x: i64, y: i64| (x as u64 as i128, y as i128);
check_pred::<Eq>("Eq", |x, y| x == y);
check_pred::<Not<Eq>>("Not<Eq>", |x, y| x != y);
check_pred::<GtSigned>("GtSigned", |x, y| x > y);
check_pred::<Not<GtSigned>>("Not<GtSigned>", |x, y| x <= y);
check_pred::<GtUnsigned>("GtUnsigned", |x, y| (x as u64) > (y as u64));
check_pred::<Not<GtUnsigned>>("Not<GtUnsigned>", |x, y| (x as u64) <= (y as u64));
check_pred::<EqUnsignedSigned>("EqUnsignedSigned", |x, y| wide(x, y).0 == wide(x, y).1);
check_pred::<Not<EqUnsignedSigned>>("Not<EqUnsignedSigned>", |x, y| wide(x, y).0 != wide(x, y).1);
check_pred::<LtUnsignedSigned>("LtUnsignedSigned", |x, y| wide(x, y).0 < wide(x, y).1);
check_pred::<Not<LtUnsignedSigned>>("Not<LtUnsignedSigned>", |x, y| wide(x, y).0 >= wide(x, y).1);
check_pred::<LeUnsignedSigned>("LeUnsignedSigned", |x, y| wide(x, y).0 <= wide(x, y).1);
check_pred::<Not<LeUnsignedSigned>>("Not<LeUnsignedSigned>", |x, y| wide(x, y).0 > wide(x, y).1);
check_pred::<EqFloat>("EqFloat", |x, y| f(x) == f(y));
check_pred::<Not<EqFloat>>("Not<EqFloat>", |x, y| f(x) != f(y));
check_pred::<GtFloat>("GtFloat", |x, y| f(x) > f(y));
check_pred::<GeFloat>("GeFloat", |x, y| f(x) >= f(y));
check_pred::<GtTotal>("GtTotal", |x, y| f(x).total_cmp(&f(y)).is_gt());
check_pred::<Not<GtTotal>>("Not<GtTotal>", |x, y| f(x).total_cmp(&f(y)).is_le());
}
#[test]
fn truthy_bits_marks_the_non_zero_lanes() {
let (a, _) = operand_lanes();
let want = packed(a.len(), |i| a[i] != 0);
for (level_name, level) in simd_levels() {
let mut got = vec![0u64; want.len()];
truthy_bits(level, &a, &mut got);
assert_eq!(got, want, "{level_name}");
}
}
#[test]
fn in_set_bits_marks_the_members() {
let (a, b) = operand_lanes();
for len in [0, 1, 2, 3, 4, 5, 8, 11, 33] {
let set = &b[..len];
let want = packed(a.len(), |i| set.contains(&a[i]));
for (level_name, level) in simd_levels() {
let mut got = vec![0u64; want.len()];
in_set_bits(level, &a, set, &mut got);
assert_eq!(got, want, "{len} values at {level_name}");
}
}
}
#[test]
fn null_bits_gathers_the_selected_columns() {
let (a, _) = operand_lanes();
let word = |i: usize| {
if i.is_multiple_of(3) {
a[i] as u64
} else {
1u64 << (i % 64)
}
};
for rows in [0, 1, 63, 64, 65, 200, 256] {
let bytes: Vec<u8> = (0..rows).flat_map(|i| word(i).to_le_bytes()).collect();
for cols in [1u64, 1 << 63, 0b1010, u64::MAX, 0] {
let mut want = vec![0u64; rows.div_ceil(64)];
for i in (0..rows).filter(|&i| word(i) & cols != 0) {
want[i / 64] |= 1 << (i % 64);
}
for (level_name, level) in simd_levels() {
let mut got = vec![u64::MAX; want.len()];
null_bits(level, &bytes, cols, &mut got);
assert_eq!(got, want, "{rows} rows, cols {cols:#x} at {level_name}");
}
}
}
}
#[test]
fn blend_takes_a_where_the_bit_is_set() {
let (a, b) = operand_lanes();
let take: Vec<u64> = (0..a.len() / 64)
.map(|w| [0, u64::MAX, 0x5555_5555_5555_5555, a[w] as u64][w % 4])
.collect();
let want: Vec<i64> = (0..a.len())
.map(|i| {
if (take[i / 64] >> (i % 64)) & 1 != 0 {
a[i]
} else {
b[i]
}
})
.collect();
for (level_name, level) in simd_levels() {
let mut got = vec![0i64; a.len()];
blend(level, &take, &a, &b, &mut got);
assert_eq!(got, want, "{level_name}");
}
}
#[test]
fn bit_lanes_writes_each_bit_as_a_lane() {
let (a, _) = operand_lanes();
let bits: Vec<u64> = a
.iter()
.take(4)
.map(|&x| x as u64)
.chain([0, u64::MAX, 1, 1 << 63])
.collect();
let want: Vec<i64> = (0..bits.len() * 64)
.map(|i| ((bits[i / 64] >> (i % 64)) & 1) as i64)
.collect();
for (level_name, level) in simd_levels() {
let mut got = vec![-1i64; want.len()];
bit_lanes(level, &bits, &mut got);
assert_eq!(got, want, "{level_name}");
}
}