合成中は、駆動電流の削減やビット幅の最小化など、複数の最適化が実行されます。自動最適化には、演算式バランス調整も含まれます。
演算式バランス調整では、演算子を並べ替えてバランスの取れたツリーを構築することにより、レイテンシを削減します。
- 整数演算の演算式バランス調整はデフォルトでオンになっていますが、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
sum の計算に 4 クロック サイクルかかります。
ただし、加算 a+b
および c+d
は並列実行できるので、レイテンシを削減できます。このように計算のバランスが調整されると、計算は 2 クロック サイクルで終了します。演算式バランス調整を使用すると共有はできず、エリアは増加します。
整数に対しては、EXPRESSION_BALANCE 最適化指示子を off
に設定すると、演算式バランス調整をオフにできます。デフォルトでは、HLS ツールは float
または double
型の演算に対しては EXPRESSION_BALANCE 最適化を実行しません。float
および double
型の合成では、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;
これは、float
または double
型の演算における C/C++ 標準の飽和および丸めの結果です。このため、HLS コンパイラでは float
または double
型の変数が使用され、デフォルトで演算式のバランス調整が実行されない場合、演算の順序が常に維持されます。
特定の演算に対して演算式バランス調整をオンにしたり、syn.compile.unsafe_math_optimizations=1
コンフィギュレーション コマンドを使用して float
および double
型の演算で演算式バランス調整をオンにしたりできます。
この設定をオンにすると、さらに最適なデザインが生成されるように演算の順序が変更されることがありますが、C/RTL 協調シミュレーションの結果が C/C++ シミュレーションと異なるものになる可能性があります。
unsafe_math_optimizations
を使用すると、syn.compile.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
最適化が使用されない場合は、丸めが実行されるので、上記の演算式は同一になりません。この最適化は、syn.compile.no_signed_zeros
コンフィギュレーション コマンドのみを選択すると、演算式バランス調整なしで使用できます。
unsafe_math_optimizations
および no_signed_zero
最適化が使用されると、RTL インプリメンテーションが C/C++ シミュレーションとは異なる結果になります。テストベンチでは、結果の多少の違いは無視できるので、範囲を確認し、厳密には比較しないでください。