RISC-Vのベクトル命令を実装する場合、まず考えなければならないのはVSETVL命令をどのように乗せるのかという点だ。VSETVL系統の命令はループのたびに高頻度で実行されるので、これを高速に動かす必要がある。
このため、RVV仕様におけるVL/VTYPEレジスタをリネームするというのは割と一般的に行われているようだ。 VL/VTYPEを複数持つことによって、可能な限りこれらのシステムレジスタを投機的に計算して保持し、ベクトル命令の計算を高速化する。
まず、この構成を考えた。VSETVL命令がデコードされると、この情報に基づいてすぐに新しいVL/VTYPE物理システムレジスタを割り当てる。 最初はこの割り当てのためにフリーリストが必要かも、と考えたが、よく考えたらいらない。デコード時に確保してコミット時に開放するので、インオーダでの割り当てで十分なのだ。また、1種類のレジスタを割り当てなおしているので、汎用レジスタのフリーリストのように複雑なことをする必要がない。
これに従って、簡単にVSETVLI命令自作CPUに実装して、動作を確認してみた。VSETVLI命令はシステムレジスタをたたくのでCSUパイプラインを使う。 CSUパイプラインは常にUncommitted Oldest状態にならなければ発行されない構成になっていたが、これも変更した。
#include <riscv_vector.h> #include <stddef.h> int main () { const int n = 100; size_t vl; for (int i = 0; i < n; i += vl) { vl = __riscv_vsetvl_e64m1(n - i); } for (int i = 0; i < n; i += vl) { vl = __riscv_vsetvl_e32m1(n - i); } for (int i = 0; i < n; i += vl) { vl = __riscv_vsetvl_e16m1(n - i); } for (int i = 0; i < n; i += vl) { vl = __riscv_vsetvl_e8m1(n - i); }
これくらいのループならばすぐに回せる。VSETVLIは3サイクルに1回アップデートすることが可能で、これで十分だろう。