【问题标题】:Convert bit vector to one bit将位向量转换为一位
【发布时间】:2013-11-24 08:38:59
【问题描述】:

对于非零无符号整数值,是否有一种有效的方法来获取 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 页面,但发现只有使用布尔条件的条件设置/清除掩码的描述,因此从 intbool 的转换应该在方法。

如果没有通用的方法来解决这个问题,我如何使用 x86 汇编代码有效地解决这个问题?

【问题讨论】:

    标签: performance assembly x86 bit-manipulation operations


    【解决方案1】:

    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 位,而不是全部翻转。)

    【讨论】:

      【解决方案2】:

      在 x86 中执行此操作的常用方法是:

      test eax, eax
      setne al
      

      【讨论】:

      • 但这并不是没有分支的。
      • 我在这里将无分支解释为没有 jmp 指令。 Shifting 和 xor hack 可能会更慢。
      • 谢谢!顺便说一句,你为什么认为它几乎没有分支? 'setne' 是一个耗时的操作吗?
      • zf 只是 eflags 寄存器的一部分,就像所有其他寄存器一样。它可能比任何移位加法或异或指令都快。很多 c++ 编译器实际上会发出这种代码。
      【解决方案3】:

      您可以使用!! to coerce a value to 0 or 1 并像这样重写表达式

      return !!(x & masks[0]) | (!!(x & masks[1]) << 1) |
             (!!(x & masks[2]) << 2) | (!!(x & masks[3]) << 3);
      

      【讨论】:

        猜你喜欢
        • 2016-07-10
        • 2023-04-06
        • 1970-01-01
        • 1970-01-01
        • 2016-10-29
        • 2023-04-10
        • 2018-06-27
        • 1970-01-01
        • 2011-08-15
        相关资源
        最近更新 更多