fix: Remove faulty `popcnt` features checks for MSVC [#4872] (#4886)

The `popcnt` feature checks weren't actually checking the ISA feature
or cpuid. This caused an illegal instruction exception on x86 hardware
that doesn't support `popcnt` when compiled with MSVC.

Since MSVC doesn't support any x86 ISA defines, the only way to check
for `popcnt` is with cpuid. Since this is a tiny inline function,
dynamic dispatch is likley not worth it so just removing the MSVC
for `popcnt`. MSVC will now fallback to the generic implementation.
This commit is contained in:
goldsteinn 2023-02-17 20:11:56 -06:00 committed by GitHub
parent 605c6bd031
commit 1e5546280e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 2 additions and 52 deletions

View File

@ -27,17 +27,11 @@
#define TR_HAVE_BUILTIN_POPCOUNT
#endif
#endif
#if defined(__x86_64__) && defined(__SSE__)
#if (defined(__x86_64__) || defined(__i386__)) && defined(__POPCNT__)
#define TR_HAVE_ASM_POPCNT
#endif
#endif
#if defined(_MSC_VER)
#if defined(_M_X64) || defined(_M_IX86)
#include <nmmintrin.h>
#endif
#endif
#if defined(TR_HAVE_STD_POPCOUNT)
#include <bit>
#endif
@ -65,7 +59,7 @@ struct tr_popcnt
return static_cast<unsigned>(std::popcount(unsigned_v));
}
#elif defined(TR_HAVE_BUILTIN_POPCOUNT) && defined(TR_HAVE_ASM_POPCNT)
#elif defined(TR_HAVE_BUILTIN_POPCOUNT)
/* Use __builtin as opposed to straight assembly to avoid any
strain the latter puts on the optimized. */
static inline unsigned count(T v)
@ -95,50 +89,6 @@ struct tr_popcnt
return __builtin_popcount(unsigned_v);
}
}
#elif defined(_MSC_VER) && defined(_M_X64)
/* 64-bit x86 intrinsics. */
static inline unsigned count(T v)
{
if constexpr (sizeof(T) == sizeof(uint64_t))
{
return _mm_popcnt_u64(v);
}
else if constexpr (sizeof(T) == sizeof(uint32_t))
{
return _mm_popcnt_u32(v);
}
else
{
static_assert(sizeof(T) < sizeof(uint32_t));
/* Need to avoid sign extension. */
unsigned_T unsigned_v = static_cast<unsigned_T>(v);
return _mm_popcnt_u32(unsigned_v);
}
}
#elif defined(_MSC_VER) && defined(_M_IX86)
/* 32-bit x86 intrinsics. */
static inline unsigned count(T v)
{
if constexpr (sizeof(T) == sizeof(uint64_t))
{
/* Avoid signed shift. */
unsigned_T unsigned_v = static_cast<unsigned_T>(v);
return _mm_popcnt_u32(static_cast<uint32_t>(unsigned_v)) + _mm_popcnt_u32(static_cast<uint32_t>(unsigned_v >> 32));
}
else if constexpr (sizeof(T) == sizeof(uint32_t))
{
return _mm_popcnt_u32(v);
}
else
{
static_assert(sizeof(T) < sizeof(uint32_t));
/* Need to avoid sign extension. */
unsigned_T unsigned_v = static_cast<unsigned_T>(v);
return _mm_popcnt_u32(unsigned_v);
}
}
#elif defined(TR_HAVE_ASM_POPCNT)
/* raw assembly. This prohibits constexpr so may be worth dropping if there
* is need for count() to be constexpr. */