XCode和_bittest函数 [英] XCode and _bittest function

查看:90
本文介绍了XCode和_bittest函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个为Win32开发的C ++项目,我想将其移植到OSX.该代码使用了 _bittest _bittest64 之类的函数,但在XCode头文件中找不到相同的函数.

这些功能的替代方案是什么?可能有工作良好的polyfill.该项目确实是一个遗产,目前不需要任何额外的性能.

解决方案

位测试指令,特别是 x86 bt 来检查从零开始的索引.

使用内存操作数, bt 具有疯狂的CISC位串行为,其中位索引可以超出寻址模式选择的内存的dword/qword之外.这很慢,并且为什么编译器会先将操作数加载到寄存器中.但这就是MSVC内在函数的目的.否则,它不必是内在的.

以下C ++匹配 bt 指令的register-arg版本的行为,将移位计数包装在寄存器宽度处,即仅查看低位.(如果 b 是< 32或< 64 ,则与MSVC固有的相匹配..)请参阅更新后的代码和注释,以了解如何实现MSVC语义,使其可以在指向的 long long long 之外进行访问.

还要注意, long 在x64 Windows ABI中是32位类型,但是在x86-64 System V ABI(您在OS X上使用,除非您构建过时的32位代码).您可能需要将代码更改为 int32_t uint32_t ,以避免在每个 long 中保留未使用的位,具体取决于您的使用方式.

 内联unsigned char bittest(long const * a,long b){自动const值{* a};自动const mask {1L<<(b& 31)};自动const masked_value {值&面具 };返回未签名的char {masked_value!= 0};}排队unsigned char bittest64(long long const * a,long long b){自动const值{* a};自动const mask {1LL<<(b& 63)};自动const masked_value {值&面具 };返回未签名的char {masked_value!= 0};} 

我不知道具有相同功能的任何GCC或Clang内在函数.如果需要,您可以改为从函数实现中发出汇编指令,但是带有内存操作数的 bt 速度较慢,因此通常最好在纯C ++中实现,并让编译器做好./p>

更新:

在讨论了从内在函数发出的代码之后,很明显,以前提出的替换代码仅涵盖部分功能.特别是,内在函数允许索引由 * a 占用的内存之外的位.以下实现方式也可以解决这个问题.

 内联unsigned char bittest(std :: int32_t const * a,std :: int32_t b){自动const位{reinterpret_cast< unsigned char const *>(a)};自动const值{位[b>>3]};auto const mask {(unsigned char)(1<<(b& 7))};return(value& mask)!= 0;}排队无符号字符bittest64(std :: int64_t const * a,std :: int64_t b){自动const位{reinterpret_cast< unsigned char const *>(a)};自动const值{位[b>>3]};auto const mask {(unsigned char)(1<<(b& 7))};return(value& mask)!= 0;} 

I've got a little C++ project that was developed for Win32 and I want to port it to OSX. The code uses functions like _bittest and _bittest64 but I haven't found same functions in the XCode header files.

What could be an alternative for these functions? May be there are good working polyfills. The project is a legacy indeed, no extra performance is required at the moment.

解决方案

The _bittest and _bittest64 symbols are compiler intrinsics, that emit Bit-test instructions, specifically x86 bt, to examine the value of a bit at a zero-based index.

With a memory operand, bt has crazy-CISC bitstring behaviour where the bit index can go outside the dword/qword of memory selected by the addressing mode. This is slow and why compilers will load the operand into a register first. But this is what the MSVC intrinsic is for. Otherwise it wouldn't need to be an intrinsic.

The following C++ matches the behaviour of register-arg version of the bt instruction, wrapping the shift count at the register width, i.e. effectively looking only at the low bits. (This matches the MSVC intrinsic if b is <32 or <64.) See the updated code and comments for discussion of how to implement the MSVC semantics which let it access outside the pointed-to long or long long.

Also beware that long is a 32-bit type in the x64 Windows ABI, but a 64-bit type in the x86-64 System V ABI (which you're using on OS X, unless you build obsolete 32-bit code). You may want to change your code to int32_t or uint32_t to avoid leaving unused bits in each long, depending on how you're using it.

inline
unsigned char bittest(long const *a, long b)
{
    auto const value{ *a };
    auto const mask{ 1L << (b&31) };
    auto const masked_value{ value & mask };
    return unsigned char{ masked_value != 0 };
}

inline
unsigned char bittest64(long long const *a, long long b)
{
    auto const value{ *a };
    auto const mask{ 1LL << (b&63) };
    auto const masked_value{ value & mask };
    return unsigned char{ masked_value != 0 };
}

I'm not aware of any GCC or Clang intrinsics with identical functionality. If needed, you could resort to emitting assembly instructions from the function implementations instead, but bt with a memory operand is slow so it's normally best to implement in pure C++ and let the compiler do a good job.

Update:

After discussing the code emitted from the intrinsics, it has become clear, that the previously proposed replacement code only covers part of the functionality. In particular, the intrinsics allow indexing bits outside the memory occupied by *a. The following implementations account for that as well.

inline
unsigned char bittest(std::int32_t const *a, std::int32_t b)
{
    auto const bits{ reinterpret_cast<unsigned char const*>(a) };
    auto const value{ bits[b >> 3] };
    auto const mask{ (unsigned char)(1 << (b & 7)) };
    return (value & mask) != 0;
}

inline
unsigned char bittest64(std::int64_t const *a, std::int64_t b)
{
    auto const bits{ reinterpret_cast<unsigned char const*>(a) };
    auto const value{ bits[b >> 3] };
    auto const mask{ (unsigned char)(1 << (b & 7)) };
    return (value & mask) != 0;
}

这篇关于XCode和_bittest函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆