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を設定し、以下が成り立つ。 1. ``AVL ≤ VLMAX``\ である場合、\ ``vl = AVL``\ である。 2. ``AVL < (2 * VLMAX)``\ である場合、\ ``ceil(AVL / 2) ≦ vl ≦ VLMAX`` を設定する。 3. ``AVL ≥ (2 * VLMAX)``\ である場合、\ ``vl = VLMAX``\ を設定する。 4. AVLとVLMAXの値が同じならば、どのような実装でも同じ値が書き込まれる。 5. 以下の制約は、上記の設定に基づいて常に成立する。 1. ``AVL = 0``\ の場合\ ``vl = 0``\ が設定される。 2. ``AVL > 0``\ の場合、\ ``vl > 0``\ である。 3. ``vl ≤ VLMAX`` 4. ``vl ≤ AVL`` 5. ``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ビットのベクトルロードの方が高速である。