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优化。