测试 256 位 YMM AVX 寄存器元素是不是等于或小于零的最有效方法

Posted

技术标签:

【中文标题】测试 256 位 YMM AVX 寄存器元素是不是等于或小于零的最有效方法【英文标题】:Most efficient way to test a 256-bit YMM AVX register element for equal or less than zero测试 256 位 YMM AVX 寄存器元素是否等于或小于零的最有效方法 【发布时间】:2015-05-11 12:44:12 【问题描述】:

我正在使用英特尔 AVX 内在函数实现粒子系统。当粒子的 Y 位置小于或等于零时,我想重置粒子。

粒子系统按如下 SOA 模式排序:

class ParticleSystem

    private:
        float*      mXPosition;
        float*      mYPosition;
        float*      mZPosition;

        .... Rest of code not important for this question

我最初想到的方法只是遍历 mYPosition 数组并检查开头所述的情况。也许使用这种方法可以提高一些性能?

然而,问题是是否有任何有效的方法来实现这一点 使用 AVX 内在函数?谢谢!

【问题讨论】:

如果其余代码比您的“检查 我不同意。如果您发布的代码与所提出的问题无关,它会被否决。初始化代码、顶点缓冲区映射和资源释放与本题无关。 “重置粒子”代码是什么样的?如果它也很简单,那么您也许可以提出一个矢量化无分支实现。 我不能说我理解这一点,但对于 avx lists.cs.uiuc.edu/pipermail/llvmbugs/2012-July/024072.html987654321@ 上的 signum 来说,它确实看起来很有趣 使用 AVX 执行此操作非常简单 - 了解 (a) 通常有多少粒子和 (b) 其中有多少可能具有 Y 位置 【参考方案1】:

如果

#include <immintrin.h>                                  // AVX intrinsics

const __m256 vk0 = _mm256_setzero_ps();                 // const vector of zeros

for (int i = 0; i + 8 <= n; i += 8)

    __m256 vy = _mm256_loadu_ps(&mYPosition[i]);        // load 8 x floats
    __m256 vcmp = _mm256_cmp_ps(vy, vk0, _CMP_LE_OS);   // compare for <= 0
    int mask = _mm256_movemask_ps(vcmp);                // get MS bits from comparison result
    if (mask != 0)                                      // if any bits set
                                                       // then we have 1 or more elements <= 0
        for (int k = 0; k < 8; ++k)                     // test each element in vector
                                                       // using scalar code...
            if ((mask & 1) != 0)
            
                // found element at index i + k
                // do something with it...
            
            mask >>= 1;
        
    

// deal with any remaining elements in case where n is not a multiple of 8
for (int j = i; j < n; ++j)

    if (mYPosition[j] <= 0.0f)
    
        // found element at index j
        // do something with it...
    

当然,如果匹配元素不是稀疏的,即如果您通常在每个 8 个向量中找到一个或多个,那么这不会为您带来任何性能提升。但是,如果元素是稀疏的,从而可以跳过大多数向量,那么您应该会看到显着的好处。

【讨论】:

以上是关于测试 256 位 YMM AVX 寄存器元素是不是等于或小于零的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

AVX 指令 vxorpd 和 vpxor 之间的区别

AVX2:AVX 寄存器中 8 位元素的 CountTrailingZeros

有没有办法将 8bitX32 ymm 寄存器右/左洗牌 N 个位置(c++)

ASM x86_64 AVX:xmm 和 ymm 寄存器差异

有效地将 YMM 寄存器的低 64 位设置为常数

从填充为 0 的数组加载到 256 位 AVX2 寄存器