EVEX

(ModRM, REX, VEXについて知ってる前提で書いているので、知らない人は昔書いた http://d.hatena.ne.jp/w_o/20130126/1359183872 を読んでください)


これまで見て来たように、AVX-512では命令の追加以外にも色々強化されています。

- mask
- rounding
- broadcast
- 32 register

この情報は、AVX-512で追加された、EVEXプリフィクスに詰め込まれています。EVEXを見ると、AVX-512で強化された点がある程度推測できますね。


EVEXプリフィクスには、3byte、24bitの情報を詰め込めます。24bitの内訳は以下のとおり、

|名前                          | bit    |
|------------------------------|--------|
| compressed legacy escape(mm) | 2      |
| reserved(0)                  | 2      |
| R'                           | 1      |
| RXB (REXのRXB)               | 3      |
|                              |        |
| compressed legacy prefix(pp) | 2      |
| fixed(常に1)                 | 1      |
| vvvv                         | 4      |
| W (REXのW)                   | 1      |
|                              |        |
| aaa                          | 3      |
| V'                           | 1      |
| b                            | 1      |
| L'L                          | 2      |
| z                            | 1      |

真面目に全部書くとマニュアルのコピペになるので、そういうのはやめていくつか思い付く例を挙げていこうと思います。


### 256bit, 128bit演算

L'L と対応して 10 = 512bit, 01 = 256bit, 00 = 128bit となります。
L'L = 11 で 1024bit演算になって、AVX-1024とかになりそうですね。ただ、VEXが付いたとき、次は、m-mmmmを使うのかと思わせて、AVX-512ではm-mmmmは使わないでEVEXプリフィクスを新規に作ったので、油断しては(?)いけないと思います。


```nasm
	vaddps zmm31, zmm31, zmm31 ; L'L = 10
	vaddps ymm31, ymm31, ymm31 ; L'L = 01
	vaddps xmm31, xmm31, xmm31 ; L'L = 00
```
 (AVX512-VL拡張が必要です(「KNLでは動かない」の遠回しな表現))


### レジスタx2 + ModRMがレジスタ

オペランドが3つともレジスタの場合は、ModRM がメモリの場合に使う、X のビットが余っていますね。ModRMのoperandの5bit目はこれを使います。

```nasm
	vaddps zmm31, zmm0, zmm0 ; R' と R が 11
	vaddps zmm0, zmm31, zmm0 ; V' vvvv が 11111
	vaddps zmm0, zmm0, zmm31 ; B と X が 11
```

###レジスタx2 + ModRMがメモリ
汎用レジスタは16個しか無いので、ModRM がメモリの場合は、B,Xがあれば十分です。


あと disp8 の解釈が変わっています。disp8 のオフセットは、(disp8 * ベクタのサイズ) になります。つまり[rax+1] よりも、[rax+512] のほうが命令が短くなります。

```
00000000  62F17C4858800100  vaddps zmm0,zmm0,zword [rax+0x1]
         -0000
0000000A  62F17C48584008    vaddps zmm0,zmm0,zword [rax+0x200]
```

### mask
aaa で mask register を指定します。aaa = 0 の場合、マスク無し(=全bitが1)と解釈されます。これは、k0 = マスク無しという意味ではなくて、k0 の値を無視してマスク無しという意味です。korw などのマスク演算では、k0 の値を使うことができます(と書いてる気がする未確認)。

```
00000000  62F17C4F58C0      vaddps zmm0{k7},zmm0,zmm0  ; aaa = 7
00000006  62F17C4858C0      vaddps zmm0,zmm0,zmm0      ; aaa = 0
```


### z
{z} を付けた場合(マスクした値を0にする場合)z = 1になります。

```
00000000  62F17CCF58C0      vaddps zmm0{k7}{z},zmm0,zmm0 ; z = 1
```

### broadcast, embedded rounding

b = 1 でModRMがメモリだと、ブロードキャストになります。

b = 1 でModRMがレジスタだと、強制的に512bit演算になって、L'L の 2bitが空きます。この2bitでroundingを指定します(なので、128bit, 256bit演算では、embedded roundingは使えません)。また、浮動小数例外が無効になります(sae は Suppress All exceptionsの略です)。

(なんかndisasmバグってる気がするのでobjdump)

```
   0:   62 f1 7c 38 58 00       vaddps (%rax){1to8},%ymm0,%ymm0   # b = 1, L'L = 01
   6:   62 f1 7c 58 58 00       vaddps (%rax){1to16},%zmm0,%zmm0  # b = 1, L'L = 10
   c:   62 f1 7c 38 58 c0       vaddps {rd-sae},%zmm0,%zmm0,%zmm0 # b = 1, L'L = 01

   # vaddps zmm0, zmm0, zmm0{1to16}
   # vaddps zmm0, zmm0, [rax], {rd-sae}
   # vaddps ymm0, ymm0, ymm0, {rd-sae}
   # とか は書けない
```


### MVEXとの関連
~~62h は MVEX と衝突しているので MVEX とはお別れの時間が近付いてきたようです。~~ (追記 : コメント参照)

- EVEXのほうが強化されてる点 : 128bit, 256bit演算, rounding が付いてる, z
- MVEXのほうが良い点 : swizzle, non temporal


明日は@tanakmura が vrcp28pd について書きます。