这就是avx浮点位逻辑运算的原因

Which is the reason for avx floating point bitwise logical operations?

本文关键字:逻辑运算 avx      更新时间:2023-10-16

AVX允许对浮点数据类型__m256和__m256d进行和/或位逻辑运算。

然而,c++不允许对浮点数和双精度数进行位操作,这是合理的。如果我是对的,浮点数的内部表示没有保证,编译器是否会使用IEEE754,因此程序员不能确定浮点数的位是什么样子的。

考虑这个例子:

#include <immintrin.h>
#include <iostream>
#include <limits>
#include <cassert>
int main() {
    float x[8] = {1,2,3,4,5,6,7,8};
    float mask[8] = {-1,0,0,-1,0,-1,0,0};
    float x_masked[8];
    assert(std::numeric_limits<float>::is_iec559);
    __m256 x_ = _mm256_load_ps(x);
    __m256 mask_ = _mm256_load_ps(mask);
    __m256 x_masked_ = _mm256_and_ps(x_,mask_);
    _mm256_store_ps(x_masked,x_masked_);
    for(int i = 0; i < 8; i++)
        std::cout << x_masked[i] << " ";
    return 0;
}

假设使用IEEE754,由于-1的表示为0xffffffff,我希望输出为

1,0,0,4,0,6,0,0

而不是

1 0 0 1.17549e-38 0 1.17549e-38 0 0

因此我对内部表示的假设可能是错误的(或者我犯了一些愚蠢的错误)。

所以问题是:有没有一种方法可以让我使用浮点逻辑并且对结果有意义的事实是安全的?

如果你使用的是AVX内部函数,那么你就知道你使用的是IEEE754浮点数,因为这就是AVX所做的。

对浮点数进行的一些有意义的位操作如下:

  • 选择,如Jens的回答,尽管在SSE4.1中,我们有blendvps及其亲属在一个指令
  • 中完成该操作
  • 绝对值(掩码)
  • 负值
  • <
  • 转移标志/gh>
  • 提取指数(稀有)

主要用于操作符号,或选择性地将整个浮点数归零,而不是用于处理指数或有效位数的单个位-您可以这样做,但很少有用。

原因是在执行单元域之间切换可能会受到惩罚,因为在切换执行单元域时可能会绕过-delay -when-switching- execution_unit -domains和why-do-some-sse-mov-instructions-specify-that-they-move-floating-point-values。在本例中,从浮点AVX执行单元切换到整数AVX执行单元。

例如,你想比较浮点AVX寄存器xy

z = _mm256_cmp_ps(x, y, 1);

AVX寄存器z包含布尔整数值(0或-1),然后您可以使用_mm256_and_ps_mm256_and_si256进行逻辑与。但是_mm256_and_ps保持在同一个执行单元,_mm256_and_si256切换单元,这可能会导致旁路延迟。

编辑:关于浮点数的位运算符在c++中当然是可能的,有时是有用的。这里有一些简单的例子。

union {
    float f;
    int i;
} u;
u.i ^= 0x80000000; // flip sign bit of u.f
u.i &= 0x7FFFFFFF; // set sign bit to zero //take absolute value

程序员可以完全确定如何表示单精度浮点数。函数如何实现是另一回事。我已经利用位运算来实现符合IEEE-754的半精度浮点数。早在2003年,在IBM为此申请专利之前,我就已经使用了分支删除操作。

static inline __m128 _mm_sel_ps(__m128 a, __m128 b, __m128 mask ) {
    b = _mm_and_ps( b, mask );
    a = _mm_andnot_ps( mask, a );
    return _mm_or_ps( a, b );
}

这个例子演示了如何使用SSE2删除一个浮点分支。使用AVX也可以达到同样的效果。如果您尝试(使用相同的技术)使用标量删除分支,由于上下文的切换,您将无法获得任何性能(适用于x86 -不适用于ARM,其中您有fpsel操作)