首页 > 解决方案 > 我如何理解 -O3 的优化?

问题描述

我目前有两个功能AB

在没有任何标志的情况下编译时,AB快。

-O1但是当使用or编译时-O3BA快得多。

我想将该功能移植到其他语言,所以看起来A是一个更好的选择。

-O3但如果我能理解如何设法加速功能B那就太好了。有什么好的方法至少可以稍微了解一下 由 所做的优化-O3吗?

标签: cgccoptimization

解决方案


-O3和 , 一样-O2,还有:

  • 函数的内联部分。
  • 执行函数克隆以使过程间常量传播更强。
  • 在石墨外进行循环交换。这可以提高循环嵌套的缓存性能,并允许进行进一步的循环优化,例如矢量化。例如,循环:
for (int i = 0; i < N; i++)
  for (int j = 0; j < N; j++)
    for (int k = 0; k < N; k++)
      c[i][j] = c[i][j] + a[i][k]*b[k][j];

被转化为

for (int i = 0; i < N; i++)
  for (int k = 0; k < N; k++)
    for (int j = 0; j < N; j++)
      c[i][j] = c[i][j] + a[i][k]*b[k][j];
  • 在可行的循环上应用展开和堵塞转换。在循环嵌套中,这会按某个因素展开外循环并融合生成的多个内循环。
  • 剥离有足够信息的循环,它们不会滚动太多。它还开启了完全循环剥离(即用少量恒定迭代次数完全去除循环)。
  • 执行预测共用优化,即重用在先前循环迭代中执行的计算(尤其是内存加载和存储)。
  • 导致循环后沿的分割路径。这可以改进死代码消除和公共子表达式消除。
  • 提高大循环体的缓存性能,并允许进行进一步的循环优化,例如并行化或矢量化。
  • 将具有循环不变条件的分支移出循环,两个分支上都有循环的重复项(根据条件结果进行修改)。
  • 如果循环遍历具有可变步幅的数组,则创建另一个版本的循环,假定步幅始终为 1。例如:
for (int i = 0; i < n; ++i)
  x[i * stride] = …;

变成:

if (stride == 1)
  for (int i = 0; i < n; ++i)
    x[i] = …;
else
  for (int i = 0; i < n; ++i)
    x[i * stride] = …;

例如,下面的代码:

unsigned long apply(unsigned long (*f)(unsigned long, unsigned long), unsigned long a, unsigned long b, unsigned long c) {
    for (unsigned long i = 0; i < b; i++)
        c = f(c, a);
    return c;
}

unsigned long inc(unsigned long a, unsigned long b) { return a + 1; }
unsigned long add(unsigned long a, unsigned long b) { return apply(inc, 0, b, a); }

优化添加功能:

英特尔语法

add:
  lea rax, [rsi+rdi]
  ret

美国电话电报公司

add:
  leaq (%rsi,%rdi), %rax
  ret

没有-O3输出是:

英特尔语法

add:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov QWORD PTR [rbp-8], rdi
  mov QWORD PTR [rbp-16], rsi
  mov rdx, QWORD PTR [rbp-8]
  mov rax, QWORD PTR [rbp-16]
  mov rcx, rdx
  mov rdx, rax
  mov esi, 0
  mov edi, OFFSET FLAT:inc
  call apply
  leave
  ret

美国电话电报公司

add:
  pushq %rbp
  movq %rsp, %rbp
  subq $16, %rsp
  movq %rdi, -8(%rbp)
  movq %rsi, -16(%rbp)
  movq -8(%rbp), %rdx
  movq -16(%rbp), %rax
  movq %rdx, %rcx
  movq %rax, %rdx
  movl $0, %esi
  movl $inc, %edi
  call apply
  leave
  ret

您可以使用flag 和比较函数AB的输出汇编程序。-S-masm=intel

此答案基于GCC 文档,您可以从中了解更多信息。


推荐阅读