というわけで何となく思いついたネタです。
ほかにも説明ページはあるかもしれませんが、自分で書いた記事にはそれなりには責任を持ちたいと思いますのでちょっと書いてみます。
過去記事でAdvanced Vector Extensionsで速くなる演算とは?というネタを書きましたが、これ自身は真実です。
つまり、「AVXで、整数演算を<行うこと>はできない」のであります。命令仕様書(Intelの資料番号319433より)からそう読み取れます。
が、うまいことをすれば「整数演算レベルでの演算」を続けるのであれば頭の体操的にx8の同時演算を使うことができます。
これの前提条件がこれです。
- AVXのfloat x8演算で使用されるfloatはIEEE754での単精度浮動小数形式である
- 浮動小数と整数の変換時間がそれほど大きくない
後者の条件は単純に変換数が多くなるとこれに手間取ることになるのでちょっと気にする要素です。
また、前者については演算器の勉強をした人ならわかると思いますが、float型の仮数部は23(+1)bitある、ということになります。
これにより、unsigned shortでの加減算レベルなら絶対に誤差は発生しません。乗除算が出てくると有効桁問題が出てきますが、ものによっては無視できることもあるのでそれをうまく使います。
(16bit x 8bitの最大桁は24bitなので、この乗算だけならfloatの仮数部にぎりぎりで入るため、誤差は発生しないといったことなど)
整数演算の例としてARGB各8bitx2pixelの描画ルーチンを考えるとこんな感じです。
- ARGB32bitx2 (8bitx8)をレジスタに転送
- unpack命令により16bit[int]x8 (128bit)に変換
- shuffle命令により16bit[int]x4 x2(a,b)に分割
- unpack命令により32bit[int]x4 x2(a,b)に変換
- vinsertf128命令により32bit[int]x4 (b)を32bit[int]x4 (a)の上位128bitに挿入して32bit[int]x8 (a)に変換
- vcvtdq2ps命令により32bit[int]x8を32bit[float]x8に変換
- いろんな描画動作
- vcvttps2dq命令により演算が完了した32bit[float]x8を32bit[int]x8に変換
- vextractf128命令により32bit[int]x8を32bit[int]x4 x2(a,b)に変換
- pack命令で8bitx8まで縮退
- メモリに書き戻す
・・・ymmレジスタ上で下位128bitのデータを上位128bitに渡す方法を調べるのに苦労しました・・・。
vinsertf128命令とvextractf128をペアにすることで実行可能なようです。この処理に持って行くまでのロスがどれくらいかがキーポイントですね。
描画自体はすでに浮動小数なのでαブレンドなどはお手の物でしょう。割り算とか考える必要ないですし。
これだと色がすでにすべてARGBの各チャネル32bitfloatで作った方がよっぽど楽な気がしてくるのは気のせいではないですね。
というわけで、ちょっとしたAVXと整数に関するネタでした。たぶん正しいと思いますが、勘違いがあるかもしれません。