15. ベクトルリダクション操作

ベクトルリダクション操作はベクトルレジスタグループの要素と、ベクトルレジスタの要素0の値を持つスカラ値をオペランドに取り、バイナリ操作を行ってリダクション操作を行い、ベクトルレジスタの要素0に巣からの結果を返す命令である。スカラの入力値と出力オペランドはベクトルレジスタの要素0を使用し、ベクトルレジスタグループは使用しない。したがってLMULの設定にかかわらず、任意のベクトルレジスタはスカラのソースとベクトルリダクションの結果を受け取ることができる。

スカラオペランドとベクトルレジスタの要素0に結果を書き込むというリダクションの操作は、スカラプロセッサ側とのデータの受け渡しによる性能低下を避けるためのものであり、スカラユニットでサポートされていない将来の型で将来のポリモーフィック使用をサポートする(xxx: 意味不明)。

ソースベクトルレジスタグループのインアクティブな要素は演算対象から外されるが、スカラオペランドに関してはマスクに関係なく常に演算対象に含まれる。

書き込み先のベクトルレジスタの書き込み要素以外の要素(0 < index < VLEN/SEW)の値は変更されない。

vl=0であれば、演算は実行されず、ベクトルレジスタへの書き込みも発生しない。

ベクトルリダクションにおける例外発生時は、常にvstartが0であるものとして発生する。ベクトルリダクションにおいてvstartが0以外であった場合、不定命令例外が発生する。

アセンブラの表記においてリダクション操作はvredop.vsと表記し、サフィックスに.vsを付け、最初のオペランドがベクトルレジスタグループであり、2番目のオペランドがベクトルレジスタの要素0を含んだスカラ値であることを示している。

15.1. 単一ビット幅整数リダクション命令

全てのオペランドと結果は単一ビット幅であり、SEWと同一である。加算命令においてオーバフローが発生した場合は、値がラップアラウンドされる。

# 単純なリダクション命令, [*] はすべてのアクティブな要素を示している。
vredsum.vs  vd, vs2, vs1, vm   # vd[0] =  sum( vs1[0] , vs2[*] )
vredmaxu.vs vd, vs2, vs1, vm   # vd[0] = maxu( vs1[0] , vs2[*] )
vredmax.vs  vd, vs2, vs1, vm   # vd[0] =  max( vs1[0] , vs2[*] )
vredminu.vs vd, vs2, vs1, vm   # vd[0] = minu( vs1[0] , vs2[*] )
vredmin.vs  vd, vs2, vs1, vm   # vd[0] =  min( vs1[0] , vs2[*] )
vredand.vs  vd, vs2, vs1, vm   # vd[0] =  and( vs1[0] , vs2[*] )
vredor.vs   vd, vs2, vs1, vm   # vd[0] =   or( vs1[0] , vs2[*] )
vredxor.vs  vd, vs2, vs1, vm   # vd[0] =  xor( vs1[0] , vs2[*] )

15.2. ビット幅拡張整数リダクション命令

符号なしの vwredsumu.vs 命令はSEWサイズのベクトル要素をゼロ符号拡張し、2SEWの幅に拡張してから、2SEWの幅のスカラ要素と加算を行い、結果を2SEWビット幅の要素に書き込む。

vwredsum.vs 命令はSEWビット幅の要素を符号拡張してから加算する。

# 符号なしリダクション加算命令。結果を2倍のサイズのアキュムレータに書き込む。
vwredsumu.vs vd, vs2, vs1, vm   # 2*SEW = 2*SEW + sum(zero-extend(SEW))

# 符号付きリダクション加算命令。結果を2倍のサイズのアキュムレータに書き込む。
vwredsum.vs  vd, vs2, vs1, vm   # 2*SEW = 2*SEW + sum(sign-extend(SEW))

15.3. 単一ビット幅ベクトル浮動小数点リダクション加算命令

# 簡単なリダクション命令
vfredosum.vs vd, vs2, vs1, vm # Ordered sum
vfredsum.vs  vd, vs2, vs1, vm # Unordered sum
vfredmax.vs  vd, vs2, vs1, vm # Maximum value
vfredmin.vs  vd, vs2, vs1, vm # Minimum value

15.3.1. 単一ビット幅ベクトルオーダー付き浮動小数点加算命令

vfredosum 命令は浮動小数点のベクトル要素を順番に加算しなければならず、vs1[0]から始まり、以下のような計算を行う。(((vs1[0] + vs2[0]) + vs2[1]) + …) + vs2[vl-1]それぞれの加算はスカラの浮動小数点命令と同じように実行され、例外の動作も同一であり、特殊な値を生成したあともその値が伝搬していく。

順序付きのリダクション命令のサポートは、コンパイラにより自動ベクトル化をサポートするための命令であり、一方でアンオーダーな浮動小数点加算命令の方が高速な実装となる。

演算操作がマスクされた場合(vm=0)、マスクされた値は計算されず、例外も発生しない。

アクティブな要素が存在しない場合、加算操作は実行されず、スカラ値vs1[0]が単純に書き込みレジスタにコピーされる。この場合NaNの値が正規化されるが、例外フラグは設定されない。この動作はスカラの加算ループを自動ベクトル化した場合にNaNの処理、例外、丸め操作を行うための仕様である。

15.3.2. 単一ビット幅ベクトルアンオーダー浮動小数点リダクション加算命令

アンオーダーなリダクション加算命令vfredsumはリダクション操作においてより性能を出すための命令である。

実装では、2分木の操作のようにリダクション操作が構成され、入力のソースオペランドはベクトルレジスタグループ(vs2)とソーススカラ値(vs1[0])である。2分木における各演算は2つの入力値を受け取り、1つの結果を出力する。各演算は正確な加算操作として実行されるか、RISC-V IEEEスカラ浮動小数点の仕様に基づいて、現在のアクティブな浮動小数点丸めモードに基づいて実行される。1つの入力値しか持たない2分木のノードに関しては、SEWビット幅に相当するIEEE +0.0が加算されるか、単純に入力値が出力地にコピーされる。2分木の根になるノードにはSEWビット幅に相当するIEEEに準拠する結果が得られていなければならない。実装では、最終的な結果に対してさらにIEEE +0.0を加算することも許されている。

リダクションツリーの構造は与えられたvtypevlにおいて決定的でなければならない。

この定義の結果として、実装ではアクティブな要素が存在しない場合にはリダクションツリーにおいてNaNのペイロードを伝搬する必要がない。特に、すべての要素がアクティブでなく、スカラの入力がNaNであった場合、この値がSignaling NaNであった場合には実装ではNaNの値を正規化し、不正例外フラグを設定する。vfredosum命令のように、オリジナルのNaNの値をそのまま渡して、例外フラグを設定しないこともできる。
vfredosum命令はvfredsum命令の正確な実装である。

15.3.3. 単一ビット幅浮動小数点Max/Minリダクション命令

浮動小数点のMax/Minリダクション命令は演算の順番にかかわらず、常に同じ結果と同じ例外が発生する必要がある。

15.4. ビット幅拡張浮動小数点ベクトルリダクション命令

リダクション加算命令においてビット幅を拡張する命令が定義されており、2倍のサイズのリダクションの結果を読み書きする。

# 単純なリダクション命令
vfwredosum.vs vd, vs2, vs1, vm # オーダー付き加算
vfwredsum.vs vd, vs2, vs1, vm  # アンオーダー加算

SEWビット幅の要素はそのままのサイズでリダクションを実行し、2SEWビットのアキュムレータに加算する前にvs2は2SEWビットに拡張される。