More robust popcnt

This commit is contained in:
Waldemar Pawlaszek 2022-07-31 22:26:59 +02:00
parent a9afcf873c
commit 5feba3a716

View file

@ -26,39 +26,11 @@
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#if defined(i386) || defined(__i386__) || defined(__i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) #if defined( _MSC_VER )
#define IS_INTEL
#endif
#ifdef IS_INTEL
#if defined ( _MSC_VER )
#include <intrin.h> #include <intrin.h>
static void cpuid( int info[4], int infoType ) static uint32_t popcnt_generic( uint32_t x )
{
__cpuidex( info, infoType, 0 );
}
#else
#include <cpuid.h>
static void cpuid( int info[4], int infoType )
{
__cpuid_count( infoType, 0, info[0], info[1], info[2], info[3] );
}
#endif
#endif
namespace Lynx
{
namespace
{
static constexpr int64_t CNT_MAX = std::numeric_limits<int64_t>::max() & ~15;
uint32_t popcnt_generic( uint32_t x )
{ {
int v = 0; int v = 0;
while ( x != 0 ) while ( x != 0 )
@ -69,18 +41,60 @@ uint32_t popcnt_generic( uint32_t x )
return v; return v;
} }
#ifdef IS_INTEL #if defined( _M_IX86 ) || defined( _M_X64 )
uint32_t popcnt_intrinsic( uint32_t x )
static uint32_t popcnt_intrinsic( uint32_t x )
{ {
#if defined ( _MSC_VER )
return __popcnt( x ); return __popcnt( x );
#else
return __builtin_popcount( x );
#endif
} }
static uint32_t( *popcnt )( uint32_t );
//detecting popcnt availability on msvc intel
static void selectPOPCNT()
{
int info[4];
__cpuid( info, 1 );
if ( ( info[2] & ( (int)1 << 23 ) ) != 0 )
{
popcnt = &popcnt_intrinsic;
}
else
{
popcnt = &popcnt_generic;
}
}
#else //defined( _M_IX86 ) || defined( _M_X64 )
//MSVC non INTEL should use generic implementation
inline void selectPOPCNT()
{
}
#define popcnt popcnt_generic
#endif #endif
static uint32_t( *popcnt )( uint32_t x ); #else //defined( _MSC_VER )
//non MVSC should use builtin implementation
inline void selectPOPCNT()
{
}
#define popcnt __builtin_popcount
#endif
namespace Lynx
{
namespace
{
static constexpr int64_t CNT_MAX = std::numeric_limits<int64_t>::max() & ~15;
int32_t clamp( int32_t v, int32_t lo, int32_t hi ) int32_t clamp( int32_t v, int32_t lo, int32_t hi )
{ {
@ -526,23 +540,8 @@ private:
Mikey::Mikey( uint32_t sampleRate ) : mMikey{ std::make_unique<MikeyPimpl>() }, mQueue{ std::make_unique<ActionQueue>() }, mTick{}, mNextTick{}, mSampleRate{ sampleRate }, mSamplesRemainder{}, mTicksPerSample{ 16000000 / mSampleRate, 16000000 % mSampleRate } Mikey::Mikey( uint32_t sampleRate ) : mMikey{ std::make_unique<MikeyPimpl>() }, mQueue{ std::make_unique<ActionQueue>() }, mTick{}, mNextTick{}, mSampleRate{ sampleRate }, mSamplesRemainder{}, mTicksPerSample{ 16000000 / mSampleRate, 16000000 % mSampleRate }
{ {
selectPOPCNT();
enqueueSampling(); enqueueSampling();
//detecting popcnt availability
#ifdef IS_INTEL
int info[4];
cpuid( info, 1 );
if ( ( info[2] & ( (int)1 << 23 ) ) != 0 )
{
popcnt = &popcnt_intrinsic;
}
else
{
popcnt = &popcnt_generic;
}
#else
popcnt = &popcnt_generic;
#endif
} }
Mikey::~Mikey() Mikey::~Mikey()