ループの展開 - 2023.2 日本語

Vitis 高位合成ユーザー ガイド (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語

ループは、ループ帰納変数で指定されている反復回数実行されます。反復の回数は、break 条件やループ exit 変数の変更など、ループ本体内のロジックにも影響されます。ループを展開すると、RTL デザインにループ本体のコピーを複数作成できるため、一部またはすべてのループ反復を並列実行できるようになります。UNROLL プラグマを使用すると、データのアクセスおよびスループットを向上するためにループを展開できます。

HLS では、デフォルトでループは展開されません。つまり、ループの各反復で同じハードウェアが使用されるということを意味します。ループを展開するということは、ループの各反復でループ関数を実行するためのハードウェアが使用されるということです。つまり、展開されたループのパフォーマンスは、展開されていないループよりも大幅に向上する可能性があります。ただし、パフォーマンスが向上することで、エリアおよびリソース使用量は増加します。

次の GitHub で公開されいる basic_loops_primer の例を検討します。

#include "test.h"
 
dout_t test(din_t A[N]) { 
  dout_t out_accum=0;
  dsel_t x;
   
  LOOP_1:for (x=0; x<N; x++) {
      out_accum += A[x];
  }
  return out_accum;
}

最適化しない場合、次の図に示す合成サマリレポートでは、インプリメンテーションが順番どおりに実行されていることがわかります。これは LOOP_1 のトリップカウントで確認でき、反復回数が 10 およびレイテンシが 200 とレポートされています。レイテンシは、ループが新しい入力データを受信できるようになるまでの時間です。

図 1. [Performance & Resource Estimates]

最適なスループットを得るためには、レイテンシをできるだけ短くする必要があります。パフォーマンスを向上させるには、ループの境界が静的であるとし、UNROLL プラグマを使用してループを完全に展開し、ループ本体を並行してインプリメントします。LOOP_1 を完全に展開すると、次の図に示すようにレイテンシが大幅に短縮されます (50ns)。ループを展開することで、パフォーマンスは向上しますが、追加のリソースが使用されることになります (次の図に示すように FF および LUT が増加)。また、ループを完全に展開すると、ループ自体が消滅し、ループ本体が並行してインプリメントされ、次に示すようにさらに多くのリソースが消費されます。

図 2. [Performance & Resource Estimates]

もちろん、リソースの増加および利用可能なプラットフォーム リソースの関係で、ループを完全に展開できないケースもあります。このような場合、部分的にループ展開をする方法が、パフォーマンスをある程度向上させながら、多くのリソースを必要としないため、推奨されることがあります。ループを部分的に展開するには、プラグマまたは指示子の展開係数を定義します。このような制約のある場合、検討可能なソリューションとして同じループを係数 2 で展開します (つまり、ループ本体が複製され、トリップカウントは半分の 5 となる)。

図 3. [Performance & Resource Estimates]

さらに、ループを部分的に展開すると、トリップカウントが展開係数で完全に割り切れない場合に備えて、HLS ツールによって終了チェックがループにインプリメントされます。トリップカウントが展開係数で完全に割り切れる場合は、終了チェックはスキップされます。