我需要检查所有向量元素是否为非零.到目前为止,我找到了以下解 有一个更好的方法吗?我在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
通常会从包含此函数的任何循环中提取归零,因此在循环内使用时,上述序列应减少一条指令.
使用直接的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
通常会从包含此函数的任何循环中提取归零,因此在循环内使用时,上述序列应减少一条指令.