【问题标题】:SIMD/SSE: How to check that all vector elements are non-zeroSIMD/SSE:如何检查所有向量元素是否非零
【发布时间】:2016-03-13 08:58:03
【问题描述】:

我需要检查所有向量元素是否非零。到目前为止,我找到了以下解决方案。有一个更好的方法吗?我在 Linux/x86_64 上使用 gcc 4.8.2,指令最高 SSE4.2。

typedef char ChrVect __attribute__((vector_size(16), aligned(16)));

inline bool testNonzero(ChrVect vect)
{
    const ChrVect vzero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    return (0 == (__int128_t)(vzero == vect));
}

更新:上面的代码被编译为以下汇编代码(当编译为非内联函数时):

movdqa  %xmm0, -24(%rsp)
pxor    %xmm0, %xmm0
pcmpeqb -24(%rsp), %xmm0
movdqa  %xmm0, -24(%rsp)
movq    -24(%rsp), %rax
orq -16(%rsp), %rax
sete    %al
ret

【问题讨论】:

  • 您对哪种架构感兴趣? x86?力量?手臂? ...?
  • x86_64,指令最高 SSE4.2
  • @i486: 这只是一种编码风格,当你把常量放在首位时编译器会在你错误地使用 = 而不是 == 时报错。
  • 您的代码与您的问题不符。您的问题想知道是否所有元素都非零。但是您的代码会检查 any 元素是否非零。
  • @RaymondChen:这里有两个比较。首先比较输入向量和零向量,结果创建具有单个元素比较结果的新向量。当它们都非零时,结果向量将是零向量。将其转换为 __int128_t 后,值也将为零,并且将返回 true。

标签: c++ c gcc vectorization simd


【解决方案1】:

使用直接的 SSE 内在函数,您可以这样做:

inline bool testNonzero(__m128i v)
{
    __m128i vcmp = _mm_cmpeq_epi8(v, _mm_setzero_si128());
#if __SSE4_1__  // for SSE 4.1 and later use PTEST
    return _mm_testz_si128(vcmp, vcmp);
#else           // for older SSE use PMOVMSKB
    uint32_t mask = _mm_movemask_epi8(vcmp);
    return (mask == 0);
#endif
}

我建议查看您的编译器当前为现有代码生成的内容,然后使用内部函数将其与此版本进行比较,看看是否有任何显着差异。

使用 SSE3 (clang -O3 -msse3) 我得到以下功能:

pxor    %xmm1, %xmm1
pcmpeqb %xmm1, %xmm0
pmovmskb    %xmm0, %ecx
testl   %ecx, %ecx

SSE4 版本 (clang -O3 -msse4.1) 产生:

pxor    %xmm1, %xmm1
pcmpeqb %xmm1, %xmm0
ptest   %xmm0, %xmm0

请注意,xmm1 的归零通常会从包含此函数的任何循环中提升,因此在循环内使用时,上述序列应减少一条指令。

【讨论】:

  • 谢谢。我试图将它与我的原始代码进行基准测试,它更快。当我将它用作非内联函数时,速度提升非常小——大约 2%。内联函数后,您的版本快了大约 26%。
  • ptest 在这里有用吗?
  • @PaulR 我已经这样做了,两个版本的结果几乎相同。
  • @Mysticial:ptest 似乎并不总是一个胜利,即使它保存了一条指令 - 我已经将它添加为 SSE4 和更高版本的替代品,只是为了完整性。
  • @Mysticial: ptest 如果它是一条微指令,那就太好了,但事实并非如此。 ptest / setcc 总共 3 微秒。 pmovmskb / test / setcc 也是 3 微秒。 pmovmskb / test/jcc 是 2 微秒,因为 test/jcc 宏熔断器(英特尔和 AMD)。我没有在真正的微基准测试中对ptest 进行太多实验,但至少在微量计数静态分析中,在pcmp* 结果上使用它时它永远不会获胜。它最有可能对两个不同的输入有用,而不是针对自身进行测试。无论如何,我建议不要为此使用它,即使可用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-09
  • 2014-12-19
  • 1970-01-01
  • 2013-12-15
相关资源
最近更新 更多