説明
Vitis HLS では、ループの同じ反復内での依存 (ループ独立依存) と、ループの異なる反復間の依存 (ループ運搬依存) が検出されます。DEPENDENCE プラグマを使用すると、追加の情報を定義、ループ依存を無効化、ループをより短い間隔でパイプライン処理できます。
- ループ独立依存
- 同じ要素が 1 つのループ反復内でアクセスされます。
for (i=1;i<N;i++) { A[i]=x; y=A[i]; }
- ループ運搬依存
- 同じ要素が異なるループ反復からアクセスされます。
for (i=1;i<N;i++) { A[i]=A[i-1]*2; }
こうした依存は、演算をスケジューリングするタイミング、特に関数およびループのパイプライン処理に影響します。
変数依存の配列インデックスや、外部要件を満たす必要があるような状況 (2 つの入力が同じインデックスにならない場合など) では、依存解析が保守的になりすぎ、偽依存性が検出されることがあります。DEPENDENCE プラグマを使用すると、依存を明示的に定義し、偽依存をなくすことができます。
構文
依存が定義されている関数内に配置します。
#pragma HLS dependence variable=<variable> <class> \
<type> <direction> distance=<int> <dependent>
説明:
-
variable=<variable>
- 依存を考慮する変数を指定します (オプション)。重要: 関数引数が
m_axi
インターフェイスでほかの引数とバンドルでまとめられている場合は、その関数引数にdependence
を指定できません。これは、関数のm_axi
インターフェイスのデフォルト設定です。また、構造体が分割されていない場合、構造体の要素に依存は指定できません。 -
class=[array | pointer]
- 依存を明確にする必要がある変数のクラスを指定します (オプション)。有効な値は
array
またはpointer
です。ヒント: 1 つの変数または関数内の変数のクラスの依存は指定できるので、<class>
とvariable=
は一緒に指定するべきではありません。 -
type=[inter | intra]
- 有効な値は
intra
またはinter
です。依存のタイプを指定します。-
intra
- 同じループ反復内の依存。
<type>
をintra
、<dependent>
を false に設定すると、HLS ツールによりループ内で演算を自由に移動でき、パフォーマンスまたはエリアを向上できる可能性が高くなります。<dependent>
を true に設定すると、演算を指定の順序で実行する必要があります。 -
inter
- 異なるループ反復間の依存。これがデフォルトの
<type>
です。<type> をinter
、<dependent>
を false に設定すると、関数またはループがパイプライン処理されているか、ループが展開されていない場合または部分的に展開されている場合に、並列実行が可能になり、<dependent>
を true に設定すると並列実行が不可能になります。
-
-
direction=[RAW | WAR | WAW]
- これはループ運搬依存にのみ関連し、依存の方向を指定します。
-
RAW
(Read-After-Write - 真の依存) - 書き込み命令により値が書き込まれ、その値が読み出し命令で使用されます。
-
WAR
(Write-After-Read - アンチ依存) - 読み出し命令で値が取得され、その値が書き込み命令で上書きされます。
-
WAW
(Write-After-Write - 出力依存) - 2 つの書き込み命令により、特定の順序で同じロケーションに書き込みが実行されます。
-
-
distance=<int>
- 配列アクセスの反復間隔を指定します。これは、依存が
true
に設定されているループ運搬依存でのみ使用されます。 -
<dependent>
-
<dependent>
引数には依存を使用する必要があるか (true
)、削除するか (false
) を指定します。指定しない場合、値が指定されていないことを示す警告メッセージが表示され、false
が指定されているのと同様に処理されます。使用できる値はtrue
またはfalse
です。
例 1
次の例では、HLS ツールでは cols
の値を認識する機能がないので、buff_A[1][col]
への書き込みと buff_A[1][col]
の読み出し間に常に依存性があると想定されます。このようなアルゴリズムでは、cols
が 0 になることはほとんどありませんが、HLS ツールではデータ依存を想定できません。この依存を解決するため、DEPENDENCE
プラグマを使用して、ループ反復間 (この例の場合は buff_A
と buff_B
の両方) に依存がないことを指定できます。
void foo(int rows, int cols, ...){
for (row = 0; row < rows + 1; row++) {
for (col = 0; col < cols + 1; col++) {
#pragma HLS PIPELINE II=1
#pragma HLS dependence variable=buff_A type=inter false
#pragma HLS dependence variable=buff_B type=inter false
if (col < cols) {
buff_A[2][col] = buff_A[1][col]; // read from buff_A[1][col]
buff_A[1][col] = buff_A[0][col]; // write to buff_A[1][col]
buff_B[1][col] = buff_B[0][col];
}
}
}
}
例 2
次の例は、関数 func
の loop_1
の同じ反復内での Var1
間の依存を削除します。
#pragma HLS dependence variable=Var1 type=intra false
例 3
次の例では、関数 func
の loop_2
にあるすべての配列の依存を定義し、同じループ反復ではすべての読み出しが書き込みの後に実行される (RAW) ように設定しています。
#pragma HLS dependence class=array type=intra direction=RAW true