理论教育 编译器设计之路:冗余代码删除基础实现

编译器设计之路:冗余代码删除基础实现

时间:2023-11-04 理论教育 版权反馈
【摘要】:而设计者关注的是如何删除冗余代码。如果du链为空,则表示本次定值不能到达任何引用点,即可作为死代码删除。事实上,死代码删除并不一定是基于全路径讨论的。近年来,还有一些部分路径死代码删除算法是基于区域分析实现的。读者可能认为通过判断InSet集合是否为空来确定该基本块是否可到达似乎也是可行的。但是,在整个流图中,除了入口基本块以外,其他基本块的InSet都是不为空的。因此,仅依据InSet集合判定不可到达代码是不彻底的。

编译器设计之路:冗余代码删除基础实现

事实上,冗余代码是一个很宽泛的概念,它可以泛指程序中一切无用代码。这里,只讨论两种较常见的形式,即死代码和不可到达代码。在编译技术中,死代码(dead code)与不可到达代码(unreacheable code)是完全不同的概念。死代码就是指那些确实对计算结果不起作用的代码。而不可到达代码就是指那些无论输入数据是什么都不可能被执行的代码。这里,举两个C语言的实例,以便读者更直观地理解这两个概念。见表7-12。

表7-12 死代码、不可到达代码的实例

978-7-111-32164-4-Chapter07-73.jpg

从程序流程来说,(a)列中的“i=4”是可以被执行到的,不过,是否执行该语句对运行结果是没有任何影响的。而(b)列中的“i=2”是不可能被执行的,当然,讨论该语句是否会影响运行结果是没有意义的。

在许多编译器经典著作中,关于这两个概念有非常明确的阐述。可惜的是许多国内的编译原理书籍往往将这两个概念混为一谈,最常见的观点认为死代码就泛指一切冗余代码,而对不可到达代码的概念就完全淡化了,这样的理解是值得商榷的。实际上,读者并不需要关注这两个概念本身,它们只不过是两个名词而己。而设计者关注的是如何删除冗余代码。不过,由于各种冗余代码的删除算法往往是不同的,因此,针对不同的实际问题设计相应的算法,这才是笔者强调区分死代码与不可到达代码的意义所在。下面,就分别讨论死代码及不可到达代码删除的相关问题。

1.死代码删除

如果编译器有比较完善的数据流分析机制,死代码分析就将变得比较容易了。最简单的方法就是根据定值IR的du链信息判断其是否为死代码。如果du链为空,则表示本次定值不能到达任何引用点,即可作为死代码删除。(www.daowen.com)

值得注意的是,编译器必须保证被删死代码没有执行任何附带动作,例如,设置标志位、触发中断等。如果死代码的附带动作会影响到其他活跃代码,那么,即便两者之间不存在任何引用关系,该死代码也是不能被删除。

这里,只讨论基于全路径的死代码删除问题。事实上,死代码删除并不一定是基于全路径讨论的。在现代优化技术中,基于部分路径的死代码删除是一个比较热门的研究领域,即某一定值IR在部分路径上是死代码,而在其他的路径上可能不是死代码。在这种情况下,讨论死代码的分析与删除是比较复杂的,将涉及许多代码变换方面的工作。早在1994年,Knoop、Ruthing、Steffen就提出了部分路径死代码删除的思想。近年来,还有一些部分路径死代码删除算法是基于区域分析实现的。与全路径的死代码删除相比,部分路径的死代码删除的适应能力更强,当然,优化效果也更好。有兴趣的读者可以参阅相关论文及学术资料。

2.不可到达代码删除

分析不可到达代码的基础思想并不复杂,就是从流图的入口基本块开始,沿向下流的边遍历整个流图,所有能够被访问到的基本块即为可到达的,而其余的基本块则是不可到达的。至此,请读者仔细考虑一个问题:是否可以依据基本块的InSet集合来判定不可到达代码呢?那样,算法实现就会更简单。读者可能认为通过判断InSet集合是否为空来确定该基本块是否可到达似乎也是可行的。实际上,也不能认为这种观点是错误的,只是不全面而己。因为有些不可到达代码是无法通过InSet集合判定的。例如,如图7-9所示,if真分支内的语句明显是不可到达代码。但是,在整个流图中,除了入口基本块以外,其他基本块的InSet都是不为空的。因此,仅依据InSet集合判定不可到达代码是不彻底的。

978-7-111-32164-4-Chapter07-74.jpg

图7-9 不可到达代码

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

我要反馈