首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >让GCC在使用向量扩展时生成PTEST指令

让GCC在使用向量扩展时生成PTEST指令
EN

Stack Overflow用户
提问于 2015-04-06 13:45:22
回答 3查看 489关注 0票数 6

当对C使用GCC向量扩展时,如何检查向量上的所有值都是零?

例如:

代码语言:javascript
复制
#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生成的代码只是解压向量并逐一检查单个元素:

代码语言:javascript
复制
.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产生一个有效的测试,而不恢复到使用本质?

更新:供参考,代码使用不可移植的GCC内置的(V)PTEST

代码语言:javascript
复制
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;
}
EN

回答 3

Stack Overflow用户

发布于 2015-07-03 20:56:43

gcc 4.9.2 -O3 -mavx2 (在64位模式下)没有意识到它可以用ptest实现这一点,不管是||还是|

|版本用vmovdvpextrd提取向量元素,并在32位寄存器之间结合7 or insns。因此,这是相当糟糕的,并且没有利用任何仍然会产生相同逻辑真值的简化。

||版本也同样糟糕,每次都做同样的提取和元素提取,但对每个版本都做一个test / jne

因此,在这一点上,你不能指望GCC能够识别这样的测试,并且做任何有效率的事情。(pcmpeq / movmsk / test是另一个不会坏的序列,但gcc也不会这么做。)

票数 2
EN

Stack Overflow用户

发布于 2015-04-12 08:28:23

vptest不帮忙吗?如果您正在查看性能,有时您会对本机类型所能提供的功能感到惊讶。下面是一些使用vanilla ()的代码以及vptest指令(通过相应的内部代码使用)。我没有安排时间。

代码语言:javascript
复制
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <immintrin.h>

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("Ones\n");
    } else {
            printf("NOT Ones\n");
    }

    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 Ones\n");
    } else {
            printf("Ones\n");
    }

    return mem;
}

int
main()
{
    v8ui v = (v8ui){ 1, 1, 1, 1, 1, 1, 1, 1 };
    foo1(&v);
    foo2(&v);
}

编译标志:

gcc -mavx2足球

哈!直到现在,我才看到你想让GCC在不使用本质的情况下生成vptest指令。反正我也会把密码留下的。

票数 1
EN

Stack Overflow用户

发布于 2015-04-14 23:51:41

如果编译器不够优化,无法自动生成优化,则有三个选项:

  • 找个新的编译器。
  • 手动进行优化(例如。使用本质,如在你的测试和其他答案)。
  • 修改编译器以自动生成优化。

您已经通过使用gcc扩展自动排除了第一个选项,尽管llvm/clang可能会为您扩展这些扩展。

你明目张胆地排除了第二个选择。

对我来说,第三种选择似乎是你最好的选择。gcc是开源的,所以您可以对其进行(并提交)您自己的更改。如果您可以修改gcc以自动生成此优化(理想情况下从100%标准C),那么您不仅可以在不将crud引入您的程序的情况下实现此优化的目标,而且还将在将来节省无数手动优化(特别是那些将您锁定使用特定编译器的非标准优化)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29472524

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档