编译原理实战课
宫文学
北京原点代码 CEO
26065 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 55 讲
真实编译器解析篇 (19讲)
编译原理实战课
15
15
1.0x
00:00/00:00
登录|注册

07 | 代码优化:跟编译器做朋友,让你的代码飞起来

反分支
拉直
循环反转
循环简化
If简化
死代码删除
不可达代码消除
叶子程序优化
内联扩展
内联
尾调用优化
代码提升
循环不变代码外提
重组
循环向量化
循环展开
边界检查消除
归纳变量优化
循环向量化
超字级并行
部分冗余消除
公共子表达式消除
值编号
拷贝传播
强度折减
代数简化
稀疏有条件的常数传播
常数传播
常数折叠
一课一思
优化的顺序
优化方法的重要性
别名分析
依赖分析
数据流分析
控制流分析
对控制流做优化
减少过程调用的开销
针对循环的优化
聚合体的标量替换
向量计算
消除重复的计算
用低代价的方法做计算
机器无关的优化与机器相关的优化
参考资料
课程小结
优化方法的重要性和顺序
代码优化所依赖的分析方法
常见的代码优化方法
优化的实现思路
对编译器的优化工作不清楚
占据了很大的比例
前端技术栈丰富和强大的根本原因
编译器的优化工作
编译技术的初学者
编译器的优化工作
一门语言的性能高低
代码优化:跟编译器做朋友,让你的代码飞起来
参考文章

该思维导图由 AI 生成,仅供参考

你好,我是宫文学。
一门语言的性能高低,是它能否成功的关键。拿 JavaScript 来说,十多年来,它的性能多次得到成倍的提升,这也是前端技术栈如此丰富和强大的根本原因。
因此,编译器会无所不用其极地做优化,而优化工作在编译器的运行时间中,也占据了很大的比例。
不过,对编译技术的初学者来说,通常会搞不清楚编译器到底做了哪些优化,这些优化的实现思路又是怎样的。
所以今天这一讲,我就重点给你普及下编译器所做的优化工作,及其工作原理。在这个过程中,你还会弄明白很多似曾相识的术语,比如在前端必须了解的 AST、终结符、非终结符等,在中后端必须熟悉的常数折叠、值编号、公共子表达式消除等。只有这样,你才算是入门了。
首先,我带你认识一些常见的代码优化方法。

常见的代码优化方法

对代码做优化的方法有很多。如果要把它们分一下类的话,可以按照下面两个维度:
第一个分类维度,是机器无关的优化与机器相关的优化。机器无关的优化与硬件特征无关,比如把常数值在编译期计算出来(常数折叠)。而机器相关的优化则需要利用某硬件特有的特征,比如 SIMD 指令可以在一条指令里完成多个数据的计算。
第二个分类维度,是优化的范围。本地优化是针对一个基本块中的代码,全局优化是针对整个函数(或过程),过程间优化则能够跨越多个函数(或过程)做优化。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

编译器优化是提高代码性能的关键,本文介绍了常见的代码优化方法及其实现思路。从常数折叠和常数传播到循环优化和控制流优化,文章详细介绍了各种优化方法的原理和实现方式。针对循环的优化是编译器中的重点,因为循环是程序中最多的计算量消耗的地方。对循环做优化可以事半功倍,例如归纳变量优化、边界检查消除、循环展开、循环向量化等方法都能有效提高性能。此外,减少过程调用的开销也是重要的优化方向,包括尾调用优化、内联、内联扩展、叶子程序优化等方法。文章还介绍了代码优化所依赖的分析方法,包括控制流分析、数据流分析、依赖分析和别名分析等。最后,文章提到了优化方法的重要性和顺序,指出了不同优化方法的适用范围和优化的顺序。整体而言,本文详细介绍了编译器优化的各种方法和分析技术,对于想要深入了解编译器优化和提高代码性能的读者具有重要意义。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《编译原理实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(3)

  • 最新
  • 精选
  • qinsi
    有两个例子怀疑有误: “x*9”等价于“x<<3+1” ----------------- 怀疑是"(x<<3)+x" int j = 0; for (int i = 0; i < 100; i++) { j = 2*i; //2*i可以替换成j+2 } return j; ------------------------- 怀疑是"for (int i = 1; i <= 100; i++) {"

    作者回复: 没错,你看得很细!感谢你! 我在文稿里改一下!

    2020-06-16
    2
  • chris
    一直有两个关于各种优化算法与ssa的关系的困惑,不知老师能否解答: 1.现代编译器的优化流程,一般ssa从哪个阶段开始使用,到哪个阶段不再使用 2.在ssa的情况下,各种优化算法本身要发生什么变化,或者可能都变得不必要了

    作者回复: 非常好的两个问题。 对问题1:ssa一般用在做机器无关的优化,也就是用于HIR和MIR。到了LIR,特别是做了寄存器分配算法以后,ssa中的值(或变量)的概念已经消失了,已经变成了对一个个物理寄存器的操作,一个物理寄存器在不同的时间对应的是不同的值,所以这个时候也就谈不到SSA了。 对问题2:优化算法会变得简单,而不是变得不必要。 比如,用非SSA的IR,要记录变量的use-def关系也是可以的,但要耗费更多的存储空间,记录更多的信息,才能达到跟SSA等价的程度。

    2020-06-16
    2
  • humor
    值编号和公共子表达式都可以减少重复计算,值编号侧重于变量的值的重复,公共子表达式侧重于表达式的重复;如果有两个包含a,b两个变量的表达式,a,b两个变量的值相同,并且除了这两个变量之外的其他部分都相同的话,则可以用值编号来优化,不能用公共子表达式来优化。 感觉可以看明白这些优化都做了什么,但是到实际使用的时候可能只能想起来一点点……

    作者回复: 总结得不错! 总的来说,编译器后端技术工程性比较强,所以不适合在学校里考试。所以,学校的的编译原理往往侧重前端部分。如果学后端部分,可以每种优化做一个课程实验的方式,由老师通过测试用例检验实际优化的效果来决定分数。国内大学可能不怎么以这种方式授课。 如果编译原理课程后面开训练营,可以这么搞。

    2020-06-15
收起评论
显示
设置
留言
3
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部