6. コンフィグレーション設定命令¶
アプリケーションの要求に応じてvl
とvtype
を簡単に設定できるような命令群が定義されている。
6.1. vsetvli
/vsetvl
命令¶
vsetvli
命令は引数に基づいてvtype
とvl
CSRの値を設定し、新しいvl
の値をrd
に書き込む。
vsetvli rd, rs1, vtypei # rd = 新しいvlの値, rs1 = AVL, vtypei = 新しいvtypeの値
vsetvl rd, rs1, rs2 # rd = 新しいvlの値, rs1 = AVL, rs2 = 新しいvtypeの値
vtype
の新しい設定値はvsetvli
のフィールドの即値として設定され、vsetvl
命令の場合はrs2
レジスタで指定される。新しいベクトル長の設定はアプリケーションベクトル長(AVL)によって設定される。この値はrs1
とrd
フィールドの値によって次のようにしてエンコーディングされる。
Table 7. vsetvli
およびvsetvl
命令によって使用されるAVL値。
rd | rs1 | AVL値 | 説明・使用方法 |
---|---|---|---|
0 | 0 | vlレジスタ内の値 | vlの値を変更することなくvtypeが変更される。 |
!0 | 0 | ~0 | vlはVLMAXに設定される。 |
!0 | x[rs1] 内の値 |
通常のストリップマイニング |
rs1
がx0
でない場合、AVLはrs1
で指定された整数レジスタ内の符号なし整数であり、新しいvl
の値はrd
によって指定された整数レジスタに書き込まれる。
rs1=x0
かつrd!=0
の場合は、AVLの値は整数の最大サイズ(~0
)が使用される。結果としてvl
にはVLMAXが書き込まれ、rd
により指定された整数レジスタにも書き込みが行われる。
rs1=x0
およびrd=0
である場合、現在のベクトル長vl
がAVLとして使用される。結果の値はvl
にのみ書き込まれる。
この形式の命令はvl
を変更することなくvtype
レジスタを変更することを許している。VLMAXの値は減る事は無い。現在のvl
値はそのままvl
CSRから読み込まれる。
OP-Vメジャーオペコードを使用したベクトルコンフィグレーション命令のフォーマット。
31 30 25 24 20 19 15 14 12 11 7 6 0
0 | zimm[10:0] | rs1 | 1 1 1 | rd |1010111| vsetvli
1 | 000000 | rs2 | rs1 | 1 1 1 | rd |1010111| vsetvl
1 6 5 5 3 5 7
ビット | 名前 | 説明 |
---|---|---|
XLEN-1 | vill | 不正な値が設定されたことを示す。 |
XLEN-2:7 | 予約領域(0が書き込まれる) | |
6:5 | vediv[1:0] | EDIV拡張に使用される。 |
4:2 | vsew[2:0] | Standard element width (SEW) の設定。 |
1:0 | vlmul[1:0] | Vector register group multiplier (LMUL) の設定 |
vtypei設定に使用される値のアセンブラで使用される名前。
e8 # 8b elements
e16 # 16b elements
e32 # 32b elements
e64 # 64b elements
e128 # 128b elements
m1 # Vlmul x1, mの指定がない場合はこの値が使用される。
m2 # Vlmul x2
m4 # Vlmul x4
m8 # Vlmul x8
d1 # EDIV 1, dの指定がない場合はこの値が使用される。
d2 # EDIV 2
d4 # EDIV 4
d8 # EDIV 8
例:
vsetvli t0, a0, e8 # SEW= 8, LMUL=1, EDIV=1
vsetvli t0, a0, e8,m2 # SEW= 8, LMUL=2, EDIV=1
vsetvli t0, a0, e32,m2,d4 # SEW=32, LMUL=2, EDIV=4
vtype
の設定値が実装によってサポートされていない場合、vtype
レジスタ内のvill
ビットが設定され、それ以外のvtype
レジスタのビットフィールドはゼロが設定され、vl
レジスタの値もゼロに設定される。
初期の仕様ではvtype
に不正な値を設定すると例外が発生する仕様になっていた。ISAへのCSR書き込みに最初にデータ依存の例外を追加することになる。現在のスキームでは、特定の設定に対してvill
がクリアされているかどうかを確認することによってベクトルユニットの設定の問い合わせを軽量化する手法をサポートしている。
6.2. vl
への設定条件¶
The vsetvl{i}
instructions first set VLMAX according to the
vtype
argument, then set vl
obeying the following constraints:
vsetvl{i}
命令は、最初に引数のvtype
に基づいてVLMAXを設定し、以下が成り立つ。
AVL ≤ VLMAX
である場合、vl = AVL
である。AVL < (2 * VLMAX)
である場合、ceil(AVL / 2) ≦ vl ≦ VLMAX
を設定する。AVL ≥ (2 * VLMAX)
である場合、vl = VLMAX
を設定する。- AVLとVLMAXの値が同じならば、どのような実装でも同じ値が書き込まれる。
- 以下の制約は、上記の設定に基づいて常に成立する。
AVL = 0
の場合vl = 0
が設定される。AVL > 0
の場合、vl > 0
である。vl ≤ VLMAX
vl ≤ AVL
vsetvl {i}
のAVL引数として使用されたときにvl
から読み取られた値は、結果のVLMAXがvl
が読み取られた時点のVLMAXの値に等しい場合、vl
で同じ値になる。
vl
の設定制約は、AVL ≤ VLMAX
のレジスタスピルとコンテキストスワップ全体でvl
の動作を維持するのに十分に厳格でありながら、AVL > VLMAX
のベクターレーン使用率を実装できるように十分に柔軟に設計されている。例えば、これにより、実装がVLMAX < AVL < 2 * VLMAX
の場合にvl = ceil(AVL / 2)
を設定して、ストリップマインループの最後の2回の繰り返しで作業を均等に分散できる。 要件2は、リダクションループの最初のストリップマイン反復が、AVL < 2 * VLMAX
の場合でも、すべての反復の最大ベクトル長を使用することを保証する。 これにより、ソフトウェアはストリップループ中に観測されたベクトル長の最大値を明示的に計算する必要がなくなる。
6.3. vsetvl
命令¶
vsetvl
命令はvsetvli
命令と同様な動作をするが、vtype
の設定がrs2
レジスタの内容に基づいて設定されることが異なる。コンテキストのリストアに使用さたり、vtypei
の即値フィールドが所望の設定に対して小さすぎる場合に使用される。
いくつかのアクティブな複雑な型では、x
レジスタに異なる値を設定する必要があり、必要に応じてvsetvl
命令を使用してスワップする必要がある。
6.4. 例¶
SEWとLMULの設定値は、単一ループ中で動的に切り替えることが可能で、これによりデータ型の幅を混合させても高いスループットを達成することが可能となる。
# Example: 16ビットの値をロードし、32ビットの乗算を行い、その結果を3ビット右シフトし、32ビット値をストアする。
# 最大幅のエレメントのみ使用するループ。
loop:
vsetvli a3, a0, e32,m8 # 32-bitの要素のみ使用する。
vlh.v v8, (a1) # 16ビットの符号付ロード値を32ビットのレジスタ要素に格納する。
sll t1, a3, 1 # 2バイト分要素の幅を計算する。
add a1, a1, t1 # ポインタを進める。
vmul.vx v8, v8, x10 # 32bの乗算結果を得る。
vsrl.vi v8, v8, 3 # 要素をシフトする。
vsw.v v8, (a2) # 32ビットの値をストアする。
sll t1, a3, 2 # 4バイト分要素の幅を計算する。
add a2, a2, t1 # ポインタを進める。
sub a0, a0, a3 # カウンタをデクリメントする。
bnez a0, loop # 要素が残っているか?
# 要素の幅をスイッチするタイプのループ
loop:
vsetvli a3, a0, e16,m4 # `vtype`を16ビットの整数に設定する。
vlh.v v4, (a1) # 16ビットのデータをロードする。
slli t1, a3, 1 # 2バイト分要素の幅を計算する。
add a1, a1, t1 # ポインタを進める。
vwmul.vx v8, v4, x10 # v8-v15を使って、32ビットの乗算を実行する。
vsetvli x0, a0, e32,m8 # 32ビットのデータ幅に変更する。
vsrl.vi v8, v8, 3
vsw.v v8, (a2) # 32ビットの値をストアする。
slli t1, a3, 2 # 4バイト分要素の幅を計算する。
add a2, a2, t1 # ポインタを進める。
sub a0, a0, a3 # カウンタをデクリメントする。
bnez a0, loop # 要素が残っているか?
2番目のループの方がより複雑であるが、16ビット幅の乗算命令を使用することで32ビットの整数乗算よりも高速で、高い性能を得ることができる。また、ベクトルレジスタへの書き込み幅が小さいことで、16ビットのベクトルロードの方が高速である。