当使用C的GCC向量扩展时,如何检查向量上的所有值是否为零?
例如:
#include 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
条件的测试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 4.9.2 -O3 -mavx2
(在64位模式下)没有意识到它可以使用ptest
,使用||
或者 。
|
version使用vmovd
和vpextrd
提取向量元素,并将内容与7位or
32位寄存器之间的insn组合在一起。 所以它非常糟糕,并没有利用任何仍然会产生相同逻辑真值的简化。
||
版本同样糟糕,并且每次都提取相同的元素,但每个元素都会test
/ jne
。
所以在这一点上,你不能指望GCC识别这样的测试并做任何远程高效的事情。 ( pcmpeq
/ movmsk
/ test
是另一个不错的序列,但gcc也不生成它。)
vptest不会有帮助吗? 如果您正在考虑性能,有时您会对本机类型提供的内容感到惊讶。 下面是一些使用vanilla memcmp()以及vptest指令的代码(通过相应的内部函数使用)。 我没有计时function。
#include #include #include #include typedef uint32_t v8ui __attribute__ ((vector_size (32))); v8ui* foo1(v8ui *mem) { v8ui v = (v8ui){ 1, 1, 1, 1, 1, 1, 1, 1 }; if (memcmp(mem, &v, sizeof (v8ui)) == 0) { printf("Onesn"); } else { printf("NOT Onesn"); } return mem; } v8ui* foo2(v8ui *mem) { v8ui v = (v8ui){ 1, 1, 1, 1, 1, 1, 1, 1 }; __m256i a, b; a = _mm256_loadu_si256((__m256i *)(&v)); b = _mm256_loadu_si256((__m256i *)(&mem)); if (!_mm256_testz_si256(a, b)) { printf("NOT Onesn"); } else { printf("Onesn"); } return mem; } int main() { v8ui v = (v8ui){ 1, 1, 1, 1, 1, 1, 1, 1 }; foo1(&v); foo2(&v); }
编译标志:
gcc -mavx2 foo.c
卫生署! 直到现在我才发现你想让GCC在不使用内在函数的情况下生成vptest指令。 无论如何我都会留下代码。
如果编译器不够自动以自动生成优化,则有三个选项:
您已经通过使用gcc扩展自动排除了第一个选项,尽管llvm / clang可能会为您扩展这些扩展。
你已经公然排除了第二种选择。
第三种选择似乎是我最好的选择。 gcc是开源的,因此您可以对其进行(并提交)自己的更改。 如果你可以修改gcc来自动生成这个优化(理想情况下来自100%标准C),那么你不仅可以实现产生这种优化的目标,而不会将crud引入你的程序,但你也可以节省无数的手动优化(特别是将来锁定您使用特定编译器的非标准版本。
以上就是c/c++开发分享使用向量扩展时让GCC生成PTEST指令相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/562096.html