Intel®高层次综合编译器专业版: 最佳实践指南

ID 683152
日期 6/22/2020
Public

本文档可提供新的版本。客户应 单击此处 前往查看最新版本。

文档目录

4.2.3. 实例:循环流水线和展开

以一种设计为例,其中需要将矩阵的每一列与矩阵中其他列进行点积运算,并将6个结果存储在不同的上层三角矩阵中。矩阵中其余单元设置为0。



代码可能类似于如下代码实例:
1. #define ROWS 4 2.
                #define COLS 4 3. 4. component void dut(...) { 5. float a_matrix[COLS][ROWS]; //
                store in column-major format 6. float r_matrix[ROWS][COLS]; // store in row-major
                format 7. 8. // setup... 9. 10. for (int i = 0; i < COLS; i++) { 11. for (int j =
                i + 1; j < COLS; j++) { 12. 13. float dotProduct = 0; 14. for (int mRow = 0; mRow
                < ROWS; mRow++) { 15. dotProduct += a_matrix[i][mRow] * a_matrix[j][mRow]; 16. }
                17. r_matrix[i][j] = dotProduct; 18. } 19. } 20. 21. // continue... 22. 23.
              }

可将在特定栏条目中迭代的循环展开,以此提高组件性能。如果该循环独立操作,则编译器将并行执行这些循环。

浮点操作通常必须按照源代码中显示的顺序执行,以保持数值精确度。但是也可使用-ffp-contract=fast编译器标记放宽浮点操作的顺序。随着浮点操作顺序的放宽,该循环中的所有乘法都可以并行进行。了解更多信息,请参阅教程: <quartus_installdir>/hls/examples/ tutorials/best_practices/floating_point_ops

当编译器认为展开循环可提供性能时,会尝试自行展开循环。例如,第14行的循环会自动展开,是因为循环中有常量迭代,且并不消耗太多硬件(ROWS是编译时定义的常量,可确保该循环具有固定的迭代次数)。

可展开第11行的j-循环,来提高吞吐量,但要允许编译器展开循环就必须确保其具有constant bound。可从j = 0替代j = i + 1来启动j-loop来确保constant bound。还必须添加一个精确的声明以防止r_matrixj-loop的迭代0,1,2,…i期间分配到无效数据。
01: #define ROWS 4
                02: #define COLS 4 03: 04: component void dut(...) { 05: float a_matrix[COLS][ROWS];
                // store in column-major format 06: float r_matrix[ROWS][COLS]; // store in
                row-major format 07: 08: // setup... 09: 10: for (int i = 0; i < COLS; i++) { 11:
                  12: #pragma unroll 13: for
                  (int j = 0; j < COLS; j++) { 14: float dotProduct = 0; 15: 16: #pragma unroll  17:
                for (int mRow = 0; mRow < ROWS; mRow++) { 18: dotProduct += a_matrix[i][mRow] *
                a_matrix[j][mRow]; 19: } 20: 21: r_matrix[i][j] = (j > i) ? dotProduct : 0; // predication 22: } 23: }
                24: } 25: 26: // continue... 27: 28: }

此时j-loop已完全展开。由于4个迭代之间无依存关系,所以可同时运行。

请从 <quartus_installdir>/hls/examples/tutorials/best_practices/resource_sharing_filter处参阅resource_sharing_filter教程了解更多详细信息。

可继续在第10行展开循环,但展开此处的循环可能导致使用面积又再增加。允许编译器流水线处理此循环以代替将其展开,就可避免面积增加且可能i-loop仅有的II为1则仅多花4个时钟周期。如果II不为1,可在高级设计报告(report.html)中Loops Analysis页面的Details窗格找到改进建议。

以下为影响循环II的常见因素:
  • 循环携带依存关系

    可在 <quartus_installdir>/hls/examples/tutorials/best_practices/loop_memory_dependency处参阅教程

  • 关键且长的循环径
  • 循环II > 1的内部循环