Intel® 高层次综合编译器专业版Pro版: 参考手册

ID 683349
日期 12/04/2023
Public
文档目录

6.2. 循环依赖项(ivdep预处理指令)

编译组件时, HLS编译器生成硬件,以避免加载和存储指令到组件存储器、agent存储器和外部存储器(通过 Avalon® -MM host接口)之间的任何数据冲突。具体而言,当循环迭代中存在读-写依赖项时会限制性能,因为这些依赖项会在当前迭代完成执行其加载和存储指令之前阻止编译器开始新的循环迭代。
可以选择通过将ivdep预处理指令添加到您的代码来向HLS编译器保证组件的循环迭代中没有潜在的存储器依赖项。

ivdep预处理指令告知编译器可以忽略循环迭代之间的存储器依赖关系。忽略依赖关系可节省面积并降低受影响循环的循环启动间隔(II),因为不再需要避免数据冒险(data hazard)的硬件。

您可以将safelen(N)子句添加到ivdep pragma来提供关于循环依赖项的更多信息。safelen(N)子句指定无循环依赖项的连续循环可以迭代的最大次数。例如,#pragma ivdep safelen(32)指示编译器,在引入循环依赖项之前,循环最多可以进行32次迭代。也就是说,#pragma ivdep承诺此循环的任何迭代之间不存在潜在存储器依赖性;与此同时,#pragma safelen(32)承诺距离本次迭代32次迭代远的那个迭代,可能是本迭代的依赖项中与本迭代最靠近的迭代。

请将行#pragma ivdep array (array_name)添加到组件代码中循环的前面,以指定对循环内内特定存储器数组的访问不会引起循环携带依赖性。被ivdep预处理指令指定的数组必须为以下项之一:
  • 组件存储器数组
  • 指针自变量
  • 指向组件存储器的指针可变量
  • mm_host对象的引用
指定的数组是一个指针,那么ivdep预处理指令也适用于所有与指定指针互为别名的数组。ivdep预处理指令指定的数组也可能是一个结构体的数组或指针成员。
警告:
ivdep预处理指令的错误用法可能会带值硬件中出现功能性错误。

用例1:

如果所有到循环内存储器数组的访问都不会导致循环携带依赖项,则请在该循环之前添加#pragma ivdep

1  // no loop-carried dependencies for A and B array accesses
2  #pragma ivdep
3  for(int i = 0; i < N; i++) {
4      A[i] = A[i + N]; 
5      B[i] = B[i + N];
6  }

用例2:

您可能在特定存储器数组上指定了#pragma ivdep array (array_name),而非所有数组访问。该预处理指令适用于数组、指针或结构体的指针成员。如果指定的数组是指针,则ivdep预处理指令适用于所有可能与指定指针互为别名的数组。

1  // No loop-carried dependencies for A array accesses
 2  // Compiler inserts hardware that reinforces dependency constraints for B
 3  #pragma ivdep array(A)
 4  for(int i = 0; i < N; i++) {
 5      A[i] = A[i - X[i]];
 6      B[i] = B[i - Y[i]];
 7  }
 8
 9  // No loop-carried dependencies for array A inside struct
10  #pragma ivdep array(S.A)
11  for(int i = 0; i < N; i++) {
12      S.A[i] = S.A[i - X[i]];
13  }
14
15  // No loop-carried dependencies for array A inside the struct pointed by S
16  #pragma ivdep array(S->X[2][3].A)
17  for(int i = 0; i < N; i++) {
18      S->X[2][3].A[i] = S.A[i - X[i]];
19  }
20
21  // No loop-carried dependencies for A and B because ptr aliases
22  // with both arrays
23  int *ptr = select ? A : B;
24  #pragma ivdep array(ptr)
25  for(int i = 0; i < N; i++) {
26      A[i] = A[i - X[i]];
27      B[i] = B[i - Y[i]];
28  }
29
30  // No loop-carried dependencies for A because ptr only aliases with A
31  int *ptr = &A[10];
32  #pragma ivdep array(ptr)
33  for(int i = 0; i < N; i++) {
34      A[i] = A[i - X[i]];
35      B[i] = B[i - Y[i]];
36  }
要详细了解关于应用ivdep循环预处理指令后的效果,请可查看以下教程:
<quartus_installdir>/hls/examples/tutorials/best_practices/loop_memory_dependency