代码之家  ›  专栏  ›  技术社区  ›  Dark Shikari

如何使用msvc内部函数来获得与此gcc代码等价的代码?

  •  12
  • Dark Shikari  · 技术社区  · 17 年前

    下面的代码调用gcc中clz/ctz的内置函数,在其他系统上,它有c版本。显然,如果系统有内置的clz/ctz指令,比如x86和arm,那么c版本就有点次优了。

    #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
    

    我需要调用哪些函数,需要包含哪些头,等等来为msvc添加适当的ifdef?我已经看过了 this page ,但我不完全确定pragma的用途(是否必需?)以及它对msvc版本编译要求的限制。作为一个并不真正使用msvc的人,我也不知道这些内部函数在其他架构上是否有c等价物,或者我是否必须定义它们。

    4 回复  |  直到 9 年前
        1
  •  19
  •   crazyjul    12 年前

    从sh0dan代码跳转过来,应该像这样更正实现:

    #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
    

    如代码中所述,如果值为0,则ctz和clz都是未定义的。在我们的抽象中,我们修正了 __builtin_clz(value) 作为 (value?__builtin_clz(value):32) 但这是个选择

        2
  •  1
  •   GregC Benjamin Baumann    9 年前

    如果msvc有一个用于此的编译器,它将在这里:

    Compiler Intrinsics on MSDN

    否则,您必须使用

        3
  •  -3
  •   Tanguy    11 年前

    在Linux和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;
    }
    
        4
  •  -3
  •   GregC Benjamin Baumann    9 年前

    有两个内部函数“_bitscanforward”和“_bitscanreverse”,它们适用于msvc。包括在内。功能包括:

    #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
    

    有等效的64位版本“_BitScanForward64”和“_BitScanReverse64”。

    请在此处阅读更多内容:

    x86 Intrinsics on MSDN

    推荐文章