在上面的图表中,黑色箭头显示数据流(文本或者二进制文件),红色箭头表示控制流。
(在该系列的后面文章里,当我们涉及到整个程序的优化,关于特定的/GL开关编译器和/LTCG开关的链接器时,还会再回到这个图表。 我们看到的是相同的框图,但是却以不同方式连接起来的。)
小结:
1. 前端需要理解C++(www.cppentry.com)源代码,其他环节,像后端和链接器,大部分都是独立于原始源语言的。他们工作在上面提到的元组上,形成一种更高层次的二进制汇编语言。原始的源程序可以是任何的命令式语言,像FORTRAN或者Pascal。后端真的不会在意。
2. 后端的优化部分会将元组转换成运行更快的更有效的形式,这种转换,我们称之为优化。(其实我们应该称之为’改进’,因为还有其他的改进,可以产生运行更快 的代码――我们只是尽力接近理想状态。 然而,几十年前,有人创造了一个术语’优化’,我们都深陷其中。) 还有很多这样的优化方法,像’常量合并’、’消除公共子表达式’、 ‘提升’、 ‘外提不变表达式’、‘冗余代码消除’、’ 内联函数’、 ‘自动向量化’等等.。大多数情况下。这些优化都是独立于程序所运行的最终处理器― 他们都是独立于机器的优化。
3. 后端的CodeGen部分决定如何制定运行时堆栈(用于实现’激活框架’);怎么样充分利用可用的机器寄存器;添加函数调用约定的细节;使用目标机器的详细介绍来转换代码,让它运行得更快。
(举一个小例子,如果你看汇编代码,例如,你在调试代码的时候,同时使用Visual Studio(Alt+8)的反汇编窗口―- 你可能会注意到一些用于将EAX置为0的指令像 xor eax, eax ,优于一些更直接的指令 move eax,0. 为什么呢 因为XOR 指令更小(只有2个字节),执行速度更快。我们也称它为“微优化”,也许你会怀疑是否值得这么麻烦 还记得那句谚语吗 积少才能成多。)
与优化相比,CodeGen就必须很清楚代码将要运行的处理器架构。有些情况下,在理解目标处理器的基础上,它甚至会改变机器指令的布局顺序― 称 之为‘调度’。我最好还是再解释一下: CodeGen知道它是针对x86,x64还是arm-32, 知道代码将要运行的处理器的具体的微架构还是很罕见的,以 Nehalem和Sandy Bridge为例(看看/favor:ATOM 这个案例,可以更多的详情)
这篇文章重点讲编译器的优化部分,很少提及构成前端, CodeGen或者链接器的其他组件。
这篇文章介绍了大量的术语,我没有打算让你全部理解它们:毕竟这只是一篇概述,传播一些思想,希望你会感兴趣,确保读完你下次还会再来,我会开始讲解所有的术语。