vsetvli命令を投機的に実行する場合を考える。
デフォルト状態:
- head_ptr
: 現在のvlvtypeレジスタが、投機的にどこまでエントリを確保しているかを意味する。デフォルト値は0。
- tail_ptr
: 現在のvlvtypeレジスタの投機実行が、どこまでコミットされているのかを示す。デフォルト値は0。
vsetvli命令がディスパッチされるたびにhead_ptr
をインクリメントし、現在処理を行っているvsetvliを取得する。
例えばhead_ptr=0でvsetvliがディスパッチされると、vsetvli命令以降のベクトル命令はインデックス=0のvlvtypeレジスタの情報を参照するものとする。この時、vlvtype_valid[index=0]=1
とし、現在このインデックスは使用中であることを示す。
- vlvtype_validのassert条件:新たにvsetvli命令がディスパッチされる
- vlvtype_validのdeassert条件:次に新しいvsetvli命令がコミットされる
vsetvli
命令がCSU内で実行されてVL値が確定するたびに、そのインデックスの情報テーブルがアップデートされ、そのテーブルはすでに取得可能であることを示す。これは、vlvtype_ready[index=0]=1
とし、このvlvtype情報はすでに確定済みであることを命令に知らせる。
- vlvtype_readyのassert条件:当該vsetvli命令の実行が完了し、vl/vtype値が確定する
vlvtype_readyのdeassert条件:vlvtype_validのdeassert条件と同じ
vlvtype投機実行エントリがFull状態の場合:つまり、vsetvli命令が非常に投機的に実行されており、どのvsetvli命令も確定状態ではない場合は、それ以降のvsetvli命令の発行を中止する。これは
vlvtype_valid[*]=1
である状態を示している。
このとき、投機実行ミスや例外が発生するとどうなるか。
vsetvli (0) vadd.vv (0) bne vsetvli (1) vadd.vv (1)
ここで、最初のvsetvli(0)がディスパッチされて、直近のvadd.vvがvlvtype[0]の情報をもとに動作するものとし、vsetvli(1)は投機的にディスパッチされて直近のvadd.vvはvlvtype[1]の情報をもとに動作するものとする。
この時点で、上記のhead_ptrは2まで進んでいるものする。
bne
が投機実行ミスを発生させた場合:vsetvli(0)およびvadd.vv(0)に動作の影響を及ぼすものではない。したがって、通常通りvsetvli(0)は動作しコミットにより確定する。
一方で、vsetvli(1)
は一応動作し確定し、vadd.vvも確定するが、これは動作に影響を与えるものではなく、ROBから削除されるのと同じタイミングポインタは進んでいく。
この時、bne
によりやり直しが始まった新たなvsetvli(2)は、head_ptr=2から新たにエントリを確保してもよい。
tail_ptr
はROBから削除される際に必ず進むので、矛盾が発生することはない。
ということは、この順番を守っている限りは、命令の投機実行ミスなどをあまり考える必要はないというとか。
以下の問題も同様で、ld
により例外が発生したとしても、ROBから正しく抜けてポインタを進めることができるのであれば、特に矛盾は発生しないということか。
vsetvli (0) vadd.vv (0) ld vsetvli (1) vadd.vv (1)