Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

AVX-512(フォーマット)詳解

2,542 views

Published on

x86/x64最適化勉強会8

Published in: Technology

AVX-512(フォーマット)詳解

  1. 1. AVX-512(フォーマット)詳解 x86/x64最適化勉強会8 2018/2/17 光成滋生
  2. 2. • AVX-512の新機能概要 • AVX-512のフォーマット 概要 2 / 29
  3. 3. • 32個の512 bit SIMDレジスタ • zmm0, zmm1, ..., zmm31 • 一つのSIMDレジスタには整数や小数が複数入る • double(64bit) x 8, qword(64bit) x 8, float(32bit) x 16 • dword(32bit) x 16, word(16bit) x 32, byte(8bit) x 64など • 一部の整数は符号あり・符号無しを選択可能 • 下位256bitは従来のymmレジスタとしてアクセス可能 • その下位128bitは従来のxmmレジスタとしてアクセス可能 AVX-512 zmm0 ymm0 xmm0 63 31 15 0 3 / 29
  4. 4. • 整数系 ; vp<演算><要素の型> dst, src1, src2 • d(dword x 32)として要素ごとにzmm2 = zmm1 + zmm0 • q(qword x 16)として要素ごとにzmm2 = zmm1 – zmm0 • 浮動小数点数系 ; v<演算><要素の型> dst, src1, src2 • pd(double x 16)として要素ごとにzmm2 = zmm1 * zmm0 • ps(float x 32)として要素ごとにzmm2 = zmm1 / zmm0 基本演算の例 vpaddd zmm2, zmm1, zmm0 vpsubq zmm2, zmm1, zmm0 vmulpd zmm2, zmm1, zmm0 vdivps zmm2, zmm1, zmm0 4 / 29
  5. 5. • AVX512F(foundation) • blend, pcmp, ptest, compress等 • CD(Conflict Detection) • 競合検出 ループ処理での補助 • ER(Exponential and Reciprocal) • 指数と逆数 • PF(prefetch) • プリフェッチ • BW(byte, word), DQ(dword, qword) • VL(Vector length) • xmm, ymmレジスタ利用可能 演算グループ(1/2) 5 / 29
  6. 6. • VBMI(Vector byte Manipulation Instructions) • pcompress, pexpand, pshld, vpermi2bなど • IFMA(Integer Fused Multiply Add) • 52bit整数の積の上位/下位52bitを加算 • 4FMAPS (Fused Multiply Accumulation Packed Single Precision) • 16個のfloat[]の積和演算4個を1命令で • 4VNNIW(Vector Neural Network Instructions Word variable precision) • 4個のword[]の積和(結果はdword)16個を1命令で • GFNI(Galois Field系) • 標数2の8次拡大体の元のアフィン変換/逆変換を1命令で 演算グループ(2/2) 6 / 29
  7. 7. • 共通 • BAIC = AVX512{F, CD} • 主に浮動小数点数強化系 • Knights Landing = BASIC + AVX512{ER, PF} • Knights Mill = Knights Landing + AVX512_{4FMAPS, 4VNNIW} • 主に整数強化系 • Skylake = BASIC + AVX512{BW, DQ, VL} • Cannon Lake = Skylake + AVX512_{VBMI, IFMA} • Ice Lake = Cannon Lake + AVX512_{VBMI2, VNNI, GFNI, ... } 対応CPU 7 / 29
  8. 8. • SIMDは特定の要素の例外処理が面倒 • AVX2までのやり方 • vcmppdで要素ごとに(a[i] > 1.0) ? (-1) : 0のマスクMを生成 • M &= a[i] ; 要素ごとにa[i] or 0 • M *= b[i] ; 要素ごとにa[i] * b[i] or 0 • vblendvpd命令で要素ごとにa[i] * b[i]かb[i]を選択 SIMDの苦手なこと double *a, *b, *c; for (int i = 0; i < n; i++) { double x = b[i]; if (a[i] > 1.0) x *= a[i]; c[i] = x; } 8 / 29
  9. 9. • 要素ごとにマスク設定が可能になった • 64bitマスクレジスタk1, ..., k7 • k0もあるがマスク設定には使えない • 要素数だけマスクレジスタの下位bitが参照される • 8byte x 64なら64bit, 32byte x 16なら16bit • マスクレジスタの扱い • 該当bitが1 ; 該当要素の処理が行われる • 該当bitが0 • ゼロ化マスクなし • 操作は行われない(例外や違反は発生しない) • ゼロ化マスクあり • 0で埋められる AVX-512におけるマスク処理 9 / 29
  10. 10. • vmovdqu8(byte単位のレジスタコピー) • k1レジスタのビットが立っているところだけコピー マスクの例 [Xf Xe Xd Xc Xb Xa X9 X8 X7 X6 X5 X4 X3 X2 X1 X0]xmm0 [Yf Ye Yd Yc Yb Ya Y9 Y8 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0]xmm1 [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0]k1 [Yf Ye Yd Yc Yb Ya Y9 Y8 Y7 Y6 Y5 X4 Y3 Y2 X1 Y0]xmm1 vmovdqu8 xmm1{k1}, xmm0 10 / 29
  11. 11. • vmovdqu8(byte単位のレジスタコピー) • k1レジスタのビットが立っているところだけコピー • それ以外は0クリア ゼロ化マスクの例 [Xf Xe Xd Xc Xb Xa X9 X8 X7 X6 X5 X4 X3 X2 X1 X0]xmm0 [Yf Ye Yd Yc Yb Ya Y9 Y8 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0]xmm1 [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0]k1 [00 00 00 00 00 00 00 00 00 00 00 X4 00 00 X1 00]xmm1 vmovdqu8 xmm1{k1}{z}, xmm0 11 / 29
  12. 12. • 再掲 • AVX-512のマスクレジスタを利用 先程のサンプルの例 double *a, *b, *c; for (int i = 0; i < n; i++) { double x = b[i]; if (a[i] > 1.0) x *= a[i]; c[i] = x; } // zmm2 = [1.0 ... 1.0]を設定しておく vmovups zmm0, [a] ; double x 16読み vmovups zmm1, [b] vcmppd k1, zmm2, zmm0, 1 ; k1=[(zmm2 < zmm0) ? 1 : 0] vmulpd zmm1{k1}, zmm0, zmm1 ; a[i] > 1のところだけ乗算 vmovups [c], zmm1 12 / 29
  13. 13. • マスクのコスト • ロードでブレンド操作が行われるため少し低速 • デスティネーション(以下dstと略記)との依存関係が発生 • ゼロ化マスクではこの依存関係は切れる • 可能な限りゼロ化マスクを使う • メモリへの書き込みはマージmaskのみ • 書き込みアドレスが書き込み禁止領域にまたがっていても マスクレジスタでマスクされていると例外は発生しない マスクレジスタの注意点 +0 +1 +2 +3 +4 +5 +6 +7 +8|+9 +a +b +c +d +e +f [yy yy yy yy yy yy yy yy yy|xx xx xx xx xx xx xx] 書き込み禁止領域書き込み可能領域 k1 = (1 << 9) – 1のとき 13 / 29
  14. 14. • 複数の条件のandやorを効率よく計算するために マスクレジスタの演算命令が追加されている • k<演算>{b,w,d,q} dst, src1, src2の形 • add, and, or, not, xor • andn(x, y) := ~(x & y) • xnor(x, y) := ~(x ^ y) • shiftl, shiftrなど • ZF, CF制御系 • kortest{b,w,d,q} src1, src2 • (src1 | src2) == 0ならZF = 1 • (src1 | src2) == ~0ならCF = 1 • vcomiss x, yよりvcomiss k, x, y; kortest k, kの方が速いらしい マスクレジスタの演算 14 / 29
  15. 15. • マスクレジスタが立っているところだけ集める データ圧縮 [Xf Xe Xd Xc Xb Xa X9 X8 X7 X6 X5 X4 X3 X2 X1 X0]xmm0 [ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0]k1 [00 00 00 00 00 00 00 00 00 00 00 00 00 00 X4 X1]xmm1 vcompresspd xmm1{k1}, xmm0 15 / 29
  16. 16. • a[]が正のところだけb[]につめていく データ圧縮の例 assert(n % 16 == 0); uint32_t a[n]; uint32_t b[n]; j = 0; for (int i = 0; i < n; i++) { if (a[i] > 0) { b[j++] = a[i]; } } 16 / 29
  17. 17. • メイン部分 AVX-512によるデータ圧縮 // rsi = a, rdi = b, zmm0 = rax = rdx = 0 .lp: vmovdqa32 zmm1, [rsi + rax * 4] ; zmm1 = a[] vpcmpgtd k1, zmm1, zmm0 ; k1 = [(a > 0)?1:0] vpcompressd zmm2{k1}, zmm1 ; zmm2 = comp(a[]) vmovdqu32 [rdi + rdx * 4], zmm2 ; b[] = zmm2 kmovd ecx, k1 popcnt rcx, rcx ; コピーした個数だけ add rdx, rcx ; bのポインタを増やす add rax, 16 ; aは16ずつ増やす cmp rax, n jne .lp 17 / 29
  18. 18. • マスクレジスタが立っているところに下から入れる データ展開 [Xf Xe Xd Xc Xb Xa X9 X8 X7 X6 X5 X4 X3 X2 X1 X0]xmm0 [ 0 0 0 1 0 0 0 0 0 1 0 1 0 0 1 0]k1 [00 00 00 X3 00 00 00 00 00 X2 00 X1 00 00 X0 00]xmm1 vcompresspd xmm1{k1}{z}, xmm0 18 / 29
  19. 19. • 32 or 64bitの値をSIMDレジスタに複数個コピー • 従来 • AVX-512 • 外に{1to8}, {1to4}など • レジスタ種別(xmm/ymm/zmm)と データの型(float/double)で{1toX}のXは一意に決まる • Xbyakではptr_b[rax]と書けるようにした ブロードキャストフラグ vbroadcastss zmm0, [rax] ; [rax]のfloat1個を16個コピー vmulps zmm2, zmm1, zmm0 vmulps zmm2, zmm1, [rax]{1to16} 19 / 29
  20. 20. • 従来 • 浮動小数点数の演算結果の丸め方はMXCSRレジスタに依存 • MXCSRの変更はコストが大きい • round系は小数→小数のみ, cvtt系は小数→整数の切り捨てのみ • AVX-512 • ほとんどの命令毎に丸め方を指定可能 • rne(round to nearest even) ; 最も近い偶数 • rd(round down) ; 切り下げ • ru(round up) ; 切り上げ • rz(round toward zero) ; ゼロへの丸め • 同時に例外抑制SAE(suppress all exceptions)も行われる 組み込み丸め操作 vcvtsd2si eax,xmm0,{rz-sae} ;小数→整数のゼロへの丸め 20 / 29
  21. 21. • 1bitが3個の入力x, y, zに対して1bitのwを出力する関数f • f(x, y, z) = w ; fは8bit定数imm8を一つ決めると決まる • vpternlog x, y, z, imm8 ; x = f(x, y, z) imm8=e8h • 例)SHA関数の中のf(a, b, c) = ((a | b) & c) | (a & b)や f(a, b, c) = a ^ (b ^ (c ^ a))はvpternlog1命令にできる 3値論理(ternary logic) x y z w 0 0 0 0 0 0 1 0 0 1 0 0 0 1 1 1 1 0 0 0 1 0 1 1 1 1 0 1 1 1 1 1 21 / 29
  22. 22. • ModR/M • mov dst, src / mov dst, [src] / mov dst, [src + disp] などの1byteエンコーディング規則 • mod • 00 ; dst, [src] • 01 ; dst, [src + disp8](8bitオフセット) • 10 ; dst, [src + disp32](32bitオフセット) • 11 ; dst, src • reg • 8種類のレジスタを3bitで指定 • r/m • srcのレジスタを指定 IA-32のフォーマット復習(1/2) [ 7 6| 5 4 3| 2 1 0] [ mod | reg | r/m ] 22 / 29
  23. 23. • SIB(Scale Index Byte) • mov eax, [ecx + edx * 4 + disp]などのエンコーディング規則 • [base + index * scale + disp] • base • レジスタ種別 • index • レジスタ種別 • scale • 1, 2, 4, 8倍をそれぞれ00, 01, 10, 11で表現 IA-32のフォーマット復習(2/2) [ 7 6| 5 4 3| 2 1 0] [scale| index | base ] 23 / 29
  24. 24. • modR/M + SIB • ~32bit, レジスタ8個 • REXプレフィクス(1byte) • inc/dec reg16を廃止して利用 • 64bit, レジスタ16個対応 • VEXプレフィクス(2-3byte, Vector Extension) • les, ldsの隙間を利用 • 3オペランド, 256bitレジスタ対応 • デコーダの負担を低減 • EVEXプレフィクス(4byte, Enhanced VEX) • 64bitモードで廃止されていたbound(0x62)始まり • 512bit, レジスタ32個対応 • マスクレジスタ、丸めモード、ブロードキャストなど エンコーディングの歴史 24 / 29
  25. 25. • テスト • mmとppは従来のVEXプレフィクス関係 • zはゼロ化フラグ, L’Lはレジスタ長や丸めモード EVEX | EVEX | |62 P0 P1 P2| opcode ModRM/M [SIB] [Disp] [Imm] | 7 6 5 4 3 2 1 0 | P0 | R | X | B | R'| 0 | 0 | m | m | P1 | W | v | v | v | v | 1 | p | p | P2 | z | L'| L | b | V'| a | a | a | vaddpd a4a3a2a1a0,{k_aaa},b4b3b2b1b0,c4c3c2c1c0 | P0 | P1 | P2 | 62|!a3 !c4 !c3 !a4 0001|1 b3 b2 b1 b0 101|0100 !b4 aaa| | ModRM/M | <opcode> |11 a2 a1 a0 c2 c1 c0| [SIB] [Disp] 25 / 29
  26. 26. • メモリアクセスのディスプレースメント(disp)は 符号つき8bit以内なら1byte, それ以外は4byte必要 • AVX-512ではzmm1個で64byteなので2個分のオフセッ ト(128)でオーバーする • これはデコーダに辛い • 通常ループアンロールなどで使うのは0x40, 0x80, 0xc0など 64byteの倍数のはず • オフセットがN(=64など)の倍数なら圧縮disp8を使う変更 圧縮disp8*N(1/2) mov rax, [rax + 0x7f] ; 48 8B 40 7F ; disp8 mov rax, [rax + 0x80] ; 48 8B 80 80 00 00 00 ; disp32 vaddpd zmm0, zmm1, [rax] ;62F1F5485800 6byte vaddpd zmm0, zmm1, [rax+0x80];62F1F548588080000000 10byte 26 / 29
  27. 27. • 命令長が7byteに収まる • その代わり[rax+1]などはdisp8でなくdisp32で表現 • 余談 • 命令毎にdisp8*NのNの値のパターンが異なる • Tuple TypeはInputSizeにより変わるのでややこしい 圧縮disp8*N(2/2) vaddpd zmm0, zmm1, [rax+64] ; 62F1F548584001 vaddpd zmm0, zmm1, [rax+128]; 62F1F548584002 vaddpd zmm0, zmm1, [rax+192]; 62F1F548584003 vaddpd zmm0, zmm1, [rax+256]; 62F1F548584004 vaddpd zmm0, zmm1, [rax+1] ; 62F1F548588001000000 27 / 29
  28. 28. • v4fmaddps zmm1, zmm<base>, [mem] • zmm<base>, ..., zmm<base+3>とfloat mem[4]の積和を zmm1に加算(baseは4の倍数) • zmm4を指定すればzmm4, zmm5, zmm6, zmm7が参照される • 擬似コード • デコーダの負担を減らすため? v4fmaddps(Knights Mill以降) v4fmaddps(zmm dest, zmm[base], float mem[4]) { floatX16 tmp = dest; for (j = 0; j < 4; j++) { for (i = 0; i < 16; i++) { tmp[i] += zmm[base + j][i] * msrc[j]; } dest = tmp; } } 28 / 29
  29. 29. • Intelのマニュアル&エミュレータ(SDE) • https://software.intel.com/en-us/articles/intel-sdm • https://software.intel.com/en-us/articles/intel-software- development-emulator • software developer‘s manual(325383-065US)の間違い • p.1312のVSQRTPD xmm1 {k1}{z}, xmm2/m128/m32bcst などはm64bcstの間違い • Optimization Reference Manual(248966-039)の間違い • p.540のvmovaps zmm1{k1}{z}, zmm0の結果の図がおかしい • p.552の図15.5 Data Expand Operationがおかしい • @tanakmuraさんのAVX-512 Advent Calendar 2014 • https://qiita.com/advent-calendar/2014/avx512 参考文献 29 / 29

×