routine_map_reduce_rust!(x86_64;
f32,
x86_64_fma_softmax2_f32_32n,
32,
8,
#[inline(never)]
fn run(buf: &mut [f32], max: f32) -> f32 {
assert!(buf.len() % 32 == 0);
unsafe { x86_64_fma_softmax2_f32_32n_run(buf, max) }
},
op(Softmax2),
isa(X86_64Avx2, X86_64Fma)
);
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2,fma")]
unsafe fn x86_64_fma_softmax2_f32_32n_run(buf: &mut [f32], max: f32) -> f32 {
use std::arch::x86_64::*;
#[inline(always)]
unsafe fn exp8(x: __m256) -> __m256 {
unsafe {
let k = _mm256_cvtps_epi32(_mm256_mul_ps(x, _mm256_set1_ps(1.442_695_04)));
let kf = _mm256_cvtepi32_ps(k);
let mut rr = _mm256_fnmadd_ps(kf, _mm256_set1_ps(0.693_145_75), x);
rr = _mm256_fnmadd_ps(kf, _mm256_set1_ps(1.428_606_8e-6), rr);
let mut q = _mm256_set1_ps(8.297653546e-03);
q = _mm256_fmadd_ps(q, rr, _mm256_set1_ps(4.191538191e-02));
q = _mm256_fmadd_ps(q, rr, _mm256_set1_ps(1.666757475e-01));
q = _mm256_fmadd_ps(q, rr, _mm256_set1_ps(4.999889485e-01));
q = _mm256_fmadd_ps(q, rr, _mm256_set1_ps(9.999996920e-01));
q = _mm256_fmadd_ps(q, rr, _mm256_set1_ps(1.000000072e+00));
let biased = _mm256_max_epi32(
_mm256_min_epi32(
_mm256_add_epi32(k, _mm256_set1_epi32(127)),
_mm256_set1_epi32(254),
),
_mm256_set1_epi32(1),
);
let scale = _mm256_castsi256_ps(_mm256_slli_epi32::<23>(biased));
let out = _mm256_or_ps(
_mm256_cmp_ps::<_CMP_LT_OQ>(x, _mm256_set1_ps(-103.0)),
_mm256_cmp_ps::<_CMP_GT_OQ>(x, _mm256_set1_ps(0.0)),
);
_mm256_blendv_ps(_mm256_mul_ps(q, scale), _mm256_setzero_ps(), out)
}
}
unsafe {
let vm = _mm256_set1_ps(max);
let mut a0 = _mm256_setzero_ps();
let mut a1 = _mm256_setzero_ps();
let mut a2 = _mm256_setzero_ps();
let mut a3 = _mm256_setzero_ps();
let p = buf.as_mut_ptr();
let n = buf.len();
let mut i = 0;
while i + 32 <= n {
let y0 = exp8(_mm256_sub_ps(_mm256_load_ps(p.add(i)), vm));
let y1 = exp8(_mm256_sub_ps(_mm256_load_ps(p.add(i + 8)), vm));
let y2 = exp8(_mm256_sub_ps(_mm256_load_ps(p.add(i + 16)), vm));
let y3 = exp8(_mm256_sub_ps(_mm256_load_ps(p.add(i + 24)), vm));
_mm256_store_ps(p.add(i), y0);
_mm256_store_ps(p.add(i + 8), y1);
_mm256_store_ps(p.add(i + 16), y2);
_mm256_store_ps(p.add(i + 24), y3);
a0 = _mm256_add_ps(a0, y0);
a1 = _mm256_add_ps(a1, y1);
a2 = _mm256_add_ps(a2, y2);
a3 = _mm256_add_ps(a3, y3);
i += 32;
}
let acc = _mm256_add_ps(_mm256_add_ps(a0, a1), _mm256_add_ps(a2, a3));
let mut s = _mm_add_ps(_mm256_castps256_ps128(acc), _mm256_extractf128_ps::<1>(acc));
s = _mm_add_ps(s, _mm_movehl_ps(s, s));
s = _mm_add_ss(s, _mm_shuffle_ps::<1>(s, s));
_mm_cvtss_f32(s)
}
}
routine_map_reduce_rust!(x86_64;
f32,
x86_64_avx512_softmax2_f32_64n,
64,
16,
#[inline(never)]
fn run(buf: &mut [f32], max: f32) -> f32 {
assert!(buf.len() % 64 == 0);
unsafe { x86_64_avx512_softmax2_f32_64n_run(buf, max) }
},
op(Softmax2),
isa(X86_64Avx512f)
);
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx512f")]
unsafe fn x86_64_avx512_softmax2_f32_64n_run(buf: &mut [f32], max: f32) -> f32 {
use std::arch::x86_64::*;
#[inline(always)]
unsafe fn exp16(x: __m512) -> __m512 {
unsafe {
let k = _mm512_cvtps_epi32(_mm512_mul_ps(x, _mm512_set1_ps(1.442_695_04)));
let kf = _mm512_cvtepi32_ps(k);
let mut rr = _mm512_fnmadd_ps(kf, _mm512_set1_ps(0.693_145_75), x);
rr = _mm512_fnmadd_ps(kf, _mm512_set1_ps(1.428_606_8e-6), rr);
let mut q = _mm512_set1_ps(8.297653546e-03);
q = _mm512_fmadd_ps(q, rr, _mm512_set1_ps(4.191538191e-02));
q = _mm512_fmadd_ps(q, rr, _mm512_set1_ps(1.666757475e-01));
q = _mm512_fmadd_ps(q, rr, _mm512_set1_ps(4.999889485e-01));
q = _mm512_fmadd_ps(q, rr, _mm512_set1_ps(9.999996920e-01));
q = _mm512_fmadd_ps(q, rr, _mm512_set1_ps(1.000000072e+00));
let biased = _mm512_max_epi32(
_mm512_min_epi32(
_mm512_add_epi32(k, _mm512_set1_epi32(127)),
_mm512_set1_epi32(254),
),
_mm512_set1_epi32(1),
);
let scale = _mm512_castsi512_ps(_mm512_slli_epi32::<23>(biased));
let out = _mm512_cmp_ps_mask::<_CMP_LT_OQ>(x, _mm512_set1_ps(-103.0))
| _mm512_cmp_ps_mask::<_CMP_GT_OQ>(x, _mm512_set1_ps(0.0));
_mm512_mask_blend_ps(out, _mm512_mul_ps(q, scale), _mm512_setzero_ps())
}
}
unsafe {
let vm = _mm512_set1_ps(max);
let mut a0 = _mm512_setzero_ps();
let mut a1 = _mm512_setzero_ps();
let mut a2 = _mm512_setzero_ps();
let mut a3 = _mm512_setzero_ps();
let p = buf.as_mut_ptr();
let n = buf.len();
let mut i = 0;
while i + 64 <= n {
let y0 = exp16(_mm512_sub_ps(_mm512_load_ps(p.add(i)), vm));
let y1 = exp16(_mm512_sub_ps(_mm512_load_ps(p.add(i + 16)), vm));
let y2 = exp16(_mm512_sub_ps(_mm512_load_ps(p.add(i + 32)), vm));
let y3 = exp16(_mm512_sub_ps(_mm512_load_ps(p.add(i + 48)), vm));
_mm512_store_ps(p.add(i), y0);
_mm512_store_ps(p.add(i + 16), y1);
_mm512_store_ps(p.add(i + 32), y2);
_mm512_store_ps(p.add(i + 48), y3);
a0 = _mm512_add_ps(a0, y0);
a1 = _mm512_add_ps(a1, y1);
a2 = _mm512_add_ps(a2, y2);
a3 = _mm512_add_ps(a3, y3);
i += 64;
}
_mm512_reduce_add_ps(_mm512_add_ps(_mm512_add_ps(a0, a1), _mm512_add_ps(a2, a3)))
}
}