首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >simd的pragma omp不生成GCC中的矢量指令

simd的pragma omp不生成GCC中的矢量指令
EN

Stack Overflow用户
提问于 2020-04-11 08:34:34
回答 1查看 1.7K关注 0票数 0

Shortpragma omp for simd OpenMP指令是否生成使用SIMD寄存器的代码?

:如OpenMP文档中所述,“工作共享循环SIMD结构指定一个或多个相关循环的迭代将分布在已经存在的线程之间,使用SIMD指令”。从这个语句中,我期望下面的代码(simd.c)在编译运行的XMMYMMZMM寄存器时使用gcc simd.c -o simd -fopenmp,但它没有使用。

代码语言:javascript
运行
复制
#include <stdio.h>
#define N 100

int main() {
    int x[N];
    int y[N];
    int z[N];
    int i;
    int sum;

    for(i=0; i < N; i++) {
        x[i] = i;
        y[i] = i;
    }

    #pragma omp parallel
    {
        #pragma omp for simd
        for(i=0; i < N; i++) {
            z[i] = x[i] + y[i];
        }
        #pragma omp for simd reduction(+:sum)
        for(i=0; i < N; i++) {
            sum += x[i];
        }
    }
    printf("%d %d\n",z[N/2], sum);

    return 0;
}

在检查运行gcc simd.c -S -fopenmp的汇编程序时,不使用SIMD寄存器。

我可以在没有OpenMP的情况下使用SIMD寄存器,使用选项-O3,因为根据GCC文献,它包括-ftree-vectorize标志。

  • XMM寄存器:gcc simd.c -o simd -O3
  • YMM寄存器:gcc simd.c -o simd -O3 -march=skylake-avx512
  • ZMM寄存器:gcc simd.c -o simd -O3 -march=skylake-avx512 -mprefer-vector-width=512

但是,使用标志-march=skylake-avx512 -mprefer-vector-width=512-fopenmp相结合不会生成SIMD指令。

因此,我可以在没有-O3的情况下轻松地用pragma omp for simd将代码向量化,而不是相反。

此时,我的目的不是生成SIMD指令,而是了解OpenMP SIMD指令在GCC中是如何工作的,以及如何仅用OpenMP (没有-O3)来生成SIMD指令。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-11 15:45:12

至少启用-O2以使-fopenmp工作,一般性能也是如此

gcc simd.c -S -fopenmp

GCC的默认设置是为一致调试而优化的-O0****。它永远不会使用-O0自动矢量化,因为当C源的每个i值都必须存在于内存中时,这是毫无意义的,等等。为什么clang使用-O0 (对于这个简单的浮点和)产生低效的asm?

同样不可能的是,您必须一次只能执行一次源行,甚至可以使用调试器在运行时修改i或内存内容,并让程序像预期的C抽象机器那样继续运行。

在没有的情况下,任何优化都是性能的垃圾;甚至考虑到性能是否足以使用OpenMP. (当然,实际调试除外),这都是疯狂的。通常,从反优化到优化标量的加速比矢量化标量代码所能得到的要多,但两者都可能是很大的因素,所以您肯定希望优化超出自动向量化。

我可以在不使用OpenMP的情况下使用SIMD寄存器,使用选项-O3,因为根据GCC的文档,它包括-ftree-vectorize标志。

好吧,那就这么做吧。-O3 -march=native -flto通常是在编译主机上运行的代码的最佳选择。而且,-fno-trapping-math -fno-math-errno对于所有的东西都应该是安全的,并且启用一些更好的FP函数内联,即使您不想要-ffast-math。另外,最好是-fprofile-generate / -fprofile-use配置文件引导优化(PGO),展开热循环,适当地选择分支和无分支,等等。

#pragma omp parallel-O3 -fopenmp上仍然有效- GCC在默认情况下不允许自动等位基因化.

此外,#pragma omp simd有时会使用不同的矢量化风格。在您的例子中,它似乎让GCC忘记了它知道数组是16字节对齐的,并且使用movdqu加载(当AVX不能用于paddd xmm0, [rax]的未对齐内存源操作数时)。比较https://godbolt.org/z/8q8Dqm -- main调用的main._omp_fn.0:助手函数不假定对齐。(如果GCC不费心去做向量大小的块,那么在按线程数除以数组的范围后,它可能就不能这样做了?)

使用-O2 -fopenmp获取您所期望的

如果没有在指针args上使用OpenMP函数,让gcc更容易或更有效地将循环矢量化,让它知道数组不重叠,或者让浮点让它假装FP数学是关联的,即使您不使用-ffast-math

或者,如果您启用了一些优化,但不是完全优化#pragma omp (例如,不包括-ftree-vectorize-O2 ),那么将按您预期的方式工作。

请注意,x[i] = y[i] = i; init循环在-O2没有自动向量化,但是#pragma循环是。没有-fopenmp,纯标量。戈德波特编译器浏览器

对于这个小的-O3,串行N代码将运行得更快,因为线程启动开销根本不值得。但是对于大N来说,如果单个核不能饱和内存带宽(例如,在Xeon上,但是大多数双/四核桌面CPU几乎可以用一个核来满足最小带宽),并行化可能会有所帮助。或者,如果您的数组在不同核心的缓存中处于热状态。

不幸的是(?)即使GCC -O3也无法在整个代码中进行常量传播,只需打印结果。或者将z[i] = x[i]+y[i]循环与sum(x[])循环融合。

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

https://stackoverflow.com/questions/61154047

复制
相关文章

相似问题

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