【发布时间】:2015-06-10 22:11:20
【问题描述】:
当使用 C 的 GCC 向量扩展时,如何检查向量上的所有值是否为零?
例如:
#include <stdint.h>
typedef uint32_t v8ui __attribute__ ((vector_size (32)));
v8ui*
foo(v8ui *mem) {
v8ui v;
for ( v = (v8ui){ 1, 1, 1, 1, 1, 1, 1, 1 };
v[0] || v[1] || v[2] || v[3] || v[4] || v[5] || v[6] || v[7];
mem++)
v &= *(mem);
return mem;
}
SSE4.2 具有 PTEST 指令,它允许运行类似于 for 条件的测试,但 GCC 生成的代码只是解包向量并一一检查单个元素:
.L2:
vandps (%rax), %ymm1, %ymm1
vmovdqa %xmm1, %xmm0
addq $32, %rax
vmovd %xmm0, %edx
testl %edx, %edx
jne .L2
vpextrd $1, %xmm0, %edx
testl %edx, %edx
jne .L2
vpextrd $2, %xmm0, %edx
testl %edx, %edx
jne .L2
vpextrd $3, %xmm0, %edx
testl %edx, %edx
jne .L2
vextractf128 $0x1, %ymm1, %xmm0
vmovd %xmm0, %edx
testl %edx, %edx
jne .L2
vpextrd $1, %xmm0, %edx
testl %edx, %edx
jne .L2
vpextrd $2, %xmm0, %edx
testl %edx, %edx
jne .L2
vpextrd $3, %xmm0, %edx
testl %edx, %edx
jne .L2
vzeroupper
ret
有什么方法可以让 GCC 为其生成有效的测试,而无需恢复使用内在函数?
更新:作为参考,使用 (V)PTEST 内置的不可移植 GCC 的代码:
typedef uint32_t v8ui __attribute__ ((vector_size (32)));
typedef long long int v4si __attribute__ ((vector_size (32)));
const v8ui ones = { 1, 1, 1, 1, 1, 1, 1, 1 };
v8ui*
foo(v8ui *mem) {
v8ui v;
for ( v = ones;
!__builtin_ia32_ptestz256((v4si)v,
(v4si)ones);
mem++)
v &= *(mem);
return mem;
}
【问题讨论】:
-
没有办法让 gcc 使用几乎任何指令,如果你确实找到了办法,它可能不适用于其他优化级别或其他版本的 gcc。更糟糕的是,欺骗编译器发出特定指令实际上将您的程序归类为仅在单个编译器上工作(性能方面)。这真的比内在函数或 asm 更便携吗?
-
@SteveCox:同样,这些都是无副作用的测试。是否生成使它们短路的代码取决于编译器。它甚至可能重新排序!
-
显然是错误的。编译器没有重新排序这些测试的余地。
v[0]==0可能暗示v+1是一个无效的内存地址,因为我不知道 C 字符串。 open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 阅读 6.5.14(特别是声明 4) -
@SamuelEdwinWard:这里的
v不是数组或指针。见GCC Vector Extensions。
标签: c gcc vectorization sse avx2