c/c++语言开发共享使用向量扩展时让GCC生成PTEST指令

当使用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使用vmovdvpextrd提取向量元素,并将内容与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

      (0)
      上一篇 2021年2月4日
      下一篇 2021年2月4日

      精彩推荐