AVX/AVX2による整数型から整数型への型変換

# はじめに
小さい型から大きい型へ整数型・整数型変換をします．
char型，unsigned char型，short型，unsigned short型，int型，unsigned int型から，short型，int型，long long型に変換します．

unsignedな型への変換はありません．
また，大きい型から小さい型への変換がないことに注意してください．
小さい型への変換は，AVX2では，packs，packusで行います．

下記変換はAVX-512をサポートするシステムでしか使用できません．

* 大きな整数から小さな整数への変換
* epuへの変換
* epi64/epu64からの変換（整数・double変換はepi32から）
 
## _mm256_cvtepi8|epu8_epi16|epi32|epi64 (AVX2)
```cpp
__m256i _mm256_cvtepi8_epi16 (__m128i a)
__m256i _mm256_cvtepu8_epi16 (__m128i a)
__m256i _mm256_cvtepi8_epi32 (__m128i a)
__m256i _mm256_cvtepu8_epi32 (__m128i a)
__m256i _mm256_cvtepi8_epi64 (__m128i a)
__m256i _mm256_cvtepu8_epi64 (__m128i a)
asm: vpmovsxbw ymm, xmm/m128 //epi8_epi16
asm: vpmovzxbw ymm, xmm/m128 //epu8_epi16
asm: vpmovsxbd ymm, xmm/m128 //epi8_epi32
asm: vpmovzxbd ymm, xmm/m128 //epu8_epi16
asm: vpmovsxbq ymm, xmm/m128 //epi8_epi64
asm: vpmovzxbq ymm, xmm/m128 //epu8_epi64
```

**動作**  
cvtepi8_epi16
![cvt_8_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/24ab81b0-8fb1-5ba4-43b1-fa005d2ac931.png)

cvtepi8_epi32
![cvt_8_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/394e1aa3-3009-3cbe-d2da-d337fabe0c61.png)

cvtepi8_epi64
![cvt_8_64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/f60865fb-bd25-721b-b620-023f30a02003.png)


**CPI/Uops**  

| Architecture | Latency | Throughput |Uops|
|--------------|:-------:|:----------:|:--:|
| Alderlake    |    1    |    0.5     |  - |
| Icelake      |    3    |     1      |  1 |
| Skylake      |    3    |     1      |  1 |
| Broadwell    |    3    |     1      |  1 |
| Haswell      |    3    |     1      |  1 |
| Zen3         |  4(≤9)  | 1.25(0.5)  |2(1)|
| Zen2         |  4(≤9)  | 1.15(0.5)  |2(1)|
| Zen          |    2    |     2      |  3 |

* 大きいサイズへの整数・整数型変換のパフォーマンスはすべて同じです．
* Intel CPUはAlderlakeで高速化しています．
* Zen2, Zen3の括弧付きはメモリからのロードを表し，メモリから__m128を読み込みながら変換する場合にスループットが倍になります．

**説明**  

* epi16: 16個の8ビット整数を16ビット整数に変換します．
* epi32: 下位8個の8ビット整数を32ビット整数に変換します．
* epi64: 下位4個の8ビット整数を64ビット整数に変換します．

epiは符号有り8bit，epuは符号無し8ビット整数を変換します．
変換先がepuになる変換は有りません．

## _mm256_cvtepi16|epu16_epi32|epi64 (AVX2)
```cpp
__m256i _mm256_cvtepi16_epi32 (__m128i a)
__m256i _mm256_cvtepu16_epi32 (__m128i a)
__m256i _mm256_cvtepi16_epi64 (__m128i a)
__m256i _mm256_cvtepu16_epi64 (__m128i a)
asm: vpmovsxwd ymm, xmm/m128 //epi16_epi32
asm: vpmovzxwd ymm, xmm/m128 //epu16_epi32
asm: vpmovsxwq ymm, xmm/m128 //epi16_epi64
asm: vpmovzxwq ymm, xmm/m128 //epu16_epi64
```

**動作**  
cvtepi16_epi32
![cvt_16_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/c027d41c-adb2-85cd-be1c-97b60079a9a7.png)

cvtepi16_epi64
![cvt_16_64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/ac487de6-cd60-1542-6dab-4cd624879ec2.png)

**CPI/Uops**  

| Architecture | Latency | Throughput |Uops|
|--------------|:-------:|:----------:|:--:|
| Alderlake    |    1    |    0.5     |  - |
| Icelake      |    3    |     1      |  1 |
| Skylake      |    3    |     1      |  1 |
| Broadwell    |    3    |     1      |  1 |
| Haswell      |    3    |     1      |  1 |
| Zen3         |  4(≤9)  | 1.25(0.5)  |2(1)|
| Zen2         |  4(≤9)  | 1.15(0.5)  |2(1)|
| Zen          |    2    |     2      |  3 |

* 大きいサイズへの整数・整数型変換のパフォーマンスはすべて同じです．
* Intel CPUはAlderlakeで高速化しています．
* Zen2, Zen3の括弧付きはメモリからのロードを表し，メモリから__m128を読み込みながら変換する場合にスループットが倍になります．


**説明**  

* epi32: 8個の16ビット整数を32ビット整数に変換します．
* epi64: 下位4個の16ビット整数を64ビット整数に変換します．

epiは符号有り16bit，epuは符号無し16ビット整数を変換します．
変換先がepuになる変換は有りません．

## _mm256_cvtepi32|epu32_epi64 (AVX2)
```cpp
__m256i _mm256_cvtepi32_epi64 (__m128i a)
__m256i _mm256_cvtepu32_epi64 (__m128i a)
asm: vpmovsxdq ymm, xmm/m128 //epi32_epi64
asm: vpmovzxdq ymm, xmm/m128 //epu32_epi64
```

**動作**  
cvtepi32_epi64
![cvt_32_64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/fc108b75-0946-1a74-19a1-2b9d3541cf2f.png)

**CPI/Uops**  

| Architecture | Latency | Throughput |Uops|
|--------------|:-------:|:----------:|:--:|
| Alderlake    |    1    |    0.5     |  - |
| Icelake      |    3    |     1      |  1 |
| Skylake      |    3    |     1      |  1 |
| Broadwell    |    3    |     1      |  1 |
| Haswell      |    3    |     1      |  1 |
| Zen3         |  4(≤9)  | 1.25(0.5)  |2(1)|
| Zen2         |  4(≤9)  | 1.15(0.5)  |2(1)|
| Zen          |    2    |     2      |  3 |

* 大きいサイズへの整数・整数型変換のパフォーマンスはすべて同じです．
* Intel CPUはAlderlakeで高速化しています．
* Zen2, Zen3の括弧付きはメモリからのロードを表し，メモリから__m128を読み込みながら変換する場合にスループットが倍になります．


**説明** 
4個の32ビット整数を64ビット整数に変換します．

epiは符号有り32bit，epuは符号無し32ビット整数を変換します．
変換先がepuになる変換は有りません．

## _mm256_cvtsi256_si32|si64 (AVX)
```cpp
//long long
__int64 _mm256_cvtsi128_si64 (__m256i a)
__int64 _mm_cvtsi128_si64 (__m128i a)
__int64 _mm_cvtsi128_si64x (__m128i a)
asm: movq r64/m32, xmm
//int
int _mm256_cvtsi256_si32 (__m256i a)
int _mm_cvtsi128_si32 (__m256i a)
asm: movd r32/m32, xmm
```

**動作**  
_mm256_cvtsi256_si64
![cvt_64_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/46efd299-c7ab-fc6f-c24c-5c9cf9558c26.png)

_mm256_cvtsi256_si32
![cvt_32_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67908/28b602da-19d1-28c2-20cc-47e63f423fa0.png)


**CPI/Uops**  

| Architecture | Latency | Throughput |Uops|
|--------------|:-------:|:----------:|:--:|
| Alderlake    |mem. dep.|    0.5     | -  |
| Icelake      | ≥3(11)  |    1(0.5)  |1(2)|
| Skylake      | ≥3(10)  |     1      |1(2)|
| Broadwell    | ≥1(9)   |     1      |1(2)|
| Haswell      | ≥1(9)   |     1      |1(2)|
| Ivy Bridge   | ≥1(9)   |     1      |1(2)|
| Sandy Bridge | ≥1(9)   |     1      |1(2)|
| Zen3         | ≥5(10)  |     1      |  1 |
| Zen2         | ≥5(9)   |     1      |  1 |
| Zen          | ≥5(8)   |     1      |  1 |

* 括弧付きはメモリへの書き出しの場合に変化した数値です．
* Icelakeはメモリへの書き出しスループットが倍です．

**説明**
下位32/64ビットの整数1つを，整数レジスタもしくはメモリにコピーします．
xmmレジスタに出力するわけではありません．
`_mm_cvtsi128_si64`はスカラ演算用の命令で，SSE2から使えます．

AVX命令である下記はSSE命令のマクロ展開でしかありません．

```cpp
int _mm256_cvtsi256_si32 (__m256i a)
asm: vmovd r32, xmm
#define _mm256_cvtsi256_si32(a) (_mm_cvtsi128_si32(_mm256_castsi256_si128(a)))
```

なお，Visual Studioだと下記命令もマクロ展開されていますが，公式には下記AVX命令はありません．

```cpp
#define _mm256_cvtsi256_si64(a) (_mm_cvtsi128_si64(_mm256_castsi256_si128(a)))
```

コンパイラは，SSE命令であるmovq，movdを，周囲の命令の状態に応じてAVX命令であるvmovq，vmovdへ置き換えてペナルティを回避します．