Intel® FPGA SDK for OpenCL™ Pro Edition: 最佳实践实践指南

ID 683521
日期 9/26/2022
Public
文档目录

6.1.2. 松弛循环携带的依赖性

基于优化报告的反馈,您可以通过增加依赖项的距离来松弛循环携带的依赖性。 通过增加循环携带的值的生成及其使用之间发生的循环迭代的次数,来增加依赖项距离。

请参考如下代码实例:

1 #define N 128
 2 
 3 __kernel void unoptimized (__global float * restrict A,
 4                            __global float * restrict result)
 5 {
 6   float mul = 1.0f;
 7 
 8   for (unsigned i = 0; i < N; i++)
 9     mul *= A[i];
10 
11   * result = mul;
12 }
 

上述优化报告显式 Intel® FPGA SDK for OpenCL™ Offline Compiler成功推断了循环的流水线执行。但是,变量mul上循环携带的依赖项导致循环迭代每6个周期启动一次。该情况下,第9行上的浮点乘法操作(即,mul *= A[i])对变量mul的计算贡献最大的延迟。

要松弛循环携带的数据依赖性,除了使用单个变量来存储乘法结果,还可以在变量的M副本上进行操作并每M次迭代使用一个副本:

  1. 声明变量mul的多个副本(例如,在名为mul_copies的数组中)。
  2. 初始化mul_copies的所有副本。
  3. 在乘法运算中使用数组中的最后一个副本。
  4. 执行移位操作以将数组的最后一个值传回移位寄存器的开头。
  5. 减少mul的副本,并将最终值写入result
以下是重构的内核:
 1 #define N 128
 2 #define M 8
 3 
 4 __kernel void optimized (__global float * restrict A,
 5                          __global float * restrict result)
 6 {
 7   float mul = 1.0f;
 8 
 9   // Step 1: Declare multiple copies of variable mul
10   float mul_copies[M];
11 
12   // Step 2: Initialize all copies
13   for (unsigned i = 0; i < M; i++)
14     mul_copies[i] = 1.0f;
15 
16   for (unsigned i = 0; i < N; i++) {
17     // Step 3: Perform multiplication on the last copy
18     float cur = mul_copies[M-1] * A[i];
19 
20     // Step 4a: Shift copies
21     #pragma unroll 
22     for (unsigned j = M-1; j > 0; j--)
23       mul_copies[j] = mul_copies[j-1];
24 
25     // Step 4b: Insert updated copy at the beginning
26     mul_copies[0] = cur;
27   }
28 
29   // Step 5: Perform reduction on copies
30   #pragma unroll 
31   for (unsigned i = 0; i < M; i++)
32     mul *= mul_copies[i];
33 
34   * result = mul;
35 }

类似于以下内容的优化报告指示成功松弛了变量mul上的循环携带依赖项: