pragma HLS unroll - 2023.2 简体中文

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

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 简体中文

描述

您可展开循环以创建多个独立操作而非单个操作集。UNROLL 编译指示会通过在 RTL 设计中创建循环主体的多个副本来变换循环,从而允许部分或全部循环迭代并行发生。

C/C++ 语言函数中的循环默认情况下全部保持收起状态。收起循环时,综合会为循环的单次迭代创建逻辑,RTL 设计会为序列中循环的每次迭代都执行此逻辑。循环的迭代执行次数由循环归纳变量来指定。迭代次数也可能受到循环主体内的逻辑影响(例如,对循环出口变量条件应用 break 条件或修改)。您可使用 UNROLL 编译指示展开循环以便增加数据访问和吞吐量。

UNROLL 编译指示支持将循环完全展开或部分展开。完全展开循环会在 RTL 内为每个循环迭代创建一份循环主体副本,因此整个循环可并发运行。部分展开循环允许您指定因子 N 以创建 N 份循环主体副本,并相应减少循环迭代。

提示: 要完全展开循环,在编译时循环边界必须已知。对于部分展开则无需满足此条件。

部分循环展开不要求 N 为最大循环迭代计数的整数因子。Vitis HLS 工具会添加出口检查以确保部分展开的循环的功能与原始循环相同。例如,给定以下代码:

for(int i = 0; i < X; i++) {
  pragma HLS unroll factor=2
  a[i] = b[i] + c[i];
}
按因子 2 展开的循环可将代码有效变换为如下所示代码,其中 break 构造函数用于确保功能保持不变,并且循环会在相应的点退出。
for(int i = 0; i < X; i += 2) {
  a[i] = b[i] + c[i];
  if (i+1 >= X) break;
  a[i+1] = b[i+1] + c[i+1];
}

在以上示例中,由于最大迭代计数 X 可用,因此 HLS 工具可能无法判定其值,故而它给部分展开的循环添加了出口检查和控制逻辑。但如果您已知指定的展开因子(在此示例中为 2)是最大迭代计数 X 的整数因子,那么 skip_exit_check 选项允许您移除出口检查和关联的逻辑。这有助于最大限度降低面积并简化控制逻辑。

提示: 当使用 ARRAY_PARTITION 或 ARRAY_RESHAPE 之类的编译指示支持在单个时钟周期内访问更多数据时,HLS 工具会自动展开耗用该数据的任意循环,前提是这样可提高吞吐量。循环可全部或部分展开以创建足够的硬件以便在单一时钟周期内使用更多数据。这种自动展开可使用 config_unroll 命令来控制。

语法

将 C 语言源代码中的编译指示置于要展开的循环主体内。

#pragma HLS unroll factor=<N> skip_exit_check off=true

其中:

factor=<N>
指定非零整数,表示已请求部分展开。循环主体将重复指定次数,迭代信息将进行相应的调整。如不指定 factor=,则循环将完全展开。
skip_exit_check
可选关键字,仅当使用 factor= 指定部分展开时才适用。根据循环迭代计数为已知还是未知来判断是否消除出口检查:
  • 固定边界

    如果迭代计数为因数的倍数,则不执行出口条件检查。

    如果迭代计数并非因数的整数倍,则该工具将执行以下操作:

    • 阻止展开。
    • 发出警告,称必须执行出口检查后才能继续。
  • 变量边界

    移除出口条件检查。您必须确保:

    • 变量边界为因数的整数倍。
    • 实际上无需出口检查。
off=true
为指定循环禁用展开。

示例 1

以下示例在 foo 函数内完全展开 loop_1。将编译指示置于 loop_1 主体内,如图所示。

loop_1: for(int i = 0; i < N; i++) {
  #pragma HLS unroll
  a[i] = b[i] + c[i];
}

示例 2

此示例指定展开因子为 4,以部分展开 foo 函数的 loop_2,并移除出口检查。

void foo (...) {
  int8 array1[M];
  int12 array2[N];
  ...
  loop_2: for(i=0;i<M;i++) {
    #pragma HLS unroll skip_exit_check factor=4
    array1[i] = ...;  
    array2[i] = ...;
    ...
  }
  ...
}