对于非零无符号整数值,是否有一种有效的方法可以获得0x00000001或0xFFFFFFFF,而在没有分支的情况下,有0可以获得零值吗?
我想测试几个蒙版并根据它创建另一个蒙版。基本上,我想优化以下代码:
unsigned getMask(unsigned x, unsigned masks[4])
{
return (x & masks[0] ? 1 : 0) | (x & masks[1] ? 2 : 0) |
(x & masks[2] ? 4 : 0) | (x & masks[3] ? 8 : 0);
}
我知道有些优化编译器可以处理这个问题,但即使是这样,他们究竟是如何做到的呢?我查看了 Bit twiddling hacks 页面,但发现只有使用布尔条件的条件设置/清除掩码的描述,因此从int
到bool
的转换应该在方法之外完成。
如果没有通用的方法来解决这个问题,我怎样才能有效地使用x86汇编程序代码呢?
答案 0 :(得分:2)
x86 SSE2只需几条指令即可完成此操作,最重要的是movmskps
,它将SIMD向量的每个4字节元素的高位提取为整数位图。
Intel's intrinsics guide很好,另请参阅SSE tag wiki
#include <immintrin.h>
static inline
unsigned getMask(unsigned x, unsigned masks[4])
{
__m128i vx = _mm_set1_epi32(x);
__m128i vm = _mm_load_si128(masks); // or loadu if this can inline where masks[] isn't aligned
__m128i and = _mm_and_si128(vx, vm);
__m128i eqzero = _mm_cmpeq_epi32(and, _mm_setzero_si128()); // vector of 0 or -1 elems
unsigned zeromask = _mm_movemask_ps(_mm_castsi128_ps(eqzero));
return zeromask ^ 0xf; // flip the low 4 bits
}
直到AVX512,没有SIMD cmpneq
,因此最好的选择是提取掩码后进行标量XOR。 (我们只想翻转低4位,而不是全部用NOT翻转。)
答案 1 :(得分:1)
在x86中执行此操作的常用方法是:
test eax, eax
setne al
答案 2 :(得分:1)
您可以使用!!
to coerce a value to 0 or 1并像这样重写表达式
return !!(x & masks[0]) | (!!(x & masks[1]) << 1) |
(!!(x & masks[2]) << 2) | (!!(x & masks[3]) << 3);