use core::arch::x86_64::{
__m128i, _mm_add_epi16, _mm_mullo_epi16, _mm_packus_epi16, _mm_set_epi16, _mm_set_epi64x,
_mm_srai_epi16, _mm_storel_epi64,
};
#[inline(always)]
pub(super) fn pack4(v: [i32; 4]) -> i64 {
((v[0] as u16 as u64)
| ((v[1] as u16 as u64) << 16)
| ((v[2] as u16 as u64) << 32)
| ((v[3] as u16 as u64) << 48)) as i64
}
#[inline(always)]
pub(super) fn pack3_opaque_base(v: [i32; 3]) -> i64 {
pack4([v[0], v[1], v[2], 255 << 6])
}
#[inline(always)]
pub(super) fn pack3_opaque_delta(v: [i32; 3]) -> i64 {
pack4([v[0], v[1], v[2], 0])
}
#[inline(always)]
pub(super) fn write2(b0: i64, d0: i64, b1: i64, d1: i64, w0: i16, w1: i16, dst: &mut [u8]) {
debug_assert!(dst.len() >= 8, "write2 needs eight bytes");
unsafe {
let base = _mm_set_epi64x(b1, b0);
let delta = _mm_set_epi64x(d1, d0);
let w = _mm_set_epi16(w1, w1, w1, w1, w0, w0, w0, w0);
let v = _mm_add_epi16(base, _mm_mullo_epi16(delta, w));
let v = _mm_srai_epi16(v, 6);
let packed = _mm_packus_epi16(v, v);
_mm_storel_epi64(dst.as_mut_ptr() as *mut __m128i, packed);
}
}
#[inline(always)]
pub(super) fn pack_bd3(bd: &[([i32; 3], [i32; 3])], pairs: usize) -> [(i64, i64); 3] {
let mut out = [(0i64, 0i64); 3];
for (k, slot) in out.iter_mut().enumerate().take(pairs) {
slot.0 = pack3_opaque_base(bd[k].0);
slot.1 = pack3_opaque_delta(bd[k].1);
}
out
}
#[inline(always)]
pub(super) fn pack_bd4(bd: &[([i32; 4], [i32; 4])], pairs: usize) -> [(i64, i64); 2] {
let mut out = [(0i64, 0i64); 2];
for (k, slot) in out.iter_mut().enumerate().take(pairs) {
slot.0 = pack4(bd[k].0);
slot.1 = pack4(bd[k].1);
}
out
}
#[inline(always)]
#[allow(clippy::too_many_arguments)]
pub(super) fn write2_split(
b0: i64,
d0: i64,
b1: i64,
d1: i64,
wc: (i16, i16),
wa: (i16, i16),
alpha_lane: usize,
dst: &mut [u8],
) {
debug_assert!(dst.len() >= 8, "write2_split needs eight bytes");
debug_assert!(alpha_lane < 4);
unsafe {
let base = _mm_set_epi64x(b1, b0);
let delta = _mm_set_epi64x(d1, d0);
let (c0, a0, c1, a1) = (wc.0, wa.0, wc.1, wa.1);
let w = match alpha_lane {
0 => _mm_set_epi16(c1, c1, c1, a1, c0, c0, c0, a0),
1 => _mm_set_epi16(c1, c1, a1, c1, c0, c0, a0, c0),
2 => _mm_set_epi16(c1, a1, c1, c1, c0, a0, c0, c0),
_ => _mm_set_epi16(a1, c1, c1, c1, a0, c0, c0, c0),
};
let v = _mm_add_epi16(base, _mm_mullo_epi16(delta, w));
let v = _mm_srai_epi16(v, 6);
let packed = _mm_packus_epi16(v, v);
_mm_storel_epi64(dst.as_mut_ptr() as *mut __m128i, packed);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn write2_matches_scalar_over_the_full_domain() {
const WEIGHTS: [i16; 6] = [0, 9, 21, 43, 60, 64];
for &e0 in &[0u32, 1, 63, 127, 128, 254, 255] {
for &e1 in &[0u32, 1, 63, 127, 128, 254, 255] {
let base = [e0 as i32 * 64 + 32; 4];
let delta = [e1 as i32 - e0 as i32; 4];
let (bp, dp) = (pack4(base), pack4(delta));
for &w0 in &WEIGHTS {
for &w1 in &WEIGHTS {
let mut got = [0u8; 8];
write2(bp, dp, bp, dp, w0, w1, &mut got);
for (k, w) in [w0, w1].into_iter().enumerate() {
let want =
((base[0] + w as i32 * delta[0]) >> 6) as u8;
for c in 0..4 {
assert_eq!(
got[k * 4 + c],
want,
"e0={e0} e1={e1} w={w} channel {c}"
);
}
}
}
}
}
}
}
#[test]
fn opaque_alpha_is_constant_across_weights() {
let base = pack3_opaque_base([100 * 64 + 32, 0 + 32, 255 * 64 + 32]);
let delta = pack3_opaque_delta([50, -50, 0]);
for w in 0..=64i16 {
let mut got = [0u8; 8];
write2(base, delta, base, delta, w, w, &mut got);
assert_eq!(got[3], 255, "alpha moved at w={w}");
assert_eq!(got[7], 255, "alpha moved at w={w}");
}
}
#[test]
fn write2_split_honours_the_alpha_lane() {
let base = pack4([10 * 64 + 32, 20 * 64 + 32, 30 * 64 + 32, 40 * 64 + 32]);
let delta = pack4([100, 100, 100, 100]);
for alpha_lane in 0..4usize {
let mut got = [0u8; 8];
write2_split(base, delta, base, delta, (0, 0), (64, 64), alpha_lane, &mut got);
let starts = [10, 20, 30, 40];
for lane in 0..4usize {
let want = if lane == alpha_lane {
((starts[lane] * 64 + 32 + 64 * 100) >> 6) as u8
} else {
starts[lane] as u8
};
assert_eq!(got[lane], want, "alpha_lane {alpha_lane}, lane {lane}");
}
}
}
}