Skip to content

Commit 04f3d21

Browse files
DiamonDinoiaserge-sans-paille
authored andcommitted
perf: native sse2 trunc for batch<double>
The common trunc is select(abs(x) < maxflint, to_float(to_int(x)), x), so on sse2 it goes through batch_cast<int64_t>. Adding 2^52 rounds |x| to an integer in any rounding mode and one conditional decrement turns that into floor, which needs no conversion at all. 3.743 -> 0.551 ns/element on a 128 KB L2-resident loop (Xeon w5-3435X, gcc 13.3 -O3, min of 300 reps). Assisted-by: Claude Opus 5 <noreply@anthropic.com>
1 parent eb416dd commit 04f3d21

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

‎include/xsimd/arch/xsimd_sse2.hpp‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,6 +2259,26 @@ namespace xsimd
22592259
transpose(reinterpret_cast<batch<double, A>*>(matrix_begin), reinterpret_cast<batch<double, A>*>(matrix_end), A {});
22602260
}
22612261

2262+
// trunc
2263+
template <class A>
2264+
XSIMD_INLINE batch<double, A> trunc(batch<double, A> const& self, requires_arch<sse2>) noexcept
2265+
{
2266+
// The common implementation goes through batch_cast<int64_t>, which on sse2
2267+
// is itself built on trunc. Adding 2^52 rounds |self| to an integer whatever
2268+
// the rounding mode is; one conditional decrement turns that into floor.
2269+
__m128d signmask = _mm_set1_pd(-0.);
2270+
__m128d t2n = _mm_set1_pd(4503599627370496.); // 2^52
2271+
__m128d s = _mm_and_pd(self, signmask);
2272+
__m128d v = _mm_andnot_pd(signmask, self); // |self|
2273+
__m128d d0 = _mm_add_pd(v, t2n);
2274+
detail::reassociation_barrier(d0, "prevent collapsing (v + 2^52) - 2^52 back to v");
2275+
__m128d d = _mm_sub_pd(d0, t2n);
2276+
d = _mm_sub_pd(d, _mm_and_pd(_mm_cmpgt_pd(d, v), _mm_set1_pd(1.))); // floor(|self|)
2277+
d = _mm_andnot_pd(signmask, d); // roundTowardNegative makes 2^52 - 2^52 negative
2278+
__m128d small = _mm_cmplt_pd(v, t2n);
2279+
return _mm_or_pd(s, _mm_or_pd(_mm_and_pd(small, d), _mm_andnot_pd(small, v)));
2280+
}
2281+
22622282
// zip_hi
22632283
template <class A>
22642284
XSIMD_INLINE batch<float, A> zip_hi(batch<float, A> const& self, batch<float, A> const& other, requires_arch<sse2>) noexcept

0 commit comments

Comments
 (0)