ud链、du链是数据流分析中两个非常重要的概念。不过,这两个名词却经常被初学者混淆。下面从程序设计语言的角度来诠释这两个概念。
ud链、du链仅仅是两个概念的代名词而己,它们揭示了两类不同的信息。读者需要关注的是其背后的概念,而非名词本身。从IR定值角度而言,数据流分析需要关心的可能是这次定值会影响哪些IR的引用。而从IR引用角度而言,数据流分析需要关心的可能是这次引用值的可能定值点的位置。在经典编译技术中,将前者称为du链(即定值一引用链),而将后者称为ud链(即引用一定值链)。
实际上,du链是活跃变量分析结果的一种扩展。活跃变量仅关心变量的一次定值后是否存在可能被引用的情况,却不关心具体引用点的位置或存在多少引用点。而du链却需要获得关于各个引用点的详细位置,而不仅仅是有或无的回答。通常,du链是针对某条IR而言的,如果该IR是定值语句,那么,其du链描述的就是本次定值可能到达的所有引用点。同理,ud链描述的就是一次引用的可能到达的定值点。
与很多数据流问题类似,ud链、du链分析的基本原则也是既保守又激进的。以定值问题为例,在很多情况下,一个定值是否能实际到达某一特定程序点是不可判定的。当然,有时还依赖于特定的外部输入。因此,在通常情况下,编译器可以分析得到哪些定值是可能到达的,却很难断言哪些定值是必然到达的。即使如此,在某些特殊情形下,定值、引用问题仍然是很难断言的。不过,当出现这类情形时,编译器可能将无法保证程序的正确性,虽然这并不是编译器设计者的初衷。
关于ud链、du链的话题,暂且讨论至此。稍后笔者还将详细阐述Neo Pascal的ud链、du链分析,届时,将介绍ud链、du链分析算法的基本思想及其实现细节。(www.daowen.com)
最后,来看一个奇怪的C语言程序,如图7-5所示。如果读者使用VC++编译这个例程,可以发现一个奇怪的问题,那就是debug和release版程序的运行结果是不同的。其中,debug版程序的运行结果是3,而release版程序的运行结果是6。究其原因就是数据流分析算法是否将后两句“*p++=l”视为对b、c的定值。debug版程序是几乎不做任何优化的,而release版程序是经过编译优化的。因此,debug版程序即使无法预知对b、c的定值,但按照程序的实际语义翻译后,仍可以得到正确的结果。而经过优化的程序则不然,由于数据流分析无法从“*p++=1”语句中分析获得任何关于b、c的定值线索,故认为test函数的返回值就是1+2+3。如果在此基础上再进行了过程间优化,则编译器就将整个test函数优化为一个常量6。读者可以从编译器生成的汇编文件中证实这个事实。由于C语言标准中只说明了函数参数的存储布局以及参数取址操作的有效性,却没有明确指出这种指针引用方式的安全性,故不能以此界定优化算法是不正确的。当然,也很难就此认定是程序逻辑的错误,作为程序员来说,能做的就是尽可能避免而己。事实上,这个现象不仅限于参数,同样适用于讨论局部变量。不过,由于不同版本程序的局部变量的存储布局是不一样的,所以较难验证这一结论。在分配debug版程序的局部变量存储空间时,编译器会加入大量调试信息,以便程序员调试源码。
图7-5 一个奇怪的C语言程序
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。