当前位置:  开发笔记 > 编程语言 > 正文

SIMD/SSE:如何检查所有向量元素是否为非零

如何解决《SIMD/SSE:如何检查所有向量元素是否为非零》经验,为你挑选了1个好方法。

我需要检查所有向量元素是否为非零.到目前为止,我找到了以下解 有一个更好的方法吗?我在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

Paul R.. 7

使用直接的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通常会从包含此函数的任何循环中提取归零,因此在循环内使用时,上述序列应减少一条指令.



1> Paul R..:

使用直接的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通常会从包含此函数的任何循环中提取归零,因此在循环内使用时,上述序列应减少一条指令.


@Mysticial:如果是单个uop指令,`ptest`会很棒,但事实并非如此.`ptest` /`setcc`总计3个uops.`pmovmskb` /`test` /`setcc`也是3 uops.`pmovmskb` /`test/jcc`是2 uops,因为test/jcc宏保险丝(Intel和AMD).我没有在真正的微基准测试中对`ptest`进行太多实验,但至少在uop-counting静态分析中,它在使用'pcmp*'结果时永远不会获胜.它最有可能对两个不同的输入有用,而不是针对自身进行测试.无论如何,我建议*不要*使用它,即使可用.
@Mysticial:`ptest`看起来并不总是一场胜利,即使它保存了一条指令 - 我已经把它作为SSE4的替代品加入了,后来无论如何只是为了完整性.
推荐阅读
jerry613
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有