循环展开 - 2022.1 简体中文

Vitis 统一软件平台文档 应用加速开发 (UG1393)

Document ID
UG1393
Release Date
2022-05-25
Version
2022.1 简体中文
编译器还可将循环部分展开或完全展开,以便并行执行多次循环迭代。这是使用 pragma HLS unroll 来执行的。展开循环可显著提升并行度,从而实现超快设计。但由于循环迭代的所有操作都并行执行,因此需要大量可编程逻辑资源来实现硬件。由此导致编译器可能面临诸如处理大量资源等难题,并且可能遇到容量问题,从而导致内核编译进程减缓。最好仅对所含循环主体较小或者所含迭代数量较少的循环执行展开。
vadd: for(int i = 0; i < 20; i++) {
  #pragma HLS UNROLL
  c[i] = a[i] + b[i];
}

在前例中,您可以看到 pragma HLS UNROLL 已插入循环主体,以指示编译器完全展开循环。如果数据依赖关系允许,那么全部 20 项循环迭代都将并行执行。

提示: 完全展开循环可能耗用大量器件资源,而部分展开循环则可提升性能同时减少所用硬件资源量。

循环已部分展开

要完全展开循环,此循环必须具有恒定界限(即上例中的 20)。但对于具有可变界限的循环,则可执行部分展开。部分展开的循环表示只能并行执行一定数量的循环迭代。

以下代码示例演示了部分展开的循环的工作方式:
array_sum:for(int i=0;i<4;i++){
  #pragma HLS UNROLL factor=2
  sum += arr[i];
}

在以上示例中,对于 UNROLL 编译指示赋值因数 2。这等同于手动复制循环主体,并发运行两个迭代,且运行数为迭代数的一半。为此编写的代码如下所示。此变换允许以上循环的两次迭代并行执行。

array_sum_unrolled:for(int i=0;i<4;i+=2){
  // Manual unroll by a factor 2
  sum += arr[i];
  sum += arr[i+1];
}

就像循环内部的数据依赖关系影响流水打拍式循环的启动时间间隔一样,展开的循环仅在数据依赖关系允许的前提下才会并行执行操作。如果某一循环迭代中的操作需要上一次循环的结果,则这两次迭代无法并行执行,但一旦来自任一迭代的数据可供另一迭代使用,即可立即执行。