为什么需要中间表示
复习
- 语义分析总装:产出带类型标注的语法树
- 抽象:加一层,把复杂细节藏起来
- 编译器:前端、中端、后端的划分
TL;DR
- 中间表示(IR)是介于源码与机器码之间的形式
- 它让“m 种源语言 × n 种机器”不必两两适配
- IR 与具体机器无关,便于统一做优化
- 它是前端与后端之间的桥梁
正文
语义分析之后,编译器有了一棵带类型的语法树。接下来是不是直接生成机器指令就好了?
先别急。想一想这个现实问题:世界上有很多种编程语言,也有很多种机器架构。 如果每种语言都要为每种机器单独写一个编译器,那就是 m × n 个工作,多得吓人。
用一层“通用语”解耦
解决思路还是那个熟悉的招数:加一层。
如果所有语言先翻译成一种通用中间形式,所有机器再各自从这个通用形式生成机器码,那么工作量就变成了:
- m 种语言,各写一个“翻译成 IR”的前端
- n 种机器,各写一个“从 IR 生成代码”的后端
总共 m + n,而不是 m × n。多了一层,就省掉了大量重复劳动。
这层通用形式,就叫中间表示(IR,Intermediate Representation)。它像一位“世界语”翻译:各语言都先译成它,再由它译成各机器的话。
为什么优化也放在这里
IR 还有一个更重要的作用:它非常适合做优化。
因为在 IR 这一层:
- 它与具体机器无关,优化一次,对所有目标机器都适用
- 它比源码更规整、更简单,分析起来容易
- 它又比机器码保留了更多结构信息,不至于无从下手
于是,编译器通常把各种优化都放在 IR 上做。前端负责“读懂并转成 IR”,中端在 IR 上优化,后端负责“把 IR 落成机器码”。 这条分工,正是我们在这一部分开头说的前端、中端、后端。
那么,这棵带类型的语法树,具体是怎样变成 IR 的?下一章来看“降低”。
思考题 1
中间表示怎样避免“每种源语言都要为每种机器写一个编译器”?
思考题 2
为什么优化通常放在中间表示上做,而不是在源码或机器码上?
小结
知识点
- IR 是介于源码与机器码之间的通用形式
- 它把 m × n 的适配降为 m + n
- IR 独立于机器,便于统一优化
- 前端转 IR、中端优化、后端生成代码
参考资料
- Wikipedia(zh):中间表示:编译器内部使用的通用程序表示
- Wikipedia(zh):编译器:前端、中端与后端的划分
思考题答案(仅供参考)
思考题 1
因为引入 IR 后,每种源语言只需写一个前端把它翻译成 IR,每种机器只需写一个后端从 IR 生成代码。这样工作量从 m × n 降为 m + n,避免了每种语言都要为每种机器单独适配。
思考题 2
因为 IR 与具体机器无关,优化一次可适用于所有目标机器;它比源码规整、比机器码保留了更多结构,既便于分析又便于转换。因此把优化集中放在 IR 层最划算。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪