我如何理解-O3的优化?

时间:2019-08-17 13:25:46

标签: c gcc optimization

我目前有两个功能 A B

编译时没有任何标志, A B 快。

但是使用-O1-O3进行编译时, B A 快得多。

我想将该功能移植到其他语言,所以似乎 A 是更好的选择。

但是,如果我能理解-O3如何设法加快功能 B ,那就太好了。是否有任何好的方法至少可以使您对-O3所做的优化类型有一点点了解?

2 个答案:

答案 0 :(得分:3)

-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

AT&T

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

AT&T

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

您可以使用-S标志和-masm=intel比较功能 A B 的输出汇编器。

此答案基于GCC documentation,您可以从中学到更多。

答案 1 :(得分:0)

问题所在

  

是否有至少至少对-O3完成的优化类型有轻微了解的好方法?

,并且显然是要在不考虑实际代码的情况下以一般意义回答问题,我认为最好的答案是建议阅读documentation for your compiler,尤其是{{3} }。

尽管并非所有GCC执行的优化都具有相应的选项标志,但大多数这样做。 docs根据这些标志指定在每个级别执行哪些优化,并且它们还指定每个标志的含义。这些解释中使用的某些术语可能并不熟悉,但是您应该至少能够“稍有理解”。一定要从优化文档的顶部开始阅读。

相关问题