- 注册时间
- 2007-12-27
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 40142
- 在线时间
- 小时
|
楼主 |
发表于 2008-2-20 12:27:36
|
显示全部楼层
现在开始考虑前面的问题,对于一个给定的循环,采用下列的循环优化如:
循环交换(Loop Interchange),循环反向(Loop Reversal),循环扭曲(Loop Skewing)等变化以及它们的组合
是否合法。
这个就是么模变换要讨论的问题。
么模变换首先假设循环体中的所有数据依赖关系都可以表示成依赖向量。这是一个很强的前提条件,通常,这个
要求循环中牵涉到的数据都是数组,不然,数据依赖关系就很难表达成依赖向量了。所以通常适合么模变换的代码
都是科学计算方面的代码。此外,编译器还要事先对代码做一些简单的变换,比如下面的代码:- for(i=0;i<n;i++){
- for(j=0;j<n;j++){
- x= A[i][j];
- B[i][j]+=x;
- }
- }
复制代码 显然可以看出,对于变量x,所有的循环迭代之间都有关于x的输出依赖关系,所以这种依赖关系就无法表达成依赖向量,
但是我们可以通过消去标量x,将代码变化成- for(i=0;i<n;i++){
- for(j=0;j<n;j++){
- B[i][j]+= A[i][j];
- }
- }
复制代码 那么就没有这个问题了,现在唯一的数据依赖就是依赖向量(0,0).
同样对于一些无法消除的关于标量的数据依赖关系,也可以通过将标量转化成数组来达到我们的目的,但是这种转化通常情况代价
比较大,很少会真正采用,比如上面的代码也可以转化为一下等价的代码:- for(i=0;i<n;i++){
- for(j=0;j<n;j++){
- X[i][j]= A[i][j];
- B[i][j]+=X[i][j];
- }
- }
复制代码 但是显然这种转化不是很好。
此外还有一种特殊情况我们可以利用,这中情况在实际应用中会经常遇上,比如代码- for(i=0;i<n;i++){
- ...
- err+=(A[i]-B[i])*(A[i]-B[i]);
- if(...){
- err -= A[i]*B[i];
- }
- }
复制代码 对于上面这个代码,显然关于标量err,同样所有的循环迭代之间都有输出依赖关系,这种依赖关系无法表达成依赖向量。
但是我们知道,如果上面的代码中,所有对于err的操作都是+=和-=某个同err无关的数据,由于我们知道+和-法操作满足结合率,
也就是我们可以任意改变上面所有累加累减的顺序而不会改变代码的正确性,所以实际上,这种依赖关系在我们的循环变换中
也可以忽略掉。所以对于这样的代码,我们依旧可以采用么模变换的判断方法。
想上面这种由于满足结合率导致我们可以忽略其数据依赖关系的操作符,我们称为Reduce操作符。典型的Reduce操作符有+,-,*,/(浮点除法,
整数除法由于截断,不符合要求),移位,逻辑运算,位运算等。
而最常见的就是+,-运算。通常的编译器都应该能够支持将整数的+,-运算作为Reduce操作符。而关于普通整数乘法由于实际上很难遇上所以一般
不会采用。而对于浮点数的乘除运算,通常编译器由于考虑到会对计算精度产生影响而不采用(对于部分编译器打开特殊优化选项则会采用)。
有了以上分析,我们可以大概知道对于那些循环可以采用么模变换的方法来判断一个循环变换是否合法了。
首先,这个循环中所有数据依赖关系都可以写成一批依赖向量,
我们可以注意到,所有这些依赖向量都必然是非负的(0或正的),这里正负的定义采用我们前面定义的方法(也就是第一项非零数据为正的称为正向量)。
我们继续查看前面用到的一个关于循环变换的图片
可以看出,每个变换都被一个矩阵所标识,实际上,由于循环变换而引起循环迭代空间上发生了一种线性变换,这个矩阵就代表了这种线性变换。
如第一中Loop Interchange是交换两层循环的位置,相当于循环迭代空间旋转90度,所以对应的变换矩阵是$[(0,1),(1,0)]$,
后面的变换也都类似,通过画图就可以比较清楚看出来所用的矩阵应该是什么。
么模变换的理论就是如果我们采用了一个线性的循环变换,对于的矩阵是A,那么对于每个数据依赖关系v,变换后数据依赖关系就变成Av了。
我们知道,对于一个循环,初始所有的数据依赖关系都是非负的。同样,对于一个合法的变换矩阵A,它必须使得对于每个数据依赖关系v,
Av也必须是一个非负的向量。这个就是判断一个循环变换是否合法的基本准则。 |
|