SSE 优化(行重新排序、操作整理)中的编译器(例如 g++)有多聪明

Posted

技术标签:

【中文标题】SSE 优化(行重新排序、操作整理)中的编译器(例如 g++)有多聪明【英文标题】:How clever is a compiler (e.g. g++) at SSE optimisation (line re-ordering, operation collation) 【发布时间】:2017-07-22 15:32:15 【问题描述】:

在不讨论过早优化的情况下,我有几个关于 g++ 或其他编译器在选择相关编译器标志时如何处理 SSE 优化的问题:

    为了在多行代码上执行 SSE 指令,是否需要重新排序多行代码?例如

    a[0] = a1+a2+a3;
    x[0] = a1*a1;
    a[1] = b1+b2+b3;
    x[1] = b1*b1;
    a[2] = c1+c2+c3;
    x[2] = c1*c1;
    

    编译器在哪里可以将这些行重新排序为两组 SSE 指令?

    编译器是否意识到何时采用类似的操作集(不在数组中)并将它们组合成 SSE 指令?例如

    a = a1+a2+a3;
    b = b1+b2+b3;
    c = c1+c2+c3;
    

    编译器是否优化了 for 循环中的指令以进行 SSE 优化?例如

    for(unsigned int i = 0; i < 4; i++)
    
        x[i] = x[i]*k;
        a[i] = a[i]*c;
    
    

编译器在尝试优化时会结合 1、2 和 3 吗?

听听人们对各种 SSE 优化编译器的想法会很有趣。

edit:我主要是在询问 g++,但其他“主流”编译器也很有趣。我也主要谈论浮点运算。

【问题讨论】:

您只是在谈论 float/double 上的严格垂直操作吗?因为整数、不动点等,以及需要扩大/缩小或排列的操作是另一回事...... 这是一个有趣的问题,但目前范围太广。 “编译器”实际上是无限的。如果你能把它缩小到一个特定的编译器,那么它会变得更有责任感。你已经标记了它 [g++];这是否意味着您只想专注于 GCC? 【参考方案1】:

根据我的经验,编译器在三年前对矢量化进行了真正的改进。目前,您的所有示例都将被有效地矢量化。此外,如果您有机会使用英特尔的编译器,您将获得巨大的加速,其报告模式将为您提供有关其应用的优化的更多信息。

在我的日常生活中,我已经看到你可以拥有最疯狂的代码,但对于计算部分,你应该帮助编译器并使用 C 方法来提取指针并执行循环:

float * pa = whatever;      // data must be contigious
float * pb = whatever;

for (int i=0; i <n; ++i)

     pa[I] = pa[i]*pb[i];   // example

现在我们还有OpenMP 4.5, which provides directives for vectorization。这只会比手写解决方案慢 10%。因此,我今天不建议使用内部函数,除非在非常特殊的情况下 #pragma 不起作用。

【讨论】:

你为什么提到英特尔的编译器会给你一个加速?您是否暗示它会比 g++ 加快速度?如果是,为什么? 编译器是一门非常难的科学。您将获得比 GCC 多 40% 的收益。原因如下:1)特殊数学函数不会破坏向量化(经验,cos,...),因为英特尔提供了实现,GCC 没有。 2) 英特尔编译器管理良好的 GCC 分支较少。 3)英特尔专用于英特尔平台。 GCC 是多平台,有好有坏。 4) 间接比 GCC (a[b[I]]) 管理得多,并且轮廓循环矢量化可以工作,但对于 GCC 来说,越来越少。

以上是关于SSE 优化(行重新排序、操作整理)中的编译器(例如 g++)有多聪明的主要内容,如果未能解决你的问题,请参考以下文章

SSE图像算法优化系列十八:三次卷积插值的进一步SSE优化。

使用 Intel 内在函数的位反向重新排序优化

如何设置 C/C++ 编译器选项以对使用中的 CPU 进行最佳优化? [关闭]

SSE 内在函数优化

DB2性能优化- REORG慢的分析

Visual C++ (x64) 中的 SSE2 选项