循环展开
循环展开在指令流水中的优化
背景
软件流水是一种强大的编译器优化技术,通过跨越迭代边界移动操作来利用指令级并行性。它通过将循环的连续迭代的执行流水化来实现迭代之间的重叠,调度循环体:
1、 所有的迭代都有相同的调度。2、 每次迭代在前一次迭代后都有固定的启动延迟
连续两个迭代的启动周期之间的延迟称为启动间距 (Initiation Interval )简称(II),时间间隔越小,软件管道的执行性能越好。所以软件流水线的目的是实现II的最小值。
实现
假设总是有足够的寄存器和高质量的寄存器分配被使用。II的计划值取决于两个约束:1)数据递归和2)计算的资源使用需求、
递归是一种依赖循环,即在循环的一个迭代中的操作直接或间接地依赖于后面一个迭代中的相同操作。与递归有关的操作不能并行执行。因此,软件管道的速度不可能比所有涉及递归的操作的顺序执行速度更快。因此决定了下界。
delay ©是一个依赖周期的延迟和distance©是周期中任意指令的两个依赖实例之间的迭代次数。
资源约束II (ResII)是第二个约束在II上的另一个下界。,因为每个II周期内完成一次迭代,所以II周期中可用的每个资源必须大于或等于一次迭代的资源使用需求,计算如下:
因此,最小启动间隔(MII)必须大于或等于RecII和ResII MII = max(RecII , ResII )
如果递归约束被降低到低于资源约束,则递归约束的软件流水线可以被转换为资源约束的软件流水线。实际上,递归约束通常可以降低到低于资源约束
对于资源受限的软件流水线循环,当关键资源(内存)被充分利用时,吞吐量最大化,
假定内存为关键资源,体系结构中有两个内存插槽。每次迭代发出三次内存访问。ResII的计算值为1.5.但是ResII应该是一个整数,四舍五入到2,浪费了一个内存插槽。为了充分利用这个内存插槽,循环可以展开两次,所有的内存单元都被使用,新的ResII增加到3
原循环:ResII=3/2=1.5=2,
展开两次: 展开2次,一个循环体中放了两次迭代的访问,访问数增加为6次,ResII=6/2=3
为了测量每个循环迭代产生的有效启动间隔,IIaverage被定义为IIunrolled/u
IIaverage=IIunrolled/u(IIunrolled是展开原始循环u次后循环体的启动时间间隔)
原循环:IIaverage=2/1=2
展开两次:IIaverage=3/2=1.5
有效间隔降低说明软件流水的吞吐量变大。
在调度前预测展开因子。选择展开因子有两个步骤。第一个是确定最关键的资源。为了确定最关键的资源,我们定义了
Refresource定义为一个循环迭代中每个循环的平均访问,average表示每个循环的可用资源数。resouce的最大值是最关键的资源
一旦关键资源确定,展开因子的可从下式得到
找到一个u,循环展开u次后,最关键资源的求余变成整数。这可能会填满所有资源槽。一旦最关键的资源被充分利用,就不可能通过以更高的展开因子展开来实现更高的性能。