pragma HLS unroll - 2019.2 Japanese

Vitis 統合ソフトウェア プラットフォームの資料: アプリケーション アクセラレーション開発 (UG1393)

Document ID
UG1393
Release Date
2020-02-28
Version
2019.2 Japanese

説明

ループを展開し、複数の演算を 1 つにまとめたものではなく、複数の個別の演算を作成します。UNROLL プラグマを使用すると、RTL デザインにループ本体のコピーを複数作成することにより、一部またはすべてのループ反復を並列実行できるようになります。

C/C++ 関数のループは、デフォルトでは展開されません。ループが展開されていない場合、合成ではそのループの 1 反復に対してロジックが作成され、RTL デザインでこのロジックがループの反復ごとに順に実行されます。ループは、ループ帰納変数で指定されている反復回数実行されます。反復の回数は、break 条件やループ exit 変数の変更など、ループ本体内のロジックにも影響されます。UNROLL プラグマを使用すると、データのアクセスおよびスループットを向上するためにループを展開できます。

UNROLL プラグマでは、ループを完全にまたは部分的に展開できます。ループを完全に展開すると、RTL に各ループ反復対してループ本体のコピーが作成され、ループ全体を同時に実行できるようになります。ループの部分展開では、係数 <N> を指定してループのコピーを <N> 個作成し、ループ反復数を削減します。ループを完全に展開するには、ループの境界がコンパイル時に認識される必要があります。これは部分展開には必要ありません。

ループを部分展開する場合、<N> は最大反復回数の整数因数である必要はありません。Vivado 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 オプションを使用して終了チェックとその関連ロジックを削除できます。これによりエリアが最小限に抑えられ、制御ロジックが単純になります。

ヒント: DATA_PACKARRAY_PARTITIONARRAY_RESHAPE などのプラグマの使用により 1 クロック サイクルでより多くのデータにアクセスできるようになっている場合、このデータを消費するループを展開することによりスループットが向上するのであれば、HLS ツールでこれらのループが自動的に展開されます。ループを完全または部分展開すると、1 クロック サイクルでこれらの追加データを消費するのに十分なハードウェアを作成できます。この機能は、config_unroll コマンドを使用して制御します。詳細は、 『Vivado Design Suite ユーザー ガイド: 高位合成』 (UG902)config_unroll を参照してください。

構文

C/C++ ソースの展開するループの本体内に配置します。

#pragma HLS unroll factor=<N> region skip_exit_check

説明:

factor=<N>
以外の整数値を指定して、部分展開が実行されるようにします。ループの本体が指定した回数繰り返され、反復情報がそれに合わせて調整されます。factor= を指定しない場合、ループは完全に展開されます。
region
オプションのキーワードで、指定したループ自体は展開せずに、そのループの本体 (領域) 内に含まれるすべてのループを展開します。
skip_exit_check
factor= を使用して部分展開を指定している場合にのみ適用されるオプションのキーワードです。ループの反復回数が既知であるかどうかによって、終了チェックが削除されます。
固定 (既知の) 境界
反復回数が係数の倍数である場合は、終了条件はチェックされません。反復回数が係数の整数倍でない場合は、次のようになります。
  1. 展開は実行されません。
  2. 処理を続行するには終了チェックを実行する必要があることを示す警告メッセージが表示されます。
可変 (不明な) 境界
必要に応じて終了条件チェックが削除されます。次を確認してください。
  1. 可変境界が指定した展開係数の整数倍数である。
  2. 終了チェックが不要である。

例 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

次の例では、関数 fooloop_2 を係数 4 で部分展開し、終了チェックを削除しています。

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] = ...;
    ...
  }
  ...
}

例 3

次の例では、関数 fooloop_1 内に含まれるすべてのループを完全に展開しますが、region キーワードを使用して loop_1 自体は展開しないようにしています。

void foo(int data_in[N], int scale, int data_out1[N], int data_out2[N]) {
  int temp1[N];
  loop_1: for(int i = 0; i < N; i++) {  
    #pragma HLS unroll region
    temp1[i] = data_in[i] * scale;
      loop_2: for(int j = 0; j < N; j++) {
        data_out1[j] = temp1[j] * 123;
      }
      loop_3: for(int k = 0; k < N; k++) {
        data_out2[k] = temp1[k] * 456;
      }
  }
}