sinonimo - ¿Cómo usar los intrínsecos de MSVC para obtener el equivalente de este código de GCC?
semiconductores intrínsecos y extrínsecos (4)
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
¿Qué funciones necesito llamar, qué encabezados necesito incluir, etc. para agregar un ifdef adecuado 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 compilación. Como alguien que realmente no usa MSVC, tampoco sé si estos intrínsecos tienen C equivalentes en otras arquitecturas, o si también tengo que #ifdef x86 / x86_64 cuando #definirlos.
Probado en Linux y Windows (x86):
#ifdef WIN32
#include <intrin.h>
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;
}
Rebotando del código sh0dan, la implementación debería corregirse así:
#ifdef _MSC_VER
#include <intrin.h>
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
Hay dos intrínsecos "_BitScanForward" y "_BitScanReverse", que se ajustan al mismo propósito para MSVC. Incluir Las funciones son:
#ifdef _MSC_VER
#include <intrin.h>
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í:
Si MSVC tiene un compilador intrínseco para esto, estará aquí:
Intrinsics del compilador en MSDN
De lo contrario, tendrás que escribirlo usando __asm