RISC-V Vector Extensionでは、ベクトルレジスタの演算対象となる要素をマスクによって制御できる。
Intrinsic においてこのマスクを使用するためには、 Intrinsicの関数の最後に _m を付けるのが基本だ。
vint64m1_t __riscv_vadd_vv_i64m1 (vint64m1_t op1, vint64m1_t op2, size_t vl); // マスク付きバージョン vint64m1_t __riscv_vadd_vv_i64m1_m (vbool64_t mask, vint64m1_t op1, vint64m1_t op2, size_t vl);
ここで注意すべき点は、マスクには複数の種類が存在することである。
- Tail: 有効なベクトル長よりも先のベクトル部分を指す。必要なベクトル長よりもベクトルレジスタが長い場合、その余剰部分がTailとなる。
- Mask: ベクトルレジスタ内で演算に不要な部分を省略するためのマスクである。
演算に不要な要素をどのように扱うかによって、2種類のモードが定義されている。
- Undisturbed: 演算に不要な要素は、元のレジスタの値を保持する。
- Agnostic: 演算に不要な要素は、元のレジスタの値を保持するか、もしくは-1(0xfffff...)で埋める。
Agnosticモードが存在する理由は、UndisturbedモードではOoO(アウト・オブ・オーダー)実装時にリネームが発生すると、元のレジスタ値の参照が必要となり、レジスタ・リード・ポートが余分に必要になるためである。
これらを厳密に制御するため、RISC-VのVector Intrinsicではいくつかの関数が用意されている(デフォルトはAgnosticであり、Undisturbedを利用する場合は明示的に切り替える必要がある)。
- Tail=Agnostic / Mask=Agnostic:
_m
vint64m1_t __riscv_vadd_vv_i64m1_m (vbool64_t mask, vint64m1_t op1, vint64m1_t op2, size_t vl);
- Tail=Agnostic / Mask=Undisturbed:
_mu
vint64m1_t __riscv_vadd_vv_i64m1_mu (vbool64_t mask, vint64m1_t vd, vint64m1_t op1, vint64m1_t op2, size_t vl);
- Tail=Undisturbed / Mask=Agnostic:
_tum
vint64m1_t __riscv_vadd_vv_i64m1_tmu (vbool64_t mask, vint64m1_t vd, vint64m1_t op1, vint64m1_t op2, size_t vl);
- Tail=Undisturbed / Mask=Undisturbed:
_tumu
vint64m1_t __riscv_vadd_vv_i64m1_tumu (vbool64_t mask, vint64m1_t op1, vint64m1_t op2, size_t vl);
また、Maskを適用せずにTail=Undisturbedとなるバージョンも存在する。
vint64m1_t __riscv_vadd_vv_i64m1_tu (vint64m1_t vd, vint64m1_t op1, vint64m1_t op2, size_t vl);
詳細については、以下の資料を参照されたい。