¿Cómo usar los intrínsecos de MSVC para obtener el equivalente de este código de GCC?

El siguiente código llama a las funciones integradas para clz / ctz en GCC y, en otros sistemas, tiene versiones C. Obviamente, las versiones C son un poco subóptimas si el sistema tiene una instrucción clz / ctz incorporada, como x86 y ARM.

#ifdef __GNUC__ #define clz(x) __builtin_clz(x) #define ctz(x) __builtin_ctz(x) #else static uint32_t ALWAYS_INLINE popcnt( uint32_t x ) { x -= ((x >> 1) & 0x55555555); x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); x = (((x >> 4) + x) & 0x0f0f0f0f); x += (x >> 8); x += (x >> 16); return x & 0x0000003f; } static uint32_t ALWAYS_INLINE clz( uint32_t x ) { x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return 32 - popcnt(x); } static uint32_t ALWAYS_INLINE ctz( uint32_t x ) { return popcnt((x & -x) - 1); } #endif 

¿A qué funciones debo llamar, qué encabezados necesito incluir, etc. para agregar un ifdef apropiado para MSVC aquí? Ya he consultado esta página , pero no estoy seguro de para qué sirve #pragma (¿es obligatorio?) Y qué restricciones impone a los requisitos de la versión de MSVC para la comstackción. Como alguien que realmente no usa MSVC, tampoco sé si estos intrínsecos tienen C equivalentes en otras architectures, o si también tengo que #ifdef x86 / x86_64 cuando #definirlos.

Rebotando del código sh0dan, la implementación debería corregirse así:

 #ifdef _MSC_VER #include  uint32_t __inline ctz( uint32_t value ) { DWORD trailing_zero = 0; if ( _BitScanForward( &trailing_zero, value ) ) { return trailing_zero; } else { // This is undefined, I better choose 32 than 0 return 32; } } uint32_t __inline clz( uint32_t value ) { DWORD leading_zero = 0; if ( _BitScanReverse( &leading_zero, value ) ) { return 31 - leading_zero; } else { // Same remarks as above return 32; } } #endif 

Como se comenta en el código, tanto ctz como clz no están definidos si el valor es 0. En nuestra abstracción, hemos corregido __builtin_clz(value) como (value?__builtin_clz(value):32) pero es una elección

Si MSVC tiene un comstackdor intrínseco para esto, estará aquí:

Intrinsics del comstackdor en MSDN

De lo contrario, tendrás que escribirlo usando __asm

Probado en Linux y Windows (x86):

 #ifdef WIN32 #include  static uint32_t __inline __builtin_clz(uint32_t x) { unsigned long r = 0; _BitScanReverse(&r, x); return (31-r); } #endif uint32_t clz64(const uint64_t x) { uint32_t u32 = (x >> 32); uint32_t result = u32 ? __builtin_clz(u32) : 32; if (result == 32) { u32 = x & 0xFFFFFFFFUL; result += (u32 ? __builtin_clz(u32) : 32); } return result; } 

Hay dos intrínsecos “_BitScanForward” y “_BitScanReverse”, que se ajustan al mismo propósito para MSVC. Incluir Las funciones son:

 #ifdef _MSC_VER #include  static uint32_t __inline ctz( uint32_t x ) { int r = 0; _BitScanReverse(&r, x); return r; } static uint32_t __inline clz( uint32_t x ) { int r = 0; _BitScanForward(&r, x); return r; } #endif 

Hay versiones equivalentes de 64 bits “_BitScanForward64” y “_BitScanReverse64”.

Leer más aquí:

Intrinsics x86 en MSDN