在综合期间会执行多次最优化(例如,强度折减和位宽最小化)。在自动最优化列表中也包括表达式平衡。
表达式平衡会重新排列运算符以构造平衡的树结构并降低时延。
- 对于整数运算,默认情况下表达式平衡处于开启状态,但可使用 EXPRESSION_BALANCE 编译指示或指令将其禁用。
- 对于浮点运算,默认情况下表达式平衡处于关闭状态,但可使用
config_compile -unsafe_math_optimizations
来启用,如下所述。
对于使用如下示例所示或者由循环展开而产生的 +=
和 *=
之类的赋值运算符的高度循序代码:
data_t foo_top (data_t a, data_t b, data_t c, data_t d)
{
data_t sum;
sum = 0;
sum += a;
sum += b;
sum += c;
sum += d;
return sum;
}
如果不使用表达式平衡并且假定每个加法都需要 1 个时钟周期,那么完整计算 sum
需要 4 个时钟周期,如下图所示。
但加法 a+b
和 c+d
可并行执行以缩减时延。经过平衡后,计算可在 2 个时钟周期内完成,如下图所示。表达式平衡禁止共享,导致面积增加。
对于整数,您可使用 EXPRESSION_BALANCE 最优化指令配合 off
选项来禁用表达式平衡。默认情况下,Vitis HLS 对于 float
类型或 double
类型的运算不执行 EXPRESSION_BALANCE 最优化。对 float
和 double
类型进行综合时,Vitis HLS 会保留 C/C++ 语言代码中执行的运算顺序,以确保结果与 C/C++ 语言仿真相同。例如,在以下代码示例中,所有变量类型均为 float
或 double
。O1
和 O2
即使看似执行相同的基本操作,其值也并不同。
A=B*C; A=B*F;
D=E*F; D=E*C;
O1=A*D O2=A*D;
此行为是 C/C++ 语言标准中执行 float
或 double
类型的运算时饱和和舍入所导致的结果。因此,存在类型为 float
或 double
的函数时,Vitis HLS 始终保留运算顺序不变,并且默认不执行表达式平衡。
您可为特定运算启用表达式平衡,或者也可对 float
类型和 double
类型启用表达式平衡,只需按如下所示方式使用 config_compile
-unsafe_math_optimizations
命令即可:
- 在 Vitis HLS IDE 中,选择 (解决方案 > 解决方案设置)。
- 在“Solution Settings”(解决方案设置)对话框中,单击General(常规)类别,然后选择config_compile,并启用unsafe_math_optimizations。
启用此设置后,Vitis HLS 即可更改运算顺序,以生成更优化的设计。但 C/RTL 协同仿真的结果可能与 C/C++ 语言仿真不同。
unsafe_math_optimizations
功能还支持 no_signed_zeros
最优化。no_signed_zeros
最优化可确保以下表达式配合 float
类型和 double
类型使用时结果完全相同:
x - 0.0 = x;
x + 0.0 = x;
0.0 - x = -x;
x - x = 0.0;
x*0.0 = 0.0;
如果不使用 no_signed_zeros
最优化,由于舍入,以上表达式结果将不同。通过在 config_compile
命令中仅选中该选项,即可选择在不使用表达式平衡的情况下执行此最优化。
unsafe_math_optimizations
和 no_signed_zero
最优化时,RTL 实现结果将不同于 C/C++ 语言仿真。测试激励文件应可忽略结果中的轻微差异:检查范围,不执行精确比对。