c - 我如何理解 -O3 的优化?
问题描述
我目前有两个功能A和B。
在没有任何标志的情况下编译时,A比B快。
-O1
但是当使用or编译时-O3
,B比A快得多。
我想将该功能移植到其他语言,所以看起来A是一个更好的选择。
-O3
但如果我能理解如何设法加速功能B那就太好了。有什么好的方法至少可以稍微了解一下 由 所做的优化-O3
吗?
解决方案
-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 和比较函数A和B的输出汇编程序。-S
-masm=intel
此答案基于GCC 文档,您可以从中了解更多信息。
推荐阅读
- javascript - 使用基于另一个数组的对象动态过滤数组
- javascript - 国家和地区选择器不使用 useState 渲染,有没有人有解决方案
- swift - 如果文本字段为空,则隐藏按钮 方程式不起作用
- android - 我正在制作一个应用程序,当我输入字符串值(例如“kin”)时,在电子邮件字段中它给了我这样的错误:E/SQLiteLog: (1) no such column: kin
- python - 循环以重新估计执行一步预测
- node.js - 无法从 PowerShell 运行“npm run serve”
- c++ - 将位打印为 IEEE-754 浮点数
- p5.js - 我将如何对两个单独的数组进行排序/对齐?
- css - 如何在不设置顶部和底部的情况下设置左右 CSS 属性
- android - 带有 android 和 Kotlin 的 ViewModel:无法可视化价值