理论教育 编译器设计:目标代码生成

编译器设计:目标代码生成

时间:2023-11-04 理论教育 版权反馈
【摘要】:目标代码生成,亦称为代码生成,是经典编译模型中最后一个阶段。不过,即使如此,代码生成器的设计仍然很大程度上依赖于目标机的体系结构。编译器对代码生成器的要求是比较严格的。这是代码生成器的设计底线,准确且等价的转换才是有意义的。鉴于以上几点,试图设计一个相对完备的代码生成器并不是一项简单的工程。

编译器设计:目标代码生成

目标代码生成,亦称为代码生成,是经典编译模型中最后一个阶段。其输入是经过语法、语义分析及优化后得到的IR,而其输出则是特定的目标语言程序。随着汇编语言的成熟,现代高级语言编译器已经很少直接将源程序转换为机器代码了,通常会选择汇编语言作为编译器的目标语言。不过,即使如此,代码生成器的设计仍然很大程度上依赖于目标机的体系结构。因此,设计者不必过多顾虑该模块与目标机的耦合程度,这是不可避免的。

编译器对代码生成器的要求是比较严格的。通常,必须遵守如下几个原则:

(1)语义等价。这是代码生成器的设计底线,准确且等价的转换才是有意义的。语义等价是编译器设计的基本原则,笔者已经多次声明,其重要性不言而喻。

(2)相对高效。理论上的最优代码是不可判定的。当然,很大程度上也是不可达到的。不过,这并不意味着设计者可以任意放纵资源耗费。即使是硬件资源不再稀缺的今天,目标程序的性能仍然是评价编译器设计的一个重要指标。为了得到相对较优的代码,编译器还引入了一些基于目标代码实现的优化算法,通常称为指令级优化。关于指令级优化的话题,笔者将在本章中稍作介绍。除了指令级优化之外,存储层的优化也是提高目标程序效率的有效途径。众所周知,寄存器、cache的访问速度远胜于内存,因此,如何合理分配寄存器以及如何提高cache的命中率是编译器设计需要关注的。当然,就算法实现而言,这可能是比较复杂的。

(3)扩展性好。在通用机编译器中,读者可能不太容易体会其优越性。因为要真正做到通用机层次上的跨目标机应用,除了编译器的因素之外,还必须考虑操作系统的差异。程序员更愿意接受像Java、.NET之类的跨平台应用,这可能更有现实意义。不过,在一些嵌入式系统的编译器中,可变目标的编译器可以使程序员省去很多烦心事。最著名的可变目标编译器就是GCC,它的经典与完美已在前文阐述。当然,扩展性也是一柄双刃剑,实践证明,即使是经典的可变目标的编译器也很难与专用编译器媲美。例如,在i386结构上,无论是目标程序的性能还是编译器本身的效率,GCC都无法与Intel C++相比。

鉴于以上几点,试图设计一个相对完备的代码生成器并不是一项简单的工程。通常,现代编译技术的观点认为,代码生成器主要完成如下三项任务:(www.daowen.com)

(1)指令选择:也称为指令筛选,即选择一个实现IR操作的目标机指令序列。

(2)寄存器分配:考虑如何有效地利用有限的寄存器资源,以提高代码的执行效率。

(3)指令调度:也称为指令排序,就是确定指令的执行顺序。

以上三个话题所涉及的理论与技术是非常丰富的,并不亚于编译优化技术,因此,本书无法详细阐述相关细节。鉴于Neo Pascal的实现及本书篇幅,本章只涉及指令选择、寄存器分配的一些基本问题,不讨论指令调度的相关技术与实现。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈