perf(math): scan least significand bit with MSVC x64 intrinsic

This commit is contained in:
KOKO\Mimi
2026-10-14 18:58:00 +09:00
parent 4365f133e1
commit 3576f3f6de
2 changed files with 36 additions and 1 deletions
+11 -1
View File
@@ -7,6 +7,9 @@
#include <cstring>
#include <initializer_list>
#include <limits>
#if defined(_MSC_VER) && defined(_M_X64)
#include <intrin.h>
#endif
#if defined(_M_X64) || defined(__SSE2__)
#include <xmmintrin.h>
#endif
@@ -114,8 +117,14 @@ inline int LowestBitExponent(double value) {
? -1074
: static_cast<int>(encoded_exponent) - 1075;
if (encoded_exponent != 0U) significand |= 1ULL << 52U;
#if defined(_MSC_VER) && defined(_M_X64)
// The finite, nonzero precondition makes the significand nonzero.
unsigned long trailing = 0;
_BitScanForward64(&trailing, significand);
return exponent + static_cast<int>(trailing);
#else
int trailing = 0;
// Strip large zero groups first without vendor/compiler intrinsics.
// Preserve the portable search outside the supported MSVC x64 path.
for (const int shift : {32, 16, 8, 4, 2, 1}) {
const auto mask = (1ULL << shift) - 1U;
if ((significand & mask) == 0U) {
@@ -124,6 +133,7 @@ inline int LowestBitExponent(double value) {
}
}
return exponent + trailing;
#endif
}
/// @brief Gives a product and its FMA residual when the dyadic tail fits.
/// @note Rejects underflow-risk exact tails, even if the rounded high is finite.