use crate::element::float::spec::Bf16;
use crate::register::PackedFloatRegister;
use crate::register::array::ArrayRegister;
use super::{F32x4V3, F32x8V3, U16x8V3, U16x16V3};
type F32x16 = ArrayRegister<F32x8V3, 2>;
impl PackedFloatRegister<Bf16, F32x4V3> for super::half16::U16x4V3 {}
impl PackedFloatRegister<Bf16, F32x8V3> for U16x8V3 {}
impl PackedFloatRegister<Bf16, F32x16> for U16x16V3 {}
#[cfg(not(feature = "avx2-f16c"))]
mod fallback {
use super::*;
use crate::element::float::spec::{Fp16, Fp16Fast};
macro_rules! impl_fp16 {
($u16:ty, $f32:ty) => {
impl PackedFloatRegister<Fp16, $f32> for $u16 {}
impl PackedFloatRegister<Fp16Fast, $f32> for $u16 {}
};
}
impl_fp16!(super::super::half16::U16x4V3, F32x4V3);
impl_fp16!(U16x8V3, F32x8V3);
impl_fp16!(U16x16V3, F32x16);
}
#[cfg(feature = "avx2-f16c")]
mod f16c {
use crate::element::float::spec::{Fp16, Fp16Fast};
use crate::register::array::ArrayRegister;
use crate::register::reduced::ReducedRegister;
use crate::register::{BitwiseRegister, PackedFloatRegister, PartialOrdRegister, Register, Storage};
use super::super::arch;
use super::super::half16::U16x4V3;
use super::super::{F32x4V3, F32x8V3, U16x8V3, U16x16V3};
use super::F32x16;
const F16_EXP: u16 = 0x7C00;
const F16_SIGN: u16 = 0x8000;
#[inline(always)]
fn flush_nonfinite<R>(h: Storage<R>) -> Storage<R>
where
R: BitwiseRegister + PartialOrdRegister + Register<Element = u16>,
{
let nonfinite = R::eq(R::bitand(h, R::splat(F16_EXP)), R::splat(F16_EXP));
let signed_zero = R::bitand(h, R::splat(F16_SIGN));
R::blendv(nonfinite, h, signed_zero)
}
const RNE: i32 = arch::_MM_FROUND_TO_NEAREST_INT;
#[thermite_macros::inline_always]
impl PackedFloatRegister<Fp16, F32x4V3> for U16x4V3 {
fn unpack(values: Storage<Self>) -> Storage<F32x4V3> {
unsafe { arch::_mm_cvtph_ps(values.0) }
}
fn pack(values: Storage<F32x4V3>) -> Storage<Self> {
ReducedRegister::new(unsafe { arch::_mm_cvtps_ph::<RNE>(values) })
}
}
#[thermite_macros::inline_always]
impl PackedFloatRegister<Fp16, F32x8V3> for U16x8V3 {
fn unpack(values: Storage<Self>) -> Storage<F32x8V3> {
unsafe { arch::_mm256_cvtph_ps(values) }
}
fn pack(values: Storage<F32x8V3>) -> Storage<Self> {
unsafe { arch::_mm256_cvtps_ph::<RNE>(values) }
}
}
#[thermite_macros::inline_always]
impl PackedFloatRegister<Fp16, F32x16> for U16x16V3 {
fn unpack(values: Storage<Self>) -> Storage<F32x16> {
unsafe {
let lo = arch::_mm256_castsi256_si128(values);
let hi = arch::_mm256_extracti128_si256(values, 1);
ArrayRegister([arch::_mm256_cvtph_ps(lo), arch::_mm256_cvtph_ps(hi)])
}
}
fn pack(values: Storage<F32x16>) -> Storage<Self> {
unsafe {
let lo = arch::_mm256_cvtps_ph::<RNE>(values.0[0]);
let hi = arch::_mm256_cvtps_ph::<RNE>(values.0[1]);
arch::_mm256_set_m128i(hi, lo)
}
}
}
#[thermite_macros::inline_always]
impl PackedFloatRegister<Fp16Fast, F32x4V3> for U16x4V3 {
fn unpack(values: Storage<Self>) -> Storage<F32x4V3> {
unsafe { arch::_mm_cvtph_ps(values.0) }
}
fn pack(values: Storage<F32x4V3>) -> Storage<Self> {
ReducedRegister::new(flush_nonfinite::<U16x8V3>(unsafe { arch::_mm_cvtps_ph::<RNE>(values) }))
}
}
#[thermite_macros::inline_always]
impl PackedFloatRegister<Fp16Fast, F32x8V3> for U16x8V3 {
fn unpack(values: Storage<Self>) -> Storage<F32x8V3> {
unsafe { arch::_mm256_cvtph_ps(values) }
}
fn pack(values: Storage<F32x8V3>) -> Storage<Self> {
flush_nonfinite::<U16x8V3>(unsafe { arch::_mm256_cvtps_ph::<RNE>(values) })
}
}
#[thermite_macros::inline_always]
impl PackedFloatRegister<Fp16Fast, F32x16> for U16x16V3 {
fn unpack(values: Storage<Self>) -> Storage<F32x16> {
unsafe {
let lo = arch::_mm256_castsi256_si128(values);
let hi = arch::_mm256_extracti128_si256(values, 1);
ArrayRegister([arch::_mm256_cvtph_ps(lo), arch::_mm256_cvtph_ps(hi)])
}
}
fn pack(values: Storage<F32x16>) -> Storage<Self> {
unsafe {
let lo = arch::_mm256_cvtps_ph::<RNE>(values.0[0]);
let hi = arch::_mm256_cvtps_ph::<RNE>(values.0[1]);
flush_nonfinite::<U16x16V3>(arch::_mm256_set_m128i(hi, lo))
}
}
}
}