set_directive_loop_flatten - 2025.2 简体中文 - UG1399

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2025-11-20
Version
2025.2 简体中文

描述

允许将内层嵌套循环折叠(平铺)为单个循环,以便在循环的所有迭代上应用流水打拍,从而实现更低的时延。

只能对最内层的循环(完成可能的内部展开后)进行流水打拍。外层循环只能是数据流循环或顺序循环。当流水打拍循环上层的循环为顺序循环时,其迭代会依次执行,而且每次迭代,就会完全执行一次内层循环。在 RTL 实现中,从外层循环移动到内层循环需要一个时钟周期,从内层循环移回外层循环需要一个时钟周期,并且中间要加上完成内层循环的所有迭代的完整时延。与此相反,平铺嵌套循环可以将其作为单个循环来进行优化和流水打拍,这样外层循环的迭代与内层循环不同调用的迭代之间就可能发生重叠(流水打拍)。总之,平铺可以提高性能,但是:

  • 平铺并非总是可行,需要遵循一定的编码风格。
  • 在某些情况下,根据外层循环中的运算和/或依赖关系,时序甚至 II 都可能会劣化。

set_directive_loop_flatten 编译指示应用于循环层级的最内层循环的循环主体。只有完美循环和近乎完美的嵌套循环(在完成可能的初步函数内联或循环展开后)才能以这种方式加以平铺:

完美循环嵌套
  • 每个非最内层循环的主体都包含一个且仅包含一个子循环,不包含任何其他指令。
近乎完美的循环嵌套
  • 每个非最内层循环的主体都包含一个且仅包含一个子循环,无任何其他控制流。
  • 每个非最内层循环的主体都不得包含任何含循环的函数调用。

对于近乎完美的循环,编译器会将两个循环之间存在的任何指令自动“推入”最内层的循环,从而使这些循环完美嵌套。

此外具备平铺能力的循环还需要满足一些要求:

  • 每个循环都应该是 for 循环,而不是 while 循环;并且不含 break 语句。
  • 在平铺循环之前,编译器应能计算出每个循环的循环次数(但它不必是一个常数)。典型的编码风格如下:
    • 所含循环计数器按常数递增的循环。
    • 循环计数器的下限和上限不依赖于要平铺的循环(应满足“循环不可变”条件)。

举例来说,如果循环的内层循环次数取决于外层循环计数器,那么这类循环就不具备平铺能力。

编译器无法平铺不完美的循环嵌套(即,当循环包含多个子循环或控制流时)。在此情况下,需要手动执行平铺,方法是重构代码,将指令推入最内层的循环,或者展开内层循环以在其上层创建完美循环嵌套。

语法

set_directive_loop_flatten [OPTIONS] <location>
  • <location> 表示最内层循环的位置,格式为 function[/label]

选项

-offoff=true

可选关键字。阻止将 loop_flatten 设为 off 的循环与其子循环(如有)一起进行平铺。

重要: 存在 LOOP_FLATTEN 编译指示和指令即表示启用优化。添加 -off 则表示禁用优化。

示例

foo 函数中的 loop_1 及循环层级中位于其上层的所有(完美或近乎完美)循环平铺为单一循环。将编译指示置于 loop_1 主体内。

set_directive_loop_flatten foo/loop_1

防止在 foo 函数的 loop_2 中进行循环平铺。将编译指示置于 loop_2 主体内。

set_directive_loop_flatten -off foo/loop_2

如需获取更完整的示例,请参阅对应的 pragma HLS loop_flatten 章节。