routine_ew_rust!(x86_64;
f32,
x86_64_fma_ln_f32_32n,
32,
8,
#[inline(never)]
fn run(buf: &mut [f32], _: ()) {
debug_assert!(buf.len() % Self::nr() == 0);
debug_assert!(buf.as_ptr() as usize % Self::alignment_bytes() == 0);
unsafe { x86_64_fma_ln_f32_32n_run(buf) }
},
func(Ln),
isa(X86_64Avx2, X86_64Fma)
);
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2,fma")]
unsafe fn x86_64_fma_ln_f32_32n_run(buf: &mut [f32]) {
use crate::generic::ln::{LN2_HI, LN2_LO, POLY, SPLIT, SUBNORMAL_SCALE, SUBNORMAL_SHIFT};
use std::arch::x86_64::*;
#[inline(always)]
unsafe fn ln8(x: __m256) -> __m256 {
unsafe {
let one = _mm256_set1_ps(1.0);
let zero = _mm256_setzero_ps();
let subnormal = _mm256_cmp_ps::<_CMP_LT_OQ>(x, _mm256_set1_ps(f32::MIN_POSITIVE));
let scaled =
_mm256_blendv_ps(x, _mm256_mul_ps(x, _mm256_set1_ps(SUBNORMAL_SCALE)), subnormal);
let bits = _mm256_castps_si256(scaled);
let mut exponent =
_mm256_sub_epi32(_mm256_srli_epi32::<23>(bits), _mm256_set1_epi32(127));
exponent = _mm256_add_epi32(
exponent,
_mm256_and_si256(
_mm256_castps_si256(subnormal),
_mm256_set1_epi32(-SUBNORMAL_SHIFT),
),
);
let mantissa = _mm256_or_ps(
_mm256_and_ps(scaled, _mm256_castsi256_ps(_mm256_set1_epi32(0x007fffff))),
one,
);
let split = _mm256_cmp_ps::<_CMP_GT_OQ>(mantissa, _mm256_set1_ps(SPLIT));
let mantissa =
_mm256_blendv_ps(mantissa, _mm256_mul_ps(mantissa, _mm256_set1_ps(0.5)), split);
exponent = _mm256_add_epi32(
exponent,
_mm256_and_si256(_mm256_castps_si256(split), _mm256_set1_epi32(1)),
);
let e = _mm256_cvtepi32_ps(exponent);
let f = _mm256_sub_ps(mantissa, one);
let mut p = _mm256_set1_ps(POLY[0]);
for c in &POLY[1..] {
p = _mm256_fmadd_ps(p, f, _mm256_set1_ps(*c));
}
let f2 = _mm256_mul_ps(f, f);
let mut y = _mm256_mul_ps(_mm256_mul_ps(p, f2), f);
y = _mm256_fmadd_ps(e, _mm256_set1_ps(LN2_LO), y);
y = _mm256_add_ps(_mm256_fnmadd_ps(_mm256_set1_ps(0.5), f2, y), f);
y = _mm256_fmadd_ps(e, _mm256_set1_ps(LN2_HI), y);
let outside = _mm256_cmp_ps::<_CMP_NGT_UQ>(x, zero);
let special = _mm256_blendv_ps(
_mm256_set1_ps(f32::NAN),
_mm256_set1_ps(f32::NEG_INFINITY),
_mm256_cmp_ps::<_CMP_EQ_OQ>(x, zero),
);
y = _mm256_blendv_ps(y, special, outside);
_mm256_blendv_ps(
y,
_mm256_set1_ps(f32::INFINITY),
_mm256_cmp_ps::<_CMP_EQ_OQ>(x, _mm256_set1_ps(f32::INFINITY)),
)
}
}
unsafe {
let p = buf.as_mut_ptr();
for i in (0..buf.len()).step_by(8) {
_mm256_store_ps(p.add(i), ln8(_mm256_load_ps(p.add(i))));
}
}
}
routine_ew_rust!(x86_64;
f32,
x86_64_avx512_ln_f32_64n,
64,
16,
#[inline(never)]
fn run(buf: &mut [f32], _: ()) {
debug_assert!(buf.len() % Self::nr() == 0);
debug_assert!(buf.as_ptr() as usize % Self::alignment_bytes() == 0);
unsafe { x86_64_avx512_ln_f32_64n_run(buf) }
},
func(Ln),
isa(X86_64Avx512f)
);
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx512f")]
unsafe fn x86_64_avx512_ln_f32_64n_run(buf: &mut [f32]) {
use crate::generic::ln::{LN2_HI, LN2_LO, POLY, SPLIT, SUBNORMAL_SCALE, SUBNORMAL_SHIFT};
use std::arch::x86_64::*;
#[inline(always)]
unsafe fn ln16(x: __m512) -> __m512 {
unsafe {
let one = _mm512_set1_ps(1.0);
let zero = _mm512_setzero_ps();
let subnormal = _mm512_cmp_ps_mask::<_CMP_LT_OQ>(x, _mm512_set1_ps(f32::MIN_POSITIVE));
let scaled = _mm512_mask_mul_ps(x, subnormal, x, _mm512_set1_ps(SUBNORMAL_SCALE));
let bits = _mm512_castps_si512(scaled);
let mut exponent =
_mm512_sub_epi32(_mm512_srli_epi32::<23>(bits), _mm512_set1_epi32(127));
exponent = _mm512_mask_sub_epi32(
exponent,
subnormal,
exponent,
_mm512_set1_epi32(SUBNORMAL_SHIFT),
);
let mantissa = _mm512_or_ps(
_mm512_and_ps(scaled, _mm512_castsi512_ps(_mm512_set1_epi32(0x007fffff))),
one,
);
let split = _mm512_cmp_ps_mask::<_CMP_GT_OQ>(mantissa, _mm512_set1_ps(SPLIT));
let mantissa = _mm512_mask_mul_ps(mantissa, split, mantissa, _mm512_set1_ps(0.5));
exponent = _mm512_mask_add_epi32(exponent, split, exponent, _mm512_set1_epi32(1));
let e = _mm512_cvtepi32_ps(exponent);
let f = _mm512_sub_ps(mantissa, one);
let mut p = _mm512_set1_ps(POLY[0]);
for c in &POLY[1..] {
p = _mm512_fmadd_ps(p, f, _mm512_set1_ps(*c));
}
let f2 = _mm512_mul_ps(f, f);
let mut y = _mm512_mul_ps(_mm512_mul_ps(p, f2), f);
y = _mm512_fmadd_ps(e, _mm512_set1_ps(LN2_LO), y);
y = _mm512_add_ps(_mm512_fnmadd_ps(_mm512_set1_ps(0.5), f2, y), f);
y = _mm512_fmadd_ps(e, _mm512_set1_ps(LN2_HI), y);
let outside = _mm512_cmp_ps_mask::<_CMP_NGT_UQ>(x, zero);
let special = _mm512_mask_blend_ps(
_mm512_cmp_ps_mask::<_CMP_EQ_OQ>(x, zero),
_mm512_set1_ps(f32::NAN),
_mm512_set1_ps(f32::NEG_INFINITY),
);
y = _mm512_mask_blend_ps(outside, y, special);
_mm512_mask_blend_ps(
_mm512_cmp_ps_mask::<_CMP_EQ_OQ>(x, _mm512_set1_ps(f32::INFINITY)),
y,
_mm512_set1_ps(f32::INFINITY),
)
}
}
unsafe {
let p = buf.as_mut_ptr();
for i in (0..buf.len()).step_by(16) {
_mm512_store_ps(p.add(i), ln16(_mm512_load_ps(p.add(i))));
}
}
}