« 上一篇下一篇 »

更新数据依赖关系

代码移动可能会改变运算之间的数据依赖关系。因此在每次代码移动之后都必须更新数据依赖关系。

对x的两个赋值 之一可以被向上移动到顶部的基本块,因为这样的转换保持了原程序中的所有依赖关系。但是,一但我们把其中一个赋值语句上移,就不能再移动另一个。更明确地说,我们看到在代码移动之前顶部的基本块的出口处X是不活跃的,但是在移动之后就变得活跃了。如果一个变量在一个程序点上活跃,那么我们不能把对该变量的投机性定值移动到该程序点的前面。

全局调度算法

我们看到代码移动对某些路径有益,但是会损害另外一些路径的性能。好消息是指令并不是生而平等的。实际上,我们知道,一个程序的90%以上的执行时间被花在不到10%的代码上。因此,我们可以把目标确定为使得频繁执行的路径更快运行,虽然有可能降低不频繁路径的运行速度。

编译器有多种技术来估算执行频率。我们有理由假设在最内层的循环中的指令比外层循环中的指令执行得更频繁,也有理由假设选择向回跳转分支的使用频率高过不选择这个分支的使用频率。另外,转向程序出口或者异常处理例程的分支不大可能被选择执行。但是,最好的频率估算来自于动态获取的程序运行剖面。在这个技术中,程序经过插装以记录程序运行时刻各个条件分支的出口选择情况。然后,程序就在有代表性的输人上运行,确定程序总体的运行行为。人们发现应用这个技术得到的结果相当精确。这样的信息可以反馈给编译器,由编译器在其优化过程中使用。

基于区域的调度

现在我们描述一个简单的全局调度器,它支持两种最容易的代码移动:

1)把运算向上移动到控制等价的基本块。

2)把运算向上移动一个分支,移动到一个支配的前驱中。

« 上一篇下一篇 »