インアクティブおよびテール要素の「変更なし」と「ゼロ設定」に関する議論 ====================================================================== 1. イントロダクション --------------------- この文章では、ベクトル命令においてアクティブでない要素に対する書き込みについて、 - a) 値の変更なし - b) ゼロ化 の方式について議論をまとめたものである。 ベクトルの設計における3つ目の選択肢として、これらの要素の値を「未定義」とするものがある。この選択肢を採用しなかったのは、各実装において互換性が維持できないと考えたためであり、また同時にセキュリティに関する問題も発生するためである。 2. これまでの仕様 (v0.7.1) -------------------------- RISC-Vのベクトル仕様では、ベクトル命令によって取り扱われる要素のオペランドを4種類に分類している: プリスタート、アクティブ、インアクティブ、テール、である。プリスタートの要素は\ ``vstart``\ よりも前の要素である。アクティブ、インアクティブの要素は\ ``vstart``\ から\ ``vl``\ までの要素であるが、アクティブな要素はマスクが有効化されており、インアクティブな要素はマスクが無効化されている。テールの要素は\ ``vl``\ よりも先の要素である。 現在のベクトル仕様(v0.7.1)では、ベクトル命令は書き込みレジスタグループに対して以下の表に基づいて動作する: 表1. 0.7.1のベクトル仕様におけるベクトルレジスタグループの書き込み時の動作 ============== ====================== 要素のカテゴリ 書き込みレジスタの動作 ============== ====================== プリスタート 変更なし アクティブ 新しい値を書き込む インアクティブ 変更なし テール ゼロを書き込む ============== ====================== プリスタートとアクティブな要素は意図通りの挙動である(プリスタートは変更なし、アクティブな要素はアップデートが行われる)。 インアクティブな要素に対する挙動は「変更なし」、テール要素についてはゼロを書き込むようになっている。 どちらの挙動も実装によりサポートする必要が生じ、以下に示すようなコストが発生する。 3. 実装例 --------- 実装における仕様決定を助けるために、タスクグループでは以下の表を作成した。実装の範囲は非常に小さな組み込み向けプロセッサから巨大なスーパコンピュータノードまでカバーしている。 表2. ベクトル実装例 +---------------+----------+---------+---------------+---------------+ | 説明 | 命令発行 | VLEN | デー | ア | | | | | タパスサイズ | ーキテクチャ | | | | | | のストレージ | +===============+==========+=========+===============+===============+ | 最小 | InO | 32b | 32b | 128B | +---------------+----------+---------+---------------+---------------+ | InO | InO | 128b | 128b | 512B | | 空間的な | | | | | | スーパスカラ | | | | | +---------------+----------+---------+---------------+---------------+ | InO | InO | 512b | 128b | 2,048B | | 短い | | | | | | 中間レジスタ | | | | | +---------------+----------+---------+---------------+---------------+ | InO | InO | 4,096b | 64b | 16,384B | | 長い | | | | | | 中間レジスタ | | | | | +---------------+----------+---------+---------------+---------------+ | OoO | OoO | 128b | 128b | 512B | | 空間的な | | | | | | スーパスカラ | | | | | +---------------+----------+---------+---------------+---------------+ | OoO | OoO | 512b | 128b | 2,048B | | 中間 | | | | | | スーパスカラ | | | | | +---------------+----------+---------+---------------+---------------+ | OoO | OoO | 2,048b | 512b | 8,192B | | スーパ | | | | | | スカラサーバ | | | | | +---------------+----------+---------+---------------+---------------+ | HPC ノード | OoO | 16,384b | 2048b | 65,536B | +---------------+----------+---------+---------------+---------------+ 4. 書き込み要素の「変更なし」の実装 ----------------------------------- 4.1. リネーミングを行わない場合の「変更なし」の実装 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ベクトルレジスタのリネーミングを行わないマシンでは、要素の変更を行わないというのは最もシンプルな方法である。ハードウェアとしては、書き込みを行わない要素に対してマスクを行い、オリジナルの値を保持する。 4.2. リネーミングを行う場合の「変更なし」の実装 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ベクトルレジスタのリネーミングを行うマシンでは、新しい物理書き込みベクトルレジスタが、各ベクトル書き込みレジスタに対して割り当てられる。 「値の変更なし」の場合はオリジナルの物理レジスタから新しい物理レジスタに対してコピーを行う必要がある。これにはオリジナルの値を読み出すためのさらなる読み出しポートが必要になる。 加えて、値の変更を行わない要素に対してはオリジナルの書き込みベクトルレジスタと新しい命令に対するRAWハザードを挿入する必要があり、これにより性能低下の可能性がある。 真に空間的なレジスタを持つマシンでレジスタリネーミングを行う場合、値の変更を行わないテールの要素は余分な実行サイクルを生じない。 すべてのテール要素は他の要素と同じサイクルで書き込まれる。 この時に古い値を読み出すために余分な電力が必要となる。 長い中間ベクトルレジスタをリネーミングするマシンでは、古いテール要素を読みだして新しい物理レジスタに書き込みを行うための余計なサイクルが必要となる。 しかし、リネーミングされたベクトルマシンはベクトルレジスタグループ内の個々のベクトルレジスタを個別にリネーミングしなければならないと仮定できる。 したがって大きなLMUL値を持っている場合にはテール要素の値を変更しないというペナルティは大きく増加しない。 さらに、長いベクトルレジスタを小さなサブレジスタに分割して個別にリネーミングすることでテール要素のコピーのペナルティを削減することができる。しかし、この場合はリネーミングテーブルのコストが増加する。 殆どのOoOマシンのリネーミングは長い中間ベクトルレジスタを持っていないと仮定しており、OoO実行とリネーミングは、長い中間ベクトルレジスタを保持する動機を減少させる。 他のいくつかのOoOマシンでは、インオーダベクトルユニットに長い中間ベクトルレジスタを実装している。この実装ではロードデータキューを分離しておりメモリアクセスのアウトオブオーダをサポートしている。値の変更を行わない要素についてはリネーミングを行わずに任意のベクトルユニットで取り扱われる。 5. 書き込み要素の「ゼロ設定」の実装 ----------------------------------- 5.1. リネーミングを行わない場合の書き込み要素の「ゼロ設定」の実装 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ インアクティブな要素とテール要素に対してゼロを設定する場合には、レジスタリネーミングを行わない場合は実装が複雑になる。 もっとも単純な実装では、明示的に書き込み要素に対してゼロを書き込む。この場合にはすべてのベクトル命令において最大ベクトル長と同じだけの実行時間が必要となる。これはLMULが大きな値になっている実装では、全体のベクトルレジスタファイルの1/4の要素を書き込む必要が生じる。 リネーミングを行わない最適化されたシステムでは、マイクロアーキテクチャが各\ **要素グループ**\ についてゼロビットを付加する。要素グループがマイクロアーキテクチャ的にベクトル実行のアトミックユニットとして動作し、空間的なデータパスと同じ長さの意味を持つように実装できる。 ゼロビットは、その要素グループの値がすべてゼロであることを示す。ベクトル機能ユニットへの命令ディスパッチでは、ビットベクトルはスナップショットを取っておく。ベクトル機能ユニットに発行する際、ゼロ化された要素グループを読む場合には読み込みポートにゼロを出力するためのマルチプレクサを付加しておく。また、ゼロビットが設定されている要素グループに対して書き込みを行う場合は、インアクティブな要素とテールの要素にゼロを書き込むためにMuxを設定する。そののちにゼロビットをリセットする。 ディスパッチ後にデコードステージのビットベクトルは要素グループと一緒にアップデートされる必要があり、ゼロに設定されなければならない(例えば、\ ``vl``\ よりも短い要素)。これにより、以降の命令がアップデートされたビットベクトルを使って命令をディスパッチできるようになる。 5.2. リネーミングを行う場合の書き込み要素の「ゼロ設定」の実装 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ アウトオブオーダのベクトルマシンにおいて、空間的なベクトルレジスタの場合は書き込みベクトルレジスタに対してインアクティブな要素とテール要素に対して直接ゼロを書き込めばよい。大きなLMUL値の場合には、テール要素のすべてのベクトルレジスタは単一の定数ゼロレジスタにリネームされ、物理レジスタのストレージを削減する効果を持つ。 中間ベクトルレジスタを持つリリネーミングを行うベクトルマシンでは、インオーダベクトル命令と同様に、マイクロアーキテクチャ的なゼロビットを各要素グループに設定する。インオーダベクトルとは異なり、すべての要素は新しい値を書き込むことができる。 6. ソフトウェアの影響 --------------------- 要素の変更なしと、ゼロ設定についてソフトウェアの影響は、テール要素に対する処理よりもインアクティブな要素に対する影響の方が大きい。なぜならばインアクティブな要素は実行ループイタレーション内で実行される想定であり、テール要素はループの終了時の処理となるからである。 インアクティブな要素を残すことで、2つのベクトル値をオーバラップしないマスクを使用しtえ1つのベクトルレジスタに移動することができる。これによりレジスタの圧縮を行うことができ、コードのスケジューリングや複数の制御パス(例えば、if-then-elseなど)での最適化が行われる。インアクティブな要素をゼロ設定することで、異なるベクトルレジスタを使って制御フローのパスを分離する必要がある。 インアクティブな要素を残すことによって、明示的に2つの制御フローからの値をマージして1つのベクトル値を生成するという処理が不要となる。 テール要素を残すことによって、コードパタンを削減することに役に立つ。リダクションにおいて、最初のストリップマインループのイタレーションではベクトルの部分的な結果を管理し、最後にリダクションを行う。しかし最後のストリップでは厳密にハードウェアのベクトル長の倍数とはならない。 7. ISA設計の影響 ---------------- ベクトル命令は破壊的なFused Multiply-Add命令を持つために設計された。オペコードの領域を節約するために、破壊的なFused積和演算はソースオペランドを使用して破壊するレジスタの値を先に読みだす。マスクされたベクトルロードは古い値とマージを行うために余分なポートが必要になり、これが「値の変更なし」の要素をサポートするためにリネーミングを行うマシンの主たるコストとなる。 8. 議論 -------