#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
const F_0_298: i16 = 2446;
const F_0_390: i16 = 3196;
const F_0_541: i16 = 4433;
const F_0_765: i16 = 6270;
const F_0_899: i16 = 7373;
const F_1_175: i16 = 9633;
const F_1_501: i16 = 12299;
const F_1_847: i16 = 15137;
const F_1_961: i16 = 16069;
const F_2_053: i16 = 16819;
const F_2_562: i16 = 20995;
const F_3_072: i16 = 25172;
const PASS1_BITS: i32 = 2;
const DESCALE_P1: i32 = 13 - PASS1_BITS; const DESCALE_P2: i32 = 13 + PASS1_BITS;
#[repr(align(32))]
struct A16([i16; 16]);
#[repr(align(32))]
struct A32([i32; 8]);
static PW_F130_F054_MF130_F054: A16 = A16([
(F_0_541 + F_0_765),
F_0_541,
(F_0_541 + F_0_765),
F_0_541,
(F_0_541 + F_0_765),
F_0_541,
(F_0_541 + F_0_765),
F_0_541,
(F_0_541 - F_1_847),
F_0_541,
(F_0_541 - F_1_847),
F_0_541,
(F_0_541 - F_1_847),
F_0_541,
(F_0_541 - F_1_847),
F_0_541,
]);
static PW_MF078_F117_F078_F117: A16 = A16([
(F_1_175 - F_1_961),
F_1_175,
(F_1_175 - F_1_961),
F_1_175,
(F_1_175 - F_1_961),
F_1_175,
(F_1_175 - F_1_961),
F_1_175,
(F_1_175 - F_0_390),
F_1_175,
(F_1_175 - F_0_390),
F_1_175,
(F_1_175 - F_0_390),
F_1_175,
(F_1_175 - F_0_390),
F_1_175,
]);
static PW_MF060_MF089_MF050_MF256: A16 = A16([
(F_0_298 - F_0_899),
-F_0_899,
(F_0_298 - F_0_899),
-F_0_899,
(F_0_298 - F_0_899),
-F_0_899,
(F_0_298 - F_0_899),
-F_0_899,
(F_2_053 - F_2_562),
-F_2_562,
(F_2_053 - F_2_562),
-F_2_562,
(F_2_053 - F_2_562),
-F_2_562,
(F_2_053 - F_2_562),
-F_2_562,
]);
static PW_F050_MF256_F060_MF089: A16 = A16([
(F_3_072 - F_2_562),
-F_2_562,
(F_3_072 - F_2_562),
-F_2_562,
(F_3_072 - F_2_562),
-F_2_562,
(F_3_072 - F_2_562),
-F_2_562,
(F_1_501 - F_0_899),
-F_0_899,
(F_1_501 - F_0_899),
-F_0_899,
(F_1_501 - F_0_899),
-F_0_899,
(F_1_501 - F_0_899),
-F_0_899,
]);
static PW_1_NEG1: A16 = A16([1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1]);
static PD_DESCALE_P1: A32 = A32([1 << (DESCALE_P1 - 1); 8]);
static PD_DESCALE_P2: A32 = A32([1 << (DESCALE_P2 - 1); 8]);
macro_rules! dofdct {
($r0:expr, $r1:expr, $r2:expr, $r3:expr, 1) => {
dofdct_pass1($r0, $r1, $r2, $r3)
};
($r0:expr, $r1:expr, $r2:expr, $r3:expr, 2) => {
dofdct_pass2($r0, $r1, $r2, $r3)
};
}
pub fn avx2_fdct_islow(data: &mut [i16; 64]) {
unsafe { avx2_fdct_islow_inner(data) }
}
#[target_feature(enable = "avx2")]
unsafe fn avx2_fdct_islow_inner(data: &mut [i16; 64]) {
let ptr = data.as_mut_ptr() as *mut __m256i;
let ymm4 = _mm256_loadu_si256(ptr);
let ymm5 = _mm256_loadu_si256(ptr.add(1));
let ymm6 = _mm256_loadu_si256(ptr.add(2));
let ymm7 = _mm256_loadu_si256(ptr.add(3));
let (out0, out1, out2, out3) = avx2_fdct_core(ymm4, ymm5, ymm6, ymm7);
_mm256_storeu_si256(ptr, out0);
_mm256_storeu_si256(ptr.add(1), out1);
_mm256_storeu_si256(ptr.add(2), out2);
_mm256_storeu_si256(ptr.add(3), out3);
}
#[target_feature(enable = "avx2")]
#[inline]
pub(crate) unsafe fn avx2_fdct_core(
ymm4: __m256i,
ymm5: __m256i,
ymm6: __m256i,
ymm7: __m256i,
) -> (__m256i, __m256i, __m256i, __m256i) {
let ymm0 = _mm256_permute2x128_si256(ymm4, ymm6, 0x20);
let ymm1 = _mm256_permute2x128_si256(ymm4, ymm6, 0x31);
let ymm2 = _mm256_permute2x128_si256(ymm5, ymm7, 0x20);
let ymm3 = _mm256_permute2x128_si256(ymm5, ymm7, 0x31);
let (t0, t1, t2, t3) = dotranspose_fdct(ymm0, ymm1, ymm2, ymm3);
let (d0, d1, d2, d3) = dofdct!(t0, t1, t2, t3, 1);
let c4 = _mm256_permute2x128_si256(d1, d3, 0x20);
let c1 = _mm256_permute2x128_si256(d1, d3, 0x31);
let (t0, t1, t2, t3) = dotranspose_fdct(d0, c1, d2, c4);
let (r0, r1, r2, r3) = dofdct!(t0, t1, t2, t3, 2);
(
_mm256_permute2x128_si256(r0, r1, 0x30),
_mm256_permute2x128_si256(r2, r1, 0x20),
_mm256_permute2x128_si256(r0, r3, 0x31),
_mm256_permute2x128_si256(r2, r3, 0x21),
)
}
#[target_feature(enable = "avx2")]
#[inline]
unsafe fn dotranspose_fdct(
r0: __m256i,
r1: __m256i,
r2: __m256i,
r3: __m256i,
) -> (__m256i, __m256i, __m256i, __m256i) {
let t0 = _mm256_unpacklo_epi16(r0, r1);
let t1 = _mm256_unpackhi_epi16(r0, r1);
let t2 = _mm256_unpacklo_epi16(r2, r3);
let t3 = _mm256_unpackhi_epi16(r2, r3);
let u0 = _mm256_unpacklo_epi32(t0, t2);
let u1 = _mm256_unpackhi_epi32(t0, t2);
let u2 = _mm256_unpacklo_epi32(t1, t3);
let u3 = _mm256_unpackhi_epi32(t1, t3);
let out0 = _mm256_permute4x64_epi64(u0, 0x8D); let out1 = _mm256_permute4x64_epi64(u1, 0x8D);
let out2 = _mm256_permute4x64_epi64(u2, 0xD8);
let out3 = _mm256_permute4x64_epi64(u3, 0xD8);
(out0, out1, out2, out3)
}
#[target_feature(enable = "avx2")]
#[inline]
unsafe fn dofdct_pass1(
in04: __m256i,
in15: __m256i,
in26: __m256i,
in37: __m256i,
) -> (__m256i, __m256i, __m256i, __m256i) {
let tmp67 = _mm256_sub_epi16(in04, in37); let tmp10 = _mm256_add_epi16(in04, in37); let tmp32 = _mm256_add_epi16(in15, in26); let tmp45 = _mm256_sub_epi16(in15, in26);
let tmp01 = _mm256_permute2x128_si256(tmp10, tmp10, 0x01); let tmp1011 = _mm256_add_epi16(tmp01, tmp32); let tmp1312 = _mm256_sub_epi16(tmp01, tmp32);
let tmp1110 = _mm256_permute2x128_si256(tmp1011, tmp1011, 0x01);
let signed = _mm256_sign_epi16(
tmp1011,
_mm256_load_si256(PW_1_NEG1.0.as_ptr() as *const __m256i),
);
let sum = _mm256_add_epi16(tmp1110, signed); let data04 = _mm256_slli_epi16::<PASS1_BITS>(sum);
let tmp1213 = _mm256_permute2x128_si256(tmp1312, tmp1312, 0x01);
let pairs_lo = _mm256_unpacklo_epi16(tmp1312, tmp1213);
let pairs_hi = _mm256_unpackhi_epi16(tmp1312, tmp1213);
let pw = _mm256_load_si256(PW_F130_F054_MF130_F054.0.as_ptr() as *const __m256i);
let d26_lo = _mm256_madd_epi16(pairs_lo, pw);
let d26_hi = _mm256_madd_epi16(pairs_hi, pw);
let round = _mm256_load_si256(PD_DESCALE_P1.0.as_ptr() as *const __m256i);
let d26_lo = _mm256_srai_epi32::<DESCALE_P1>(_mm256_add_epi32(d26_lo, round));
let d26_hi = _mm256_srai_epi32::<DESCALE_P1>(_mm256_add_epi32(d26_hi, round));
let data26 = _mm256_packs_epi32(d26_lo, d26_hi);
let z34 = _mm256_add_epi16(tmp45, tmp67); let z43 = _mm256_permute2x128_si256(z34, z34, 0x01);
let z_lo = _mm256_unpacklo_epi16(z34, z43);
let z_hi = _mm256_unpackhi_epi16(z34, z43);
let pw_z = _mm256_load_si256(PW_MF078_F117_F078_F117.0.as_ptr() as *const __m256i);
let z34_lo = _mm256_madd_epi16(z_lo, pw_z);
let z34_hi = _mm256_madd_epi16(z_hi, pw_z);
let tmp76 = _mm256_permute2x128_si256(tmp67, tmp67, 0x01);
let p45_lo = _mm256_unpacklo_epi16(tmp45, tmp76);
let p45_hi = _mm256_unpackhi_epi16(tmp45, tmp76);
let pw_45 = _mm256_load_si256(PW_MF060_MF089_MF050_MF256.0.as_ptr() as *const __m256i);
let d75_lo = _mm256_add_epi32(_mm256_madd_epi16(p45_lo, pw_45), z34_lo);
let d75_hi = _mm256_add_epi32(_mm256_madd_epi16(p45_hi, pw_45), z34_hi);
let d75_lo = _mm256_srai_epi32::<DESCALE_P1>(_mm256_add_epi32(d75_lo, round));
let d75_hi = _mm256_srai_epi32::<DESCALE_P1>(_mm256_add_epi32(d75_hi, round));
let data75 = _mm256_packs_epi32(d75_lo, d75_hi);
let tmp54 = _mm256_permute2x128_si256(tmp45, tmp45, 0x01);
let p67_lo = _mm256_unpacklo_epi16(tmp67, tmp54);
let p67_hi = _mm256_unpackhi_epi16(tmp67, tmp54);
let pw_67 = _mm256_load_si256(PW_F050_MF256_F060_MF089.0.as_ptr() as *const __m256i);
let d31_lo = _mm256_add_epi32(_mm256_madd_epi16(p67_lo, pw_67), z34_lo);
let d31_hi = _mm256_add_epi32(_mm256_madd_epi16(p67_hi, pw_67), z34_hi);
let d31_lo = _mm256_srai_epi32::<DESCALE_P1>(_mm256_add_epi32(d31_lo, round));
let d31_hi = _mm256_srai_epi32::<DESCALE_P1>(_mm256_add_epi32(d31_hi, round));
let data31 = _mm256_packs_epi32(d31_lo, d31_hi);
(data04, data31, data26, data75)
}
#[target_feature(enable = "avx2")]
#[inline]
unsafe fn dofdct_pass2(
in04: __m256i,
in15: __m256i,
in26: __m256i,
in37: __m256i,
) -> (__m256i, __m256i, __m256i, __m256i) {
let tmp67 = _mm256_sub_epi16(in04, in37);
let tmp10 = _mm256_add_epi16(in04, in37);
let tmp32 = _mm256_add_epi16(in15, in26);
let tmp45 = _mm256_sub_epi16(in15, in26);
let tmp01 = _mm256_permute2x128_si256(tmp10, tmp10, 0x01);
let tmp1011 = _mm256_add_epi16(tmp01, tmp32);
let tmp1312 = _mm256_sub_epi16(tmp01, tmp32);
let tmp1110 = _mm256_permute2x128_si256(tmp1011, tmp1011, 0x01);
let signed = _mm256_sign_epi16(
tmp1011,
_mm256_load_si256(PW_1_NEG1.0.as_ptr() as *const __m256i),
);
let sum = _mm256_add_epi16(tmp1110, signed);
let p2_round = _mm256_set1_epi16(1 << (PASS1_BITS - 1));
let data04 = _mm256_srai_epi16::<PASS1_BITS>(_mm256_add_epi16(sum, p2_round));
let tmp1213 = _mm256_permute2x128_si256(tmp1312, tmp1312, 0x01);
let pairs_lo = _mm256_unpacklo_epi16(tmp1312, tmp1213);
let pairs_hi = _mm256_unpackhi_epi16(tmp1312, tmp1213);
let pw = _mm256_load_si256(PW_F130_F054_MF130_F054.0.as_ptr() as *const __m256i);
let d26_lo = _mm256_madd_epi16(pairs_lo, pw);
let d26_hi = _mm256_madd_epi16(pairs_hi, pw);
let round = _mm256_load_si256(PD_DESCALE_P2.0.as_ptr() as *const __m256i);
let d26_lo = _mm256_srai_epi32::<DESCALE_P2>(_mm256_add_epi32(d26_lo, round));
let d26_hi = _mm256_srai_epi32::<DESCALE_P2>(_mm256_add_epi32(d26_hi, round));
let data26 = _mm256_packs_epi32(d26_lo, d26_hi);
let z34 = _mm256_add_epi16(tmp45, tmp67);
let z43 = _mm256_permute2x128_si256(z34, z34, 0x01);
let z_lo = _mm256_unpacklo_epi16(z34, z43);
let z_hi = _mm256_unpackhi_epi16(z34, z43);
let pw_z = _mm256_load_si256(PW_MF078_F117_F078_F117.0.as_ptr() as *const __m256i);
let z34_lo = _mm256_madd_epi16(z_lo, pw_z);
let z34_hi = _mm256_madd_epi16(z_hi, pw_z);
let tmp76 = _mm256_permute2x128_si256(tmp67, tmp67, 0x01);
let p45_lo = _mm256_unpacklo_epi16(tmp45, tmp76);
let p45_hi = _mm256_unpackhi_epi16(tmp45, tmp76);
let pw_45 = _mm256_load_si256(PW_MF060_MF089_MF050_MF256.0.as_ptr() as *const __m256i);
let d75_lo = _mm256_add_epi32(_mm256_madd_epi16(p45_lo, pw_45), z34_lo);
let d75_hi = _mm256_add_epi32(_mm256_madd_epi16(p45_hi, pw_45), z34_hi);
let d75_lo = _mm256_srai_epi32::<DESCALE_P2>(_mm256_add_epi32(d75_lo, round));
let d75_hi = _mm256_srai_epi32::<DESCALE_P2>(_mm256_add_epi32(d75_hi, round));
let data75 = _mm256_packs_epi32(d75_lo, d75_hi);
let tmp54 = _mm256_permute2x128_si256(tmp45, tmp45, 0x01);
let p67_lo = _mm256_unpacklo_epi16(tmp67, tmp54);
let p67_hi = _mm256_unpackhi_epi16(tmp67, tmp54);
let pw_67 = _mm256_load_si256(PW_F050_MF256_F060_MF089.0.as_ptr() as *const __m256i);
let d31_lo = _mm256_add_epi32(_mm256_madd_epi16(p67_lo, pw_67), z34_lo);
let d31_hi = _mm256_add_epi32(_mm256_madd_epi16(p67_hi, pw_67), z34_hi);
let d31_lo = _mm256_srai_epi32::<DESCALE_P2>(_mm256_add_epi32(d31_lo, round));
let d31_hi = _mm256_srai_epi32::<DESCALE_P2>(_mm256_add_epi32(d31_hi, round));
let data31 = _mm256_packs_epi32(d31_lo, d31_hi);
(data04, data31, data26, data75)
}