Obsah
1. Rozšíření instrukční sady AVX-512 na platformě x86–64 (dokončení)
2. Datové typy používané v GCC s podporou AVX-512
3. Intrinsic definované v GCC pro instrukční sady AVX-512
4. Základ AVX-512: AVX-512F (foundation)
5. Maskovací registry k0 až k7
6. Operace prováděné přímo s maskovacími registry
7. Intrinsic pro operace prováděné přímo s maskovacími registry
8. Instrukce, v nichž se využívají nové maskovací registry
9. Instrinsic pro instrukce vblendmps a addps s maskou
11. Instrukce pro kompresi a expanzi dat
12. Instrinsic pro instrukce komprese dat
13. Instrukce pro provedení permutace (přerozdělení) prvků vektorů
14. Intrinsic pro provedení permutace
16. Rozšíření Vector Neural Network Instructions (VNNI)
17. Příloha – soubor Makefile použitý v článcích o SIMD operacích
18. Repositář s demonstračními příklady
19. Seznam všech předchozích částí tohoto seriálu
1. Rozšíření instrukční sady AVX-512 na platformě x86–64 (dokončení)
Na předchozí článek s úvodními informacemi o AVX-512 na platformě x86–64 dnes navážeme. Víme již, že sada AVX-512 by přinesla do návrhu a výroby čipů tak rozsáhlou změnu, že je celá nová sada instrukcí rozdělena do několika podmnožin, přičemž zdaleka na všechny mikroprocesory musí podporovat všechny podmnožiny. To má zajímavý důsledek – počet (teoretických) možných kombinací podporuje/nepodporuje je obrovský. Podívejme se na názvy jednotlivých podmnožin společně s informacemi o tom, ve kterém jádru byla daná podmnožina AVX-512 poprvé implementována:
Množina instrukcí | Plné jméno | První procesor s implementací |
---|---|---|
F | AVX-512 Foundation | Xeon Phi x200 (Knights Landing), Xeon Gold/Platinum |
CD | AVX-512 Conflict Detection Instructions | Xeon Phi x200 (Knights Landing), Xeon Gold/Platinum |
ER | AVX-512 Exponential and Reciprocal Instructions | Xeon Phi x200 (Knights Landing) |
PF | AVX-512 Prefetch Instructions | Xeon Phi x200 (Knights Landing) |
VL | AVX-512 Vector Length Extensions | Skylake X, Cannon Lake |
DQ | AVX-512 Doubleword and Quadword Instructions | Skylake X, Cannon Lake |
BW | AVX-512 Byte and Word Instructions | Skylake X, Cannon Lake |
IFMA | AVX-512 Integer Fused Multiply Add | Cannon Lake |
VBMI | AVX-512 Vector Byte Manipulation Instructions | Cannon Lake |
4VNNIW | AVX-512 Vector Neural Network Instructions Word variable precision | Knights Mill |
4FMAPS | AVX-512 Fused Multiply Accumulation Packed Single precision | Knights Mill |
VPOPCNTDQ | Vector population count instruction | Knights Mill, Ice Lake |
VNNI | AVX-512 Vector Neural Network Instructions | Ice Lake |
VBMI2 | AVX-512 Vector Byte Manipulation Instructions 2 | Ice Lake |
BITALG | AVX-512 Bit Algorithms | Ice Lake |
VP2INTERSECT | AVX-512 Vector Pair Intersection to a Pair of Mask Registers | Tiger Lake |
Z pohledu programátora je nejdůležitější hned první podmnožina nazvaná AVX-512 Foundation, což je zkracováno na AVX-512F. Značná část dnešního článku je věnována právě této podmnožině, protože ta přináší dvě důležité změny: rozšíření počtu i bitové šířky vektorových registrů ZMMx a taktéž zavedení maskovacích registrů k0 až k7, které lze využít v mnoha nových instrukcích. Taktéž bylo změněno kódování instrukcí, to je však již pro běžného programátora (většinou) poměrně nepodstatná informace.
2. Datové typy používané v GCC s podporou AVX-512
Vzhledem k tomu, že si dnes ukážeme i několik demonstračních příkladů založených na intrinsic nabízených překladačem GCC C, je nutné znát i datové typy, s nimiž se bude pracovat. Jedná se o vektory s šířkou 512 bitů (64 bajtů), které obsahují buď celočíselné prvky (pochopitelně volitelné šířky) nebo prvky s hodnotami reprezentovanými v systému plovoucí řádové čárky. V mnoha demonstračních příkladech konkrétně použijeme typ __v16sf, tedy vektor se šestnácti prvky typu single/float:
# | Typ prvku | Počet prvků | Celkový počet bitů | Definice datového typu |
---|---|---|---|---|
1 | double | 8 | 512 | typedef double __v8df __attribute__ ((__vector_size__ (64))); |
2 | float | 16 | 512 | typedef float __v16sf __attribute__ ((__vector_size__ (64))); |
3 | long long | 8 | 512 | typedef long long __v8di __attribute__ ((__vector_size__ (64))); |
4 | unsigned long long | 8 | 512 | typedef unsigned long long __v8du __attribute__ ((__vector_size__ (64))); |
5 | int | 16 | 512 | typedef int __v16si __attribute__ ((__vector_size__ (64))); |
6 | unsigned int | 16 | 512 | typedef unsigned int __v16su __attribute__ ((__vector_size__ (64))); |
7 | short | 32 | 512 | typedef short __v32hi __attribute__ ((__vector_size__ (64))); |
8 | unsigned short | 32 | 512 | typedef unsigned short __v32hu __attribute__ ((__vector_size__ (64))); |
9 | char | 64 | 512 | typedef char __v64qi __attribute__ ((__vector_size__ (64))); |
10 | unsigned char | 64 | 512 | typedef unsigned char __v64qu __attribute__ ((__vector_size__ (64))); |
Dále se ještě poměrně často setkáme s následujícími aliasy:
typedef long long __m512i __attribute__ ((__vector_size__ (64), __may_alias__)); typedef float __m512 __attribute__ ((__vector_size__ (64), __may_alias__)); typedef double __m512d __attribute__ ((__vector_size__ (64), __may_alias__));
3. Intrinsic definované v GCC pro instrukční sady AVX-512
Víme již, že překladač GCC C podporuje přes intrinsic (vestavěné pseudofunkce) všechna dříve popsaná rozšíření instrukční sady x86(-64) se SIMD operacemi. Jedná se o intrinsic pro MMX, SSE, SSE2 i AVX (a vlastně i 3DNow!, které jsme vynechali, protože bylo záhy nahrazeno za SSE). To stejné platí i pro AVX-512; konkrétně jsou nabízeny intrinsic vypsané pod tímto odstavcem (pozor na to, že tato jména nejsou zcela kompatibilní s překladačem firmy Intel!). Taktéž si povšimněte toho, že mnoho instrinsic má v názvu slovo mask, což znamená, že se používají maskovací registry:
__builtin_ia32_addpd512_mask __builtin_ia32_addps512_mask __builtin_ia32_addsd_mask_round __builtin_ia32_addsd_round __builtin_ia32_addss_mask_round __builtin_ia32_addss_round __builtin_ia32_alignd512_mask __builtin_ia32_alignq512_mask __builtin_ia32_blendmd_512_mask __builtin_ia32_blendmpd_512_mask __builtin_ia32_blendmps_512_mask __builtin_ia32_blendmq_512_mask __builtin_ia32_broadcastf32x4_512 __builtin_ia32_broadcastf64x4_512 __builtin_ia32_broadcasti32x4_512 __builtin_ia32_broadcasti64x4_512 __builtin_ia32_broadcastsd512 __builtin_ia32_broadcastss512 __builtin_ia32_cmpd512_mask __builtin_ia32_cmppd512_mask __builtin_ia32_cmpps512_mask __builtin_ia32_cmpq512_mask __builtin_ia32_cmpsd_mask __builtin_ia32_cmpss_mask __builtin_ia32_compressdf512_mask __builtin_ia32_compressdi512_mask __builtin_ia32_compresssf512_mask __builtin_ia32_compresssi512_mask __builtin_ia32_compressstoredf512_mask __builtin_ia32_compressstoredi512_mask __builtin_ia32_compressstoresf512_mask __builtin_ia32_compressstoresi512_mask __builtin_ia32_cvtdq2pd512_mask __builtin_ia32_cvtdq2ps512_mask __builtin_ia32_cvtpd2dq512_mask __builtin_ia32_cvtpd2ps512_mask __builtin_ia32_cvtpd2udq512_mask __builtin_ia32_cvtps2dq512_mask __builtin_ia32_cvtps2pd512_mask __builtin_ia32_cvtps2udq512_mask __builtin_ia32_cvtsd2ss_round __builtin_ia32_cvtsi2sd64 __builtin_ia32_cvtsi2ss32 __builtin_ia32_cvtsi2ss64 __builtin_ia32_cvtss2sd_round __builtin_ia32_cvttpd2dq512_mask __builtin_ia32_cvttpd2udq512_mask __builtin_ia32_cvttps2dq512_mask __builtin_ia32_cvttps2udq512_mask __builtin_ia32_cvtudq2pd512_mask __builtin_ia32_cvtudq2ps512_mask __builtin_ia32_cvtusi2sd32 __builtin_ia32_cvtusi2sd64 __builtin_ia32_cvtusi2ss32 __builtin_ia32_cvtusi2ss64 __builtin_ia32_divpd512_mask __builtin_ia32_divps512_mask __builtin_ia32_divsd_mask_round __builtin_ia32_divsd_round __builtin_ia32_divss_mask_round __builtin_ia32_divss_round __builtin_ia32_expanddf512_mask __builtin_ia32_expanddf512_maskz __builtin_ia32_expanddi512_mask __builtin_ia32_expanddi512_maskz __builtin_ia32_expandloaddf512_mask __builtin_ia32_expandloaddf512_maskz __builtin_ia32_expandloaddi512_mask __builtin_ia32_expandloaddi512_maskz __builtin_ia32_expandloadsf512_mask __builtin_ia32_expandloadsf512_maskz __builtin_ia32_expandloadsi512_mask __builtin_ia32_expandloadsi512_maskz __builtin_ia32_expandsf512_mask __builtin_ia32_expandsf512_maskz __builtin_ia32_expandsi512_mask __builtin_ia32_expandsi512_maskz __builtin_ia32_extractf32x4_mask __builtin_ia32_extractf64x4_mask __builtin_ia32_extracti32x4_mask __builtin_ia32_extracti64x4_mask __builtin_ia32_fixupimmpd512_mask __builtin_ia32_fixupimmpd512_maskz __builtin_ia32_fixupimmps512_mask __builtin_ia32_fixupimmps512_maskz __builtin_ia32_fixupimmsd_mask __builtin_ia32_fixupimmsd_maskz __builtin_ia32_fixupimmss_mask __builtin_ia32_fixupimmss_maskz __builtin_ia32_gatherdiv16sf __builtin_ia32_gatherdiv16si __builtin_ia32_gatherdiv8df __builtin_ia32_gatherdiv8di __builtin_ia32_gathersiv16sf __builtin_ia32_gathersiv16si __builtin_ia32_gathersiv8df __builtin_ia32_gathersiv8di __builtin_ia32_getexppd512_mask __builtin_ia32_getexpps512_mask __builtin_ia32_getexpsd128_round __builtin_ia32_getexpsd_mask_round __builtin_ia32_getexpss128_round __builtin_ia32_getexpss_mask_round __builtin_ia32_getmantpd512_mask __builtin_ia32_getmantps512_mask __builtin_ia32_getmantsd_mask_round __builtin_ia32_getmantsd_round __builtin_ia32_getmantss_mask_round __builtin_ia32_getmantss_round __builtin_ia32_insertf32x4_mask __builtin_ia32_insertf64x4_mask __builtin_ia32_inserti32x4_mask __builtin_ia32_inserti64x4_mask __builtin_ia32_kandhi __builtin_ia32_kandnhi __builtin_ia32_kmovw __builtin_ia32_knothi __builtin_ia32_korhi __builtin_ia32_kortestchi __builtin_ia32_kortestzhi __builtin_ia32_kshiftlihi __builtin_ia32_kshiftrihi __builtin_ia32_kunpckhi __builtin_ia32_kxnorhi __builtin_ia32_kxorhi __builtin_ia32_loadapd512_mask __builtin_ia32_loadaps512_mask __builtin_ia32_loaddqudi512_mask __builtin_ia32_loaddqusi512_mask __builtin_ia32_loadsd_mask __builtin_ia32_loadss_mask __builtin_ia32_loadupd512_mask __builtin_ia32_loadups512_mask __builtin_ia32_maxpd512_mask __builtin_ia32_maxps512_mask __builtin_ia32_maxsd_mask_round __builtin_ia32_maxsd_round __builtin_ia32_maxss_mask_round __builtin_ia32_maxss_round __builtin_ia32_minpd512_mask __builtin_ia32_minps512_mask __builtin_ia32_minsd_mask_round __builtin_ia32_minsd_round __builtin_ia32_minss_mask_round __builtin_ia32_minss_round __builtin_ia32_movapd512_mask __builtin_ia32_movaps512_mask __builtin_ia32_movddup512_mask __builtin_ia32_movdqa32_512_mask __builtin_ia32_movdqa32load512_mask __builtin_ia32_movdqa32store512_mask __builtin_ia32_movdqa64_512_mask __builtin_ia32_movdqa64load512_mask __builtin_ia32_movdqa64store512_mask __builtin_ia32_movesd_mask __builtin_ia32_movess_mask __builtin_ia32_movntdq512 __builtin_ia32_movntdqa512 __builtin_ia32_movntpd512 __builtin_ia32_movntps512 __builtin_ia32_movshdup512_mask __builtin_ia32_movsldup512_mask __builtin_ia32_mulpd512_mask __builtin_ia32_mulps512_mask __builtin_ia32_mulsd_mask_round __builtin_ia32_mulsd_round __builtin_ia32_mulss_mask_round __builtin_ia32_mulss_round __builtin_ia32_pabsd512_mask __builtin_ia32_pabsq512_mask __builtin_ia32_paddd512_mask __builtin_ia32_paddq512_mask __builtin_ia32_pandd512_mask __builtin_ia32_pandnd512_mask __builtin_ia32_pandnq512_mask __builtin_ia32_pandq512_mask __builtin_ia32_pbroadcastd512 __builtin_ia32_pbroadcastd512_gpr_mask __builtin_ia32_pbroadcastq512 __builtin_ia32_pbroadcastq512_gpr_mask __builtin_ia32_pcmpeqd512_mask __builtin_ia32_pcmpeqq512_mask __builtin_ia32_pcmpgtd512_mask __builtin_ia32_pcmpgtq512_mask __builtin_ia32_pd512_256pd __builtin_ia32_pd512_pd __builtin_ia32_permdf512_mask __builtin_ia32_permdi512_mask __builtin_ia32_permvardf512_mask __builtin_ia32_permvardi512_mask __builtin_ia32_permvarsf512_mask __builtin_ia32_permvarsi512_mask __builtin_ia32_pmaxsd512_mask __builtin_ia32_pmaxsq512_mask __builtin_ia32_pmaxud512_mask __builtin_ia32_pmaxuq512_mask __builtin_ia32_pminsd512_mask __builtin_ia32_pminsq512_mask __builtin_ia32_pminud512_mask __builtin_ia32_pminuq512_mask __builtin_ia32_pmovdb512_mask __builtin_ia32_pmovdb512mem_mask __builtin_ia32_pmovdw512_mask __builtin_ia32_pmovdw512mem_mask __builtin_ia32_pmovqb512_mask __builtin_ia32_pmovqb512mem_mask __builtin_ia32_pmovqd512_mask __builtin_ia32_pmovqd512mem_mask __builtin_ia32_pmovqw512_mask __builtin_ia32_pmovqw512mem_mask __builtin_ia32_pmovsdb512_mask __builtin_ia32_pmovsdb512mem_mask __builtin_ia32_pmovsdw512_mask __builtin_ia32_pmovsdw512mem_mask __builtin_ia32_pmovsqb512_mask __builtin_ia32_pmovsqb512mem_mask __builtin_ia32_pmovsqd512_mask __builtin_ia32_pmovsqd512mem_mask __builtin_ia32_pmovsqw512_mask __builtin_ia32_pmovsqw512mem_mask __builtin_ia32_pmovsxbd512_mask __builtin_ia32_pmovsxbq512_mask __builtin_ia32_pmovsxdq512_mask __builtin_ia32_pmovsxwd512_mask __builtin_ia32_pmovsxwq512_mask __builtin_ia32_pmovusdb512_mask __builtin_ia32_pmovusdb512mem_mask __builtin_ia32_pmovusdw512_mask __builtin_ia32_pmovusdw512mem_mask __builtin_ia32_pmovusqb512_mask __builtin_ia32_pmovusqb512mem_mask __builtin_ia32_pmovusqd512_mask __builtin_ia32_pmovusqd512mem_mask __builtin_ia32_pmovusqw512_mask __builtin_ia32_pmovusqw512mem_mask __builtin_ia32_pmovzxbd512_mask __builtin_ia32_pmovzxbq512_mask __builtin_ia32_pmovzxdq512_mask __builtin_ia32_pmovzxwd512_mask __builtin_ia32_pmovzxwq512_mask __builtin_ia32_pmuldq512_mask __builtin_ia32_pmulld512_mask __builtin_ia32_pmuludq512_mask __builtin_ia32_pord512_mask __builtin_ia32_porq512_mask __builtin_ia32_prold512_mask __builtin_ia32_prolq512_mask __builtin_ia32_prolvd512_mask __builtin_ia32_prolvq512_mask __builtin_ia32_prord512_mask __builtin_ia32_prorq512_mask __builtin_ia32_prorvd512_mask __builtin_ia32_prorvq512_mask __builtin_ia32_ps512_256ps __builtin_ia32_ps512_ps __builtin_ia32_pshufd512_mask __builtin_ia32_pslld512_mask __builtin_ia32_pslldi512_mask __builtin_ia32_psllq512_mask __builtin_ia32_psllqi512_mask __builtin_ia32_psllv16si_mask __builtin_ia32_psllv8di_mask __builtin_ia32_psrad512_mask __builtin_ia32_psradi512_mask __builtin_ia32_psraq512_mask __builtin_ia32_psraqi512_mask __builtin_ia32_psrav16si_mask __builtin_ia32_psrav8di_mask __builtin_ia32_psrld512_mask __builtin_ia32_psrldi512_mask __builtin_ia32_psrlq512_mask __builtin_ia32_psrlqi512_mask __builtin_ia32_psrlv16si_mask __builtin_ia32_psrlv8di_mask __builtin_ia32_psubd512_mask __builtin_ia32_psubq512_mask __builtin_ia32_pternlogd512_mask __builtin_ia32_pternlogd512_maskz __builtin_ia32_pternlogq512_mask __builtin_ia32_pternlogq512_maskz __builtin_ia32_ptestmd512 __builtin_ia32_ptestmq512 __builtin_ia32_ptestnmd512 __builtin_ia32_ptestnmq512 __builtin_ia32_punpckhdq512_mask __builtin_ia32_punpckhqdq512_mask __builtin_ia32_punpckldq512_mask __builtin_ia32_punpcklqdq512_mask __builtin_ia32_pxord512_mask __builtin_ia32_pxorq512_mask __builtin_ia32_rcp14pd512_mask __builtin_ia32_rcp14ps512_mask __builtin_ia32_rcp14sd __builtin_ia32_rcp14sd_mask __builtin_ia32_rcp14ss __builtin_ia32_rcp14ss_mask __builtin_ia32_rndscalepd_mask __builtin_ia32_rndscaleps_mask __builtin_ia32_rndscalesd_round __builtin_ia32_rndscaless_round __builtin_ia32_rsqrt14pd512_mask __builtin_ia32_rsqrt14ps512_mask __builtin_ia32_rsqrt14sd __builtin_ia32_rsqrt14sd_mask __builtin_ia32_rsqrt14ss __builtin_ia32_rsqrt14ss_mask __builtin_ia32_scalefpd512_mask __builtin_ia32_scalefps512_mask __builtin_ia32_scalefsd_mask_round __builtin_ia32_scalefss_mask_round __builtin_ia32_scatterdiv16sf __builtin_ia32_scatterdiv16si __builtin_ia32_scatterdiv8df __builtin_ia32_scatterdiv8di __builtin_ia32_scattersiv16sf __builtin_ia32_scattersiv16si __builtin_ia32_scattersiv8df __builtin_ia32_scattersiv8di __builtin_ia32_shuf_f32x4_mask __builtin_ia32_shuf_f64x2_mask __builtin_ia32_shuf_i32x4_mask __builtin_ia32_shuf_i64x2_mask __builtin_ia32_shufpd512_mask __builtin_ia32_shufps512_mask __builtin_ia32_si512_256si __builtin_ia32_si512_si __builtin_ia32_sqrtpd512_mask __builtin_ia32_sqrtps512_mask __builtin_ia32_sqrtsd_mask_round __builtin_ia32_sqrtss_mask_round __builtin_ia32_storeapd512_mask __builtin_ia32_storeaps512_mask __builtin_ia32_storedqudi512_mask __builtin_ia32_storedqusi512_mask __builtin_ia32_storesd_mask __builtin_ia32_storess_mask __builtin_ia32_storeupd512_mask __builtin_ia32_storeups512_mask __builtin_ia32_subpd512_mask __builtin_ia32_subps512_mask __builtin_ia32_subsd_mask_round __builtin_ia32_subsd_round __builtin_ia32_subss_mask_round __builtin_ia32_subss_round __builtin_ia32_ucmpd512_mask __builtin_ia32_ucmpq512_mask __builtin_ia32_unpckhpd512_mask __builtin_ia32_unpckhps512_mask __builtin_ia32_unpcklpd512_mask __builtin_ia32_unpcklps512_mask __builtin_ia32_vcomisd __builtin_ia32_vcomiss __builtin_ia32_vcvtph2ps512_mask __builtin_ia32_vcvtps2ph512_mask __builtin_ia32_vcvtsd2si32 __builtin_ia32_vcvtsd2si64 __builtin_ia32_vcvtsd2usi32 __builtin_ia32_vcvtsd2usi64 __builtin_ia32_vcvtss2si32 __builtin_ia32_vcvtss2si64 __builtin_ia32_vcvtss2usi32 __builtin_ia32_vcvtss2usi64 __builtin_ia32_vcvttsd2si32 __builtin_ia32_vcvttsd2si64 __builtin_ia32_vcvttsd2usi32 __builtin_ia32_vcvttsd2usi64 __builtin_ia32_vcvttss2si32 __builtin_ia32_vcvttss2si64 __builtin_ia32_vcvttss2usi32 __builtin_ia32_vcvttss2usi64 __builtin_ia32_vfmaddpd512_mask __builtin_ia32_vfmaddpd512_mask3 __builtin_ia32_vfmaddpd512_maskz __builtin_ia32_vfmaddps512_mask __builtin_ia32_vfmaddps512_mask3 __builtin_ia32_vfmaddps512_maskz __builtin_ia32_vfmaddsd3_mask __builtin_ia32_vfmaddsd3_mask3 __builtin_ia32_vfmaddsd3_maskz __builtin_ia32_vfmaddsd3_round __builtin_ia32_vfmaddss3_mask __builtin_ia32_vfmaddss3_mask3 __builtin_ia32_vfmaddss3_maskz __builtin_ia32_vfmaddss3_round __builtin_ia32_vfmaddsubpd512_mask __builtin_ia32_vfmaddsubpd512_mask3 __builtin_ia32_vfmaddsubpd512_maskz __builtin_ia32_vfmaddsubps512_mask __builtin_ia32_vfmaddsubps512_mask3 __builtin_ia32_vfmaddsubps512_maskz __builtin_ia32_vfmsubaddpd512_mask3 __builtin_ia32_vfmsubaddps512_mask3 __builtin_ia32_vfmsubpd512_mask __builtin_ia32_vfmsubpd512_mask3 __builtin_ia32_vfmsubpd512_maskz __builtin_ia32_vfmsubps512_mask __builtin_ia32_vfmsubps512_mask3 __builtin_ia32_vfmsubps512_maskz __builtin_ia32_vfmsubsd3_mask3 __builtin_ia32_vfmsubss3_mask3 __builtin_ia32_vfnmaddpd512_mask __builtin_ia32_vfnmaddpd512_mask3 __builtin_ia32_vfnmaddpd512_maskz __builtin_ia32_vfnmaddps512_mask __builtin_ia32_vfnmaddps512_mask3 __builtin_ia32_vfnmaddps512_maskz __builtin_ia32_vfnmsubpd512_mask __builtin_ia32_vfnmsubpd512_mask3 __builtin_ia32_vfnmsubpd512_maskz __builtin_ia32_vfnmsubps512_mask __builtin_ia32_vfnmsubps512_mask3 __builtin_ia32_vfnmsubps512_maskz __builtin_ia32_vpermi2vard512_mask __builtin_ia32_vpermi2varpd512_mask __builtin_ia32_vpermi2varps512_mask __builtin_ia32_vpermi2varq512_mask __builtin_ia32_vpermilpd512_mask __builtin_ia32_vpermilps512_mask __builtin_ia32_vpermilvarpd512_mask __builtin_ia32_vpermilvarps512_mask __builtin_ia32_vpermt2vard512_mask __builtin_ia32_vpermt2vard512_maskz __builtin_ia32_vpermt2varpd512_mask __builtin_ia32_vpermt2varpd512_maskz __builtin_ia32_vpermt2varps512_mask __builtin_ia32_vpermt2varps512_maskz __builtin_ia32_vpermt2varq512_mask __builtin_ia32_vpermt2varq512_maskz
4. Základ AVX-512: AVX-512F (foundation)
Všechny mikroprocesory, které podporují nějaké podmnožiny AVX-512 musí v každém případě podporovat minimálně podmnožinu označovanou AVX-512F, kde F je odvozeno od slova foundation. Jedná se o základní sadu, která rozšiřuje většinu instrukcí z původního AVX takovým způsobem, že se namísto vektorů o délce 256 bitů pracuje s vektory o délce 512 bitů. Taktéž se změnila, resp. rozšířila sémantika mnohých instrukcí díky zavedení maskovacích registrů k0 až k7, z nichž každý má v AVX-512F šířku šestnácti bitů. Významem těchto registrů se budeme zabývat v páté kapitole i v kapitolách navazujících. A nesmíme zapomenout na to, že se (opět!, pokolikáté už?) změnilo kódování instrukcí. Nové kódování se jmenuje EVEX, což je zkratka z označení Enhanced Vector Extension. Díky EVEX je možné pracovat s 32 SIMD registry, specifikovat již zmíněné maskovací registry, provádět takzvaný broadcasting atd.
5. Maskovací registry k0 až k7
Novinkou v AVX-512F jsou maskovací registry k0 až k7. Jedná se o šestnáctibitové registry, teprve později (konkrétně v AVX-512BW) došlo k jejich rozšíření na 64 bitů. Jednotlivé bity v těchto registrech slouží jako maska, například pro operace součtu, nebo tyto bity slouží k rozhodování, zda bude operace provedena s prvkem prvního vstupního vektoru nebo naopak s prvkem získaným z vektoru druhého. Původně mnohdy čistě vektorové operace prováděné se všemi prvky vektorů se tak „rozpadají“ na podmíněné operace, přičemž podmínky jsou zakódovány do bitů zvoleného maskovacího registru. Maskovací registry ovšem mohou sloužit naopak i pro uložení výsledků nějakých operací – například porovnání prvků ze dvou vstupních registrů atd. A konečně, vzhledem k tomu, že se jedná o šestnáctibitové hodnoty, lze s maskovacími registry provádět některé bitové operace, bitové posuny atd.
6. Operace prováděné přímo s maskovacími registry
V případě, že se zaměříme „pouze“ na rozšíření AVX-512F, lze říci, že všechny maskovací registry obsahují šestnáctibitové hodnoty (masky), které lze využít v instrukcích popsaných v navazující kapitole. V instrukční sadě nalezneme i několik instrukcí, které se používají přímo pro manipulaci s obsahem maskovacích registrů, a to prakticky stejně, jakoby se jednalo o běžné šestnáctibitové celočíselné registry. Jedná se o tyto operace:
provedení bitové operace OR se dvěma maskovacími registry# | Instrukce | Stručný popis instrukce |
---|---|---|
1 | KMOV | načtení konstanty do maskovacího registru nebo převod hodnot mezi dvojicí registrů |
2 | KNOT | negace obsahu zvoleného maskovacího registru |
3 | KAND | provedení bitové operace AND se dvěma maskovacími registry |
4 | KANDN | provedení bitové operace AND NOT se dvěma maskovacími registry |
5 | KOR | |
6 | KXOR | provedení bitové operace XOR se dvěma maskovacími registry |
7 | KXNOR | provedení bitové operace XNOR se dvěma maskovacími registry |
8 | KORTEST | operace OR s nastavením příznaků Zero (všechny bity nulové) a Carry (všechny bity výsledku jedničkové) |
9 | KSHIFTL | bitový posun doleva o n bitů |
10 | KSHIFTR | bitový posun doprava o n bitů |
11 | KUNPCK | kombinace spodní poloviny dvou maskovacích registrů do registru cílového |
7. Intrinsic pro operace prováděné přímo s maskovacími registry
Vyzkoušejme si nyní ty intrinsic, které lze v GCC použít pro instrukce popsané v rámci předchozí kapitoly. Provedeme několik bitových operací s maskovacími registry:
#include <stdio.h> #include <immintrin.h> int main(void) { short unsigned int x = 2; short unsigned int y = 3; short unsigned int z; z = __builtin_ia32_kandhi(x, y); printf("and: %d\n", z); z = __builtin_ia32_kandnhi(x, y); printf("and not: %d\n", z); z = __builtin_ia32_korhi(x, y); printf("or: %d\n", z); z = __builtin_ia32_kxorhi(x, y); printf("xor: %d\n", z); z = __builtin_ia32_kxnorhi(x, y); printf("xnor: %d\n", z); return 0; }
Po překladu (s přepínačem -mavx512f) a spuštění by se měla vypsat tato pětice řádků:
and: 2 and not: 1 or: 3 xor: 1 xnor: 65534
Z objektového kódu a disassemblovaného výstupu je patrné, že nové instrukce pro manipulaci s maskovacími registry jsou zakódovány do pouhých čtyř bajtů, což je na platformě x86–64 skoro zázrak:
z = __builtin_ia32_kandhi(x, y); 18: 0f b7 45 fc movzx eax,WORD PTR [rbp-0x4] 1c: 0f b7 55 fa movzx edx,WORD PTR [rbp-0x6] 20: c5 f8 92 ca kmovw k1,edx 24: c5 f8 92 d0 kmovw k2,eax 28: c5 f4 41 c2 kandw k0,k1,k2 2c: c5 f8 91 45 fe kmovw WORD PTR [rbp-0x2],k0 z = __builtin_ia32_kandnhi(x, y); 48: 0f b7 45 fc movzx eax,WORD PTR [rbp-0x4] 4c: 0f b7 55 fa movzx edx,WORD PTR [rbp-0x6] 50: c5 f8 92 da kmovw k3,edx 54: c5 f8 92 e0 kmovw k4,eax 58: c5 e4 42 c4 kandnw k0,k3,k4 5c: c5 f8 91 45 fe kmovw WORD PTR [rbp-0x2],k0 z = __builtin_ia32_korhi(x, y); 78: 0f b7 45 fc movzx eax,WORD PTR [rbp-0x4] 7c: 0f b7 55 fa movzx edx,WORD PTR [rbp-0x6] 80: c5 f8 92 ea kmovw k5,edx 84: c5 f8 92 f0 kmovw k6,eax 88: c5 d4 45 c6 korw k0,k5,k6 8c: c5 f8 91 45 fe kmovw WORD PTR [rbp-0x2],k0 z = __builtin_ia32_kxorhi(x, y); a8: 0f b7 45 fc movzx eax,WORD PTR [rbp-0x4] ac: 0f b7 55 fa movzx edx,WORD PTR [rbp-0x6] b0: c5 f8 92 fa kmovw k7,edx b4: c5 f8 92 c8 kmovw k1,eax b8: c5 c4 47 c1 kxorw k0,k7,k1 bc: c5 f8 91 45 fe kmovw WORD PTR [rbp-0x2],k0 z = __builtin_ia32_kxnorhi(x, y); d8: 0f b7 45 fc movzx eax,WORD PTR [rbp-0x4] dc: 0f b7 55 fa movzx edx,WORD PTR [rbp-0x6] e0: c5 f8 92 d2 kmovw k2,edx e4: c5 f8 92 d8 kmovw k3,eax e8: c5 ec 46 c3 kxnorw k0,k2,k3 ec: c5 f8 91 45 fe kmovw WORD PTR [rbp-0x2],k0
8. Instrukce, v nichž se využívají nové maskovací registry
V instrukční sadě AVX-512F se nachází poměrně velké množství instrukcí, v nichž se využívají nové maskovací registry popsané v rámci předchozích dvou kapitol. Tyto nové či upravené instrukce můžeme rozdělit do několika kategorií.
Smíchání obsahu dvou registrů, tj. výběr, jak se vyberou prvky do cílového registru na základě bitové masky:
Instrukce | Stručný popis instrukce |
---|---|
VBLENDMPD | smíchání obsahu dvou registrů s prvky typu double |
VBLENDMPS | smíchání obsahu dvou registrů s prvky typu single/float |
VPBLENDMD | smíchání obsahu dvou registrů s prvky typu int32 |
VPBLENDMQ | smíchání obsahu dvou registrů s prvky typu int64 |
Porovnání obsahu dvou registrů vybranou operací (EQ, LT, LE atd.), přičemž výsledek je uložen do maskovacího registru:
Instrukce | Stručný popis instrukce |
---|---|
VPCMPD | porovnání obsahu dvou registrů s prvky typu int32 s nastavením příznaků v maskovacím registru |
VPCMPUD | porovnání obsahu dvou registrů s prvky typu uint32 s nastavením příznaků v maskovacím registru |
VPCMPQ | porovnání obsahu dvou registrů s prvky typu int64 s nastavením příznaků v maskovacím registru |
VPCMPUQ | porovnání obsahu dvou registrů s prvky typu uint64 s nastavením příznaků v maskovacím registru |
Provedení logické operace AND nebo NAND nad registry, výsledek (0 nebo 1) se uloží do zvoleného maskovacího registru:
Instrukce | Stručný popis instrukce |
---|---|
VPTESTMD | logická operace AND pro vektor s 32bitovými celými čísly |
VPTESTMQ | logická operace AND pro vektor s 64bitovými celými čísly |
VPTESTNMD | logická operace NAND pro vektor s 32bitovými celými čísly |
VPTESTNMQ | logická operace NAND pro vektor s 64bitovými celými čísly |
9. Instrinsic pro instrukce vblendmps a addps s maskou
Podívejme se nyní na způsob použití některých instrukcí, v nichž se využívají maskovací registry resp. bitová maska. Nejdříve si ukážeme intrinsic nazvaný __builtin_ia32_blendmps512_mask, která implementuje instrukci typu vblendmps. Připomeňme si, že tato instrukce promíchá prvky dvou vektorů, přičemž každý vektor obsahuje šestnáct hodnot typu single/float. Promíchání se děje na základě obsahu maskovacího registru – pokud n-tý bit tohoto registru obsahuje logickou nulu, bude n-tý prvek výsledného vektoru získán z vektoru prvního, v opačném případě z vektoru druhého:
#include <stdio.h> #include <immintrin.h> int main(void) { __v16sf x = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 }; __v16sf y = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6 }; __v16sf z; int i; z = __builtin_ia32_blendmps_512_mask(x, y, 0x0000); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_blendmps_512_mask(x, y, 0x1111); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_blendmps_512_mask(x, y, 0x5555); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_blendmps_512_mask(x, y, 0xffff); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } return 0; }
Výsledky získané po překladu a spuštění tohoto příkladu ukazují, jak fungují jednotlivé šestnáctibitové masky:
0 1.000000 0.100000 1.000000 1 2.000000 0.200000 2.000000 2 3.000000 0.300000 3.000000 3 4.000000 0.400000 4.000000 4 5.000000 0.500000 5.000000 5 6.000000 0.600000 6.000000 6 7.000000 0.700000 7.000000 7 8.000000 0.800000 8.000000 8 9.000000 0.900000 9.000000 9 10.000000 1.100000 10.000000 10 11.000000 1.100000 11.000000 11 12.000000 1.200000 12.000000 12 13.000000 1.300000 13.000000 13 14.000000 1.400000 14.000000 14 15.000000 1.500000 15.000000 15 16.000000 1.600000 16.000000 0 1.000000 0.100000 0.100000 1 2.000000 0.200000 2.000000 2 3.000000 0.300000 3.000000 3 4.000000 0.400000 4.000000 4 5.000000 0.500000 0.500000 5 6.000000 0.600000 6.000000 6 7.000000 0.700000 7.000000 7 8.000000 0.800000 8.000000 8 9.000000 0.900000 0.900000 9 10.000000 1.100000 10.000000 10 11.000000 1.100000 11.000000 11 12.000000 1.200000 12.000000 12 13.000000 1.300000 1.300000 13 14.000000 1.400000 14.000000 14 15.000000 1.500000 15.000000 15 16.000000 1.600000 16.000000 0 1.000000 0.100000 0.100000 1 2.000000 0.200000 2.000000 2 3.000000 0.300000 0.300000 3 4.000000 0.400000 4.000000 4 5.000000 0.500000 0.500000 5 6.000000 0.600000 6.000000 6 7.000000 0.700000 0.700000 7 8.000000 0.800000 8.000000 8 9.000000 0.900000 0.900000 9 10.000000 1.100000 10.000000 10 11.000000 1.100000 1.100000 11 12.000000 1.200000 12.000000 12 13.000000 1.300000 1.300000 13 14.000000 1.400000 14.000000 14 15.000000 1.500000 1.500000 15 16.000000 1.600000 16.000000 0 1.000000 0.100000 0.100000 1 2.000000 0.200000 0.200000 2 3.000000 0.300000 0.300000 3 4.000000 0.400000 0.400000 4 5.000000 0.500000 0.500000 5 6.000000 0.600000 0.600000 6 7.000000 0.700000 0.700000 7 8.000000 0.800000 0.800000 8 9.000000 0.900000 0.900000 9 10.000000 1.100000 1.100000 10 11.000000 1.100000 1.100000 11 12.000000 1.200000 1.200000 12 13.000000 1.300000 1.300000 13 14.000000 1.400000 1.400000 14 15.000000 1.500000 1.500000 15 16.000000 1.600000 1.600000
Způsob překladu výše uvedené intrinsic do objektového kódu a do assembleru (nenechte se zmýlit odlišným jménem instrukce v GNU toolchainu):
z = __builtin_ia32_blendmps_512_mask(x, y, 0x0000); 55: 62 f1 7c 48 28 8d 10 vmovaps zmm1,ZMMWORD PTR [rbp-0xf0] 5c: ff ff ff 5f: 62 f1 7c 48 28 85 d0 vmovaps zmm0,ZMMWORD PTR [rbp-0x130] 66: fe ff ff 69: c5 f4 47 c9 kxorw k1,k1,k1 6d: 62 f1 7c 49 28 c1 vmovaps zmm0{k1},zmm1 73: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 7a: ff ff ff z = __builtin_ia32_blendmps_512_mask(x, y, 0x1111); fd: 62 f1 7c 48 28 8d 10 vmovaps zmm1,ZMMWORD PTR [rbp-0xf0] 104: ff ff ff 107: 62 f1 7c 48 28 85 d0 vmovaps zmm0,ZMMWORD PTR [rbp-0x130] 10e: fe ff ff 111: b8 11 11 00 00 mov eax,0x1111 116: c5 f8 92 d0 kmovw k2,eax 11a: 62 f1 7c 4a 28 c1 vmovaps zmm0{k2},zmm1 120: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 127: ff ff ff z = __builtin_ia32_blendmps_512_mask(x, y, 0x5555); 1aa: 62 f1 7c 48 28 8d 10 vmovaps zmm1,ZMMWORD PTR [rbp-0xf0] 1b1: ff ff ff 1b4: 62 f1 7c 48 28 85 d0 vmovaps zmm0,ZMMWORD PTR [rbp-0x130] 1bb: fe ff ff 1be: b8 55 55 00 00 mov eax,0x5555 1c3: c5 f8 92 d8 kmovw k3,eax 1c7: 62 f1 7c 4b 28 c1 vmovaps zmm0{k3},zmm1 1cd: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 1d4: ff ff ff z = __builtin_ia32_blendmps_512_mask(x, y, 0xffff); 257: 62 f1 7c 48 28 8d 10 vmovaps zmm1,ZMMWORD PTR [rbp-0xf0] 25e: ff ff ff 261: 62 f1 7c 48 28 85 d0 vmovaps zmm0,ZMMWORD PTR [rbp-0x130] 268: fe ff ff 26b: c5 f4 46 c9 kxnorw k1,k1,k1 26f: 62 f1 7c 49 28 c1 vmovaps zmm0{k1},zmm1 275: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 27c: ff ff ff
V dalším demonstračním příkladu si ukážeme způsob použití intrinsic nazvané __builtin_ia32_addps512_mask. Podle názvu této intrinsic je zřejmé, že provádí vektorový součet, ovšem s využitím masky. Této intrinsic se předává trojice vektorů, maskovací registr (resp. přesněji řečeno hodnota, jenž se do maskovacího registru uloží) a taktéž parametr určující způsob zaokrouhlení. Zajímavé bude zjistit, jak se vlastně chová maska a proč se vůbec této instrukci předává trojice vektorů a nikoli jen dvojice. Podívejme se tedy nejdříve na zdrojový kód demonstračního příkladu:
#include <stdio.h> #include <immintrin.h> int main(void) { __v16sf x = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 }; __v16sf y = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6 }; __v16sf z = -x; __v16sf w; int i; w = __builtin_ia32_addps512_mask(x, y, z, 0, _MM_FROUND_CUR_DIRECTION); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %5.1f %5.1f %5.1f %5.1f\n", i, x[i], y[i], z[i], w[i]); } w = __builtin_ia32_addps512_mask(x, y, z, 0xf0f0, _MM_FROUND_CUR_DIRECTION); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %5.1f %5.1f %5.1f %5.1f\n", i, x[i], y[i], z[i], w[i]); } w = __builtin_ia32_addps512_mask(x, y, z, -1, _MM_FROUND_CUR_DIRECTION); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %5.1f %5.1f %5.1f %5.1f\n", i, x[i], y[i], z[i], w[i]); } return 0; }
Výsledek výpočtů ukazuje, jak se vybírá operace součtu (dvou prvních vstupních registrů) nebo pouhého přesunu (ze třetího vstupního registru) na základě obsahu maskovacího registru:
0 1.0 0.1 -1.0 -1.0 1 2.0 0.2 -2.0 -2.0 2 3.0 0.3 -3.0 -3.0 3 4.0 0.4 -4.0 -4.0 4 5.0 0.5 -5.0 -5.0 5 6.0 0.6 -6.0 -6.0 6 7.0 0.7 -7.0 -7.0 7 8.0 0.8 -8.0 -8.0 8 9.0 0.9 -9.0 -9.0 9 10.0 1.1 -10.0 -10.0 10 11.0 1.1 -11.0 -11.0 11 12.0 1.2 -12.0 -12.0 12 13.0 1.3 -13.0 -13.0 13 14.0 1.4 -14.0 -14.0 14 15.0 1.5 -15.0 -15.0 15 16.0 1.6 -16.0 -16.0 0 1.0 0.1 -1.0 -1.0 1 2.0 0.2 -2.0 -2.0 2 3.0 0.3 -3.0 -3.0 3 4.0 0.4 -4.0 -4.0 4 5.0 0.5 -5.0 5.5 5 6.0 0.6 -6.0 6.6 6 7.0 0.7 -7.0 7.7 7 8.0 0.8 -8.0 8.8 8 9.0 0.9 -9.0 -9.0 9 10.0 1.1 -10.0 -10.0 10 11.0 1.1 -11.0 -11.0 11 12.0 1.2 -12.0 -12.0 12 13.0 1.3 -13.0 14.3 13 14.0 1.4 -14.0 15.4 14 15.0 1.5 -15.0 16.5 15 16.0 1.6 -16.0 17.6 0 1.0 0.1 -1.0 1.1 1 2.0 0.2 -2.0 2.2 2 3.0 0.3 -3.0 3.3 3 4.0 0.4 -4.0 4.4 4 5.0 0.5 -5.0 5.5 5 6.0 0.6 -6.0 6.6 6 7.0 0.7 -7.0 7.7 7 8.0 0.8 -8.0 8.8 8 9.0 0.9 -9.0 9.9 9 10.0 1.1 -10.0 11.1 10 11.0 1.1 -11.0 12.1 11 12.0 1.2 -12.0 13.2 12 13.0 1.3 -13.0 14.3 13 14.0 1.4 -14.0 15.4 14 15.0 1.5 -15.0 16.5 15 16.0 1.6 -16.0 17.6
Způsob překladu výše uvedené intrinsic do objektového kódu a do assembleru:
w = __builtin_ia32_addps512_mask(x, y, z, 0, _MM_FROUND_CUR_DIRECTION); 79: 62 f1 7c 48 28 85 10 vmovaps zmm0,ZMMWORD PTR [rbp-0xf0] 80: ff ff ff 83: 62 f1 7c 48 28 8d d0 vmovaps zmm1,ZMMWORD PTR [rbp-0x130] 8a: fe ff ff 8d: 62 f1 7c 48 28 95 90 vmovaps zmm2,ZMMWORD PTR [rbp-0x170] 94: fe ff ff 97: c5 f4 47 c9 kxorw k1,k1,k1 9b: 62 f1 6c 49 58 c1 vaddps zmm0{k1},zmm2,zmm1 a1: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 a8: ff ff ff w = __builtin_ia32_addps512_mask(x, y, z, 0xf0f0, _MM_FROUND_CUR_DIRECTION); 136: 62 f1 7c 48 28 85 10 vmovaps zmm0,ZMMWORD PTR [rbp-0xf0] 13d: ff ff ff 140: 62 f1 7c 48 28 8d d0 vmovaps zmm1,ZMMWORD PTR [rbp-0x130] 147: fe ff ff 14a: 62 f1 7c 48 28 95 90 vmovaps zmm2,ZMMWORD PTR [rbp-0x170] 151: fe ff ff 154: b8 f0 f0 ff ff mov eax,0xfffff0f0 159: c5 f8 92 d0 kmovw k2,eax 15d: 62 f1 6c 4a 58 c1 vaddps zmm0{k2},zmm2,zmm1 163: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 16a: ff ff ff w = __builtin_ia32_addps512_mask(x, y, z, -1, _MM_FROUND_CUR_DIRECTION); 1f8: 62 f1 7c 48 28 85 10 vmovaps zmm0,ZMMWORD PTR [rbp-0xf0] 1ff: ff ff ff 202: 62 f1 7c 48 28 8d d0 vmovaps zmm1,ZMMWORD PTR [rbp-0x130] 209: fe ff ff 20c: 62 f1 7c 48 28 95 90 vmovaps zmm2,ZMMWORD PTR [rbp-0x170] 213: fe ff ff 216: c5 f4 46 c9 kxnorw k1,k1,k1 21a: 62 f1 6c 49 58 c1 vaddps zmm0{k1},zmm2,zmm1 220: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 227: ff ff ff
10. Komprese a expanze dat
Nyní se dostáváme k zajímavé části AVX-512F. Jedná se o instrukce určené ke „kompresi“ a „expanzi“ dat, resp. přesněji řečeno prvků uložených ve vektorech. Na těchto operacích je zajímavý fakt, že byly poprvé představeny v programovacím jazyku APL. Ovšem ukazuje se, že se jedná o užitečné operace, takže se staly součástí mainstreamu. Jak však tyto operace pracují?
Podívejme se nejdříve na operaci komprese. Ta pracuje s dvojicí vektorů – vektorem libovolných hodnot a bitovým vektorem. Do výsledného vektoru se uloží (za sebou, tedy komprimovaně) pouze ty prvky ze vstupního vektoru, pro které je odpovídající prvek bitového vektoru nastaven na jedničku. Pro desetiprvkové vektory to může vypadat následovně:
compress([1 0 1 0 1 0 1 0 1 0], [1 2 3 4 5 6 7 8 9 10]) = [x x x x x 1 3 5 7 9] compress([0 0 0 0 0 1 1 1 1 1], [1 2 3 4 5 6 7 8 9 10]) = [x x x x x 6 7 8 9 10] compress([1 1 1 1 1 0 0 0 0 0], [1 2 3 4 5 6 7 8 9 10]) = [x x x x x 1 2 3 4 5]
Operace expanze naopak na vstupu očekává vektor „komprimovaných“ hodnot a bitový vektor. Výsledkem bude nový vektor, do kterého jsou na příslušná místa přidány nulové prvky i prvky ze vstupního vektoru: pokud je bit v bitovém vektoru jedničkový, je prvek přečten ze vstupního vektoru, jinak je do výsledku přidána nula. Demonstrační příklady ukážou přesně, jaká operace se provádí:
expand([0 0 0 0 0 1 1 1 1 1], [x x x x x 1 2 3 4 5], [0 0 0 0 0 1 2 3 4 5]) expand([1 0 1 0 1 0 1 0 1 0], [x x x x x 1 2 3 4 5], [1 0 2 0 3 0 4 0 5 0]) expand([1 0 0 0 0 0 1 1 1 1], [x x x x x 1 2 3 4 5], [1 0 0 0 0 0 2 3 4 5])
V tomto případě je výhodné zobrazit si bitový vektor a výsledný vektor pod sebou, aby bylo zřejmé, jaká operace se provádí:
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 2 3 4 5 1 0 1 0 1 0 1 0 1 0 1 0 2 0 3 0 4 0 5 0 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 2 3 4 5
11. Instrukce pro kompresi a expanzi dat
Výše uvedené instrukce pro kompresi a expanzi dat jsou v AVX-512F pojmenovány takto:
Instrukce | Stručný popis instrukce |
---|---|
VCOMPRESSPD | komprese dat pro prvky typu double |
VCOMPRESSPS | komprese dat pro prvky typu single/float |
VPCOMPRESSD | komprese dat pro prvky typu int32 |
VPCOMPRESSQ | komprese dat pro prvky typu int64 |
VEXPANDPD | expanze dat pro prvky typu double |
VEXPANDPS | expanze dat pro prvky typu single/float |
VPEXPANDD | expanze dat pro prvky typu int32 |
VPEXPANDQ | expanze dat pro prvky typu int64 |
12. Instrinsic pro instrukce komprese dat
Otestujme si nyní intrinsic poskytovanou překladačem GCC C, která slouží pro vygenerování některé z instrukcí pro kompresi dat. Konkrétně použijeme intrinsic nazvanou __builtin_ia32_compresssf512_mask, která na vstupu pracuje se dvěma vektory hodnot typu float/single a taky s celočíselnou šestnáctibitovou maskou. Na základě bitů v masce je potom seskládán výsledný vektor, který bude opět obsahovat šestnáct hodnot typu float/single:
#include <stdio.h> #include <immintrin.h> int main(void) { __v16sf x = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 }; __v16sf y = -x; __v16sf z; int i; z = __builtin_ia32_compresssf512_mask(x, y, 0b1010101010101010); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_compresssf512_mask(x, y, 0b0000000011111111); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_compresssf512_mask(x, y, 0b1111111100000000); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } return 0; }
Výsledky získané pro trojici bitových masek podle zdrojového kódu demonstračního příkladu:
0 1.000000 -1.000000 2.000000 1 2.000000 -2.000000 4.000000 2 3.000000 -3.000000 6.000000 3 4.000000 -4.000000 8.000000 4 5.000000 -5.000000 10.000000 5 6.000000 -6.000000 12.000000 6 7.000000 -7.000000 14.000000 7 8.000000 -8.000000 16.000000 8 9.000000 -9.000000 -9.000000 9 10.000000 -10.000000 -10.000000 10 11.000000 -11.000000 -11.000000 11 12.000000 -12.000000 -12.000000 12 13.000000 -13.000000 -13.000000 13 14.000000 -14.000000 -14.000000 14 15.000000 -15.000000 -15.000000 15 16.000000 -16.000000 -16.000000 0 1.000000 -1.000000 1.000000 1 2.000000 -2.000000 2.000000 2 3.000000 -3.000000 3.000000 3 4.000000 -4.000000 4.000000 4 5.000000 -5.000000 5.000000 5 6.000000 -6.000000 6.000000 6 7.000000 -7.000000 7.000000 7 8.000000 -8.000000 8.000000 8 9.000000 -9.000000 -9.000000 9 10.000000 -10.000000 -10.000000 10 11.000000 -11.000000 -11.000000 11 12.000000 -12.000000 -12.000000 12 13.000000 -13.000000 -13.000000 13 14.000000 -14.000000 -14.000000 14 15.000000 -15.000000 -15.000000 15 16.000000 -16.000000 -16.000000 0 1.000000 -1.000000 9.000000 1 2.000000 -2.000000 10.000000 2 3.000000 -3.000000 11.000000 3 4.000000 -4.000000 12.000000 4 5.000000 -5.000000 13.000000 5 6.000000 -6.000000 14.000000 6 7.000000 -7.000000 15.000000 7 8.000000 -8.000000 16.000000 8 9.000000 -9.000000 -9.000000 9 10.000000 -10.000000 -10.000000 10 11.000000 -11.000000 -11.000000 11 12.000000 -12.000000 -12.000000 12 13.000000 -13.000000 -13.000000 13 14.000000 -14.000000 -14.000000 14 15.000000 -15.000000 -15.000000 15 16.000000 -16.000000 -16.000000
Překlad intrinsic do objektového kódu (a do assembleru) bude vypadat následovně:
z = __builtin_ia32_compresssf512_mask(x, y, 0b1010101010101010); 65: 62 f1 7c 48 28 8d 10 vmovaps zmm1,ZMMWORD PTR [rbp-0xf0] 6c: ff ff ff 6f: 62 f1 7c 48 28 85 d0 vmovaps zmm0,ZMMWORD PTR [rbp-0x130] 76: fe ff ff 79: b8 aa aa ff ff mov eax,0xffffaaaa 7e: c5 f8 92 c8 kmovw k1,eax 82: 62 f2 7d 49 8a c1 vcompressps zmm1{k1},zmm0 88: 62 f1 7c 48 28 c1 vmovaps zmm0,zmm1 8e: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 95: ff ff ff z = __builtin_ia32_compresssf512_mask(x, y, 0b0000000011111111); 118: 62 f1 7c 48 28 8d 10 vmovaps zmm1,ZMMWORD PTR [rbp-0xf0] 11f: ff ff ff 122: 62 f1 7c 48 28 85 d0 vmovaps zmm0,ZMMWORD PTR [rbp-0x130] 129: fe ff ff 12c: b8 ff 00 00 00 mov eax,0xff 131: c5 f8 92 d0 kmovw k2,eax 135: 62 f2 7d 4a 8a c1 vcompressps zmm1{k2},zmm0 13b: 62 f1 7c 48 28 c1 vmovaps zmm0,zmm1 141: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 148: ff ff ff z = __builtin_ia32_compresssf512_mask(x, y, 0b1111111100000000); 1cb: 62 f1 7c 48 28 8d 10 vmovaps zmm1,ZMMWORD PTR [rbp-0xf0] 1d2: ff ff ff 1d5: 62 f1 7c 48 28 85 d0 vmovaps zmm0,ZMMWORD PTR [rbp-0x130] 1dc: fe ff ff 1df: b8 00 ff ff ff mov eax,0xffffff00 1e4: c5 f8 92 d8 kmovw k3,eax 1e8: 62 f2 7d 4b 8a c1 vcompressps zmm1{k3},zmm0 1ee: 62 f1 7c 48 28 c1 vmovaps zmm0,zmm1 1f4: 62 f1 7c 48 29 85 50 vmovaps ZMMWORD PTR [rbp-0xb0],zmm0 1fb: ff ff ff
13. Instrukce pro provedení permutace (přerozdělení) prvků vektorů
Mezi další instrukce přidané do AVX-512F (a tedy podporované všemi typy mikroprocesorů, které mají implementovanou nějakou kombinaci sad AVX-512) patří instrukce provádějící permutaci (tedy přerozdělení) prvků vektorů. Jedná se konkrétně o tyto instrukce:
Instrukce | Stručný popis instrukce |
---|---|
VPERMI2PD | permutace vektorů s prvky typu double s přepisem indexu |
VPERMI2PS | permutace vektorů s prvky typu single s přepisem indexu |
VPERMI2D | permutace vektorů s prvky typu int32 s přepisem indexu |
VPERMI2Q | permutace vektorů s prvky typu int64 s přepisem indexu |
VPERMT2PD | permutace vektorů s prvky typu double s přepisem prvního zdrojového registru |
VPERMT2PS | permutace vektorů s prvky typu single s přepisem prvního zdrojového registru |
VPERMT2D | permutace vektorů s prvky typu int32 s přepisem prvního zdrojového registru |
VPERMT2Q | permutace vektorů s prvky typu int64 s přepisem prvního zdrojového registru |
VSHUFF32×4 | přeskládání čtveřice lanes, z nichž každá má šířku 128 bitů |
VSHUFF64×2 | přeskládání čtveřice lanes, z nichž každá má šířku 128 bitů |
VSHUFI32×4 | přeskládání čtveřice lanes, z nichž každá má šířku 128 bitů |
VSHUFI64×2 | přeskládání čtveřice lanes, z nichž každá má šířku 128 bitů |
14. Intrinsic pro provedení permutace
Vyzkoušejme si nyní, jak vlastně instrukce pro provedení permutace funguje. Opět se zaměříme na dvojici vstupních vektorů, z nichž každý obsahuje šestnáct hodnot typu single/float. První vektor bude obsahovat kladné hodnoty, druhý vektor hodnoty záporné. S touto dvojicí vektorů provedeme permutaci s využitím indexu (osmibitová celočíselná hodnota) a zápisové masky (šestnáctibitová celočíselná hodnota). Výsledek je vypsán pro různé kombinace indexů a zápisových masek:
#include <stdio.h> #include <immintrin.h> int main(void) { __v16sf x = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 }; __v16sf y = -x; __v16sf z; int i; z = __builtin_ia32_vpermilps512_mask(x, 0x00, z, 0x0000); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_vpermilps512_mask(x, 0x00, z, 0xffff); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_vpermilps512_mask(x, 0x03, z, 0xffff); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); z = __builtin_ia32_vpermilps512_mask(x, 0x04, z, 0xffff); for (i = 0; i < sizeof(x) / sizeof(float); i++) { printf("%2d %f %f %f\n", i, x[i], y[i], z[i]); } putchar('\n'); return 0; }
Výsledky rozdělíme do čtyř skupin.
Index nastavený na 0×00, maska nastavená na 0×0000. Vzhledem k tomu, že všechny bity masky jsou nulové a současně i index je nulový, budou všechny prvky vektoru nastaveny na nulu (nezávisle na obsahu vstupních vektorů):
0 1.000000 -1.000000 0.000000 1 2.000000 -2.000000 0.000000 2 3.000000 -3.000000 0.000000 3 4.000000 -4.000000 0.000000 4 5.000000 -5.000000 0.000000 5 6.000000 -6.000000 0.000000 6 7.000000 -7.000000 0.000000 7 8.000000 -8.000000 0.000000 8 9.000000 -9.000000 0.000000 9 10.000000 -10.000000 0.000000 10 11.000000 -11.000000 0.000000 11 12.000000 -12.000000 0.000000 12 13.000000 -13.000000 0.000000 13 14.000000 -14.000000 0.000000 14 15.000000 -15.000000 0.000000 15 16.000000 -16.000000 0.000000
Index nastavený na 0×00, maska nastavená na 0×ffff. Maska nyní nebude „blokovat/nulovat“ prvky, takže se projeví vliv indexu. Vstupní vektor je rozdělený do čtyř částí a z každé části je vybrán první prvek (který je následně rozkopírován do čtyř prvků výsledného vektoru):
0 1.000000 -1.000000 1.000000 1 2.000000 -2.000000 1.000000 2 3.000000 -3.000000 1.000000 3 4.000000 -4.000000 1.000000 4 5.000000 -5.000000 5.000000 5 6.000000 -6.000000 5.000000 6 7.000000 -7.000000 5.000000 7 8.000000 -8.000000 5.000000 8 9.000000 -9.000000 9.000000 9 10.000000 -10.000000 9.000000 10 11.000000 -11.000000 9.000000 11 12.000000 -12.000000 9.000000 12 13.000000 -13.000000 13.000000 13 14.000000 -14.000000 13.000000 14 15.000000 -15.000000 13.000000 15 16.000000 -16.000000 13.000000
Index nastavený na 0×03, maska nastavená na 0×ffff. Opět dojde k rozdělení vstupního vektoru na čtyři části. První prvek každé části výsledného vektoru z každé části bude vybrán ze vstupního vektoru ze stejné části, ovšem s indexem posunutým o trojku:
0 1.000000 -1.000000 4.000000 1 2.000000 -2.000000 1.000000 2 3.000000 -3.000000 1.000000 3 4.000000 -4.000000 1.000000 4 5.000000 -5.000000 8.000000 5 6.000000 -6.000000 5.000000 6 7.000000 -7.000000 5.000000 7 8.000000 -8.000000 5.000000 8 9.000000 -9.000000 12.000000 9 10.000000 -10.000000 9.000000 10 11.000000 -11.000000 9.000000 11 12.000000 -12.000000 9.000000 12 13.000000 -13.000000 16.000000 13 14.000000 -14.000000 13.000000 14 15.000000 -15.000000 13.000000 15 16.000000 -16.000000 13.000000
Index nastavený na 0×04, maska nastavená na 0×ffff. Opět dojde k rozdělení vstupního vektoru na čtyři části. Tentokrát se ovšem díky konstantě 0×04 (nastavený bit s indexe 5) změní způsob výběru druhého prvku:
0 1.000000 -1.000000 1.000000 1 2.000000 -2.000000 2.000000 2 3.000000 -3.000000 1.000000 3 4.000000 -4.000000 1.000000 4 5.000000 -5.000000 5.000000 5 6.000000 -6.000000 6.000000 6 7.000000 -7.000000 5.000000 7 8.000000 -8.000000 5.000000 8 9.000000 -9.000000 9.000000 9 10.000000 -10.000000 10.000000 10 11.000000 -11.000000 9.000000 11 12.000000 -12.000000 9.000000 12 13.000000 -13.000000 13.000000 13 14.000000 -14.000000 14.000000 14 15.000000 -15.000000 13.000000 15 16.000000 -16.000000 13.000000
Kombinace předchozích možností: index nastavený na 0×11, maska nastavená na 0×ffff:
0 1.000000 -1.000000 2.000000 1 2.000000 -2.000000 1.000000 2 3.000000 -3.000000 2.000000 3 4.000000 -4.000000 1.000000 4 5.000000 -5.000000 6.000000 5 6.000000 -6.000000 5.000000 6 7.000000 -7.000000 6.000000 7 8.000000 -8.000000 5.000000 8 9.000000 -9.000000 10.000000 9 10.000000 -10.000000 9.000000 10 11.000000 -11.000000 10.000000 11 12.000000 -12.000000 9.000000 12 13.000000 -13.000000 14.000000 13 14.000000 -14.000000 13.000000 14 15.000000 -15.000000 14.000000 15 16.000000 -16.000000 13.000000
15. Rozšíření AVX-512BW
Zajímavou podmnožinou AVX-512 je AVX-512BW. Tato podmnožina rozšiřuje většinu již existujících instrukcí takovým způsobem, aby je bylo možné použít i pro vektory s datovými typy int8/byte a int16. Zdálo by se, že toto rozšíření je triviální, ovšem je zde jeden háček – vektorové registry o šířce 512 bitů obsahují 64 prvků typu int8/byte a 32 prvků typu int16, takže pro ty instrukce, v nichž se používají maskovací registry, muselo dojít k rozšíření těchto registrů na 32 resp. pro bytové vektory dokonce na 64 bitů. I přes tento problém je rozšíření AVX-512BW potenciálně velmi dobře použitelné například při zpracování audia a videa, stejně jako pro operace s rastrovými obrázky. Všechny nové instrukce popsané v předchozích kapitolách, byly upraveny i pro typy int8 a int16, pouze se změnila koncovka na B, W, UB nebo UW:
Instrukce |
---|
VPBLENDMB |
VPBLENDMW |
VPCMPB |
VPCMPUB |
VPCMPW |
VPCMPUW |
VPTESTMB |
VPTESTMW |
VPTESTNMB |
VPTESTNMW |
VPERMT2W |
VPERMI2W |
16. Rozšíření Vector Neural Network Instructions (VNNI)
Potenciálně užitečné (pokud se tedy všechny výpočty nepřesunou na GPU) jsou čtyři instrukce zavedené v rámci podmnožiny VNNI neboli Vector Neural Network Instructions. Tyto instrukce provádí výpočty s vektory, jejichž prvky jsou typu bajt nebo šestnáctibitové celé číslo:
Instrukce | Stručný popis |
---|---|
VPDPBUSD | vynásobení skupin čtyř dvojic bajtů se součtem výsledků |
VPDPBUSDS | dtto, ovšem se saturací |
VPDPWSSD | dtto, jako VPDPBUSD, ovšem pro šestnáctibitové hodnoty |
VPDPWSSDS | dtto, jako VPDPBUSDS, ovšem pro šestnáctibitové hodnoty |
17. Příloha – soubor Makefile použitý v článcích o SIMD operacích
Následující soubor Makefile byl použit pro překlad zdrojových kódů všech výše uvedených demonstračních příkladů do objektového kódu jeho s následným disassemblingem do assembleru (resp. přesněji řečeno do assembleru zkombinovaného s hexadecimálním výpisem obsahu souboru s objektovým kódem). Makefile obsahuje i instrukce pro překlad demonstračních příkladů z předchozích článků o SIMD operacích:
CC=gcc OBJDUMP=objdump all: simd04_1.lst simd04_2.lst \ simd04B_1.lst simd04B_2.lst \ simd07_1.lst simd07_2.lst \ simd08_1.lst simd08_2.lst \ simd12_1.lst simd12_2.lst \ simd13_1.lst simd13_2.lst simd13_3.lst simd13_4.lst \ simd14_1.lst simd14_2.lst simd14_3.lst simd14_4.lst \ simd15_1.lst simd15_2.lst simd15_3.lst simd15_4.lst \ simd16_1.lst simd16_2.lst simd16_3.lst simd16_4.lst \ simd17_1.lst simd17_2.lst simd17_3.lst simd17_4.lst \ simd18_1.lst simd18_2.lst simd18_3.lst simd18_4.lst \ simd19_sse.lst simd19_avx.lst simd19_avx2.lst \ simd20_sse.lst simd20_avx.lst simd20_avx2.lst \ simd21_sse.lst simd21_avx.lst simd21_avx2.lst \ intrinsic_mmx_1.lst \ intrinsic_mmx_2.lst \ intrinsic_mmx_3.lst \ intrinsic_mmx_4.lst \ intrinsic_mmx_5.lst \ intrinsic_sse_1.lst \ intrinsic_sse_2.lst \ intrinsic_sse_3.lst \ intrinsic_sse_4.lst \ intrinsic_sse_5.lst \ intrinsic_sse_6.lst \ intrinsic_sse_7.lst \ intrinsic_sse_8.lst \ intrinsic_sse_9.lst \ intrinsic_sse_A.lst \ intrinsic_sse_B.lst \ intrinsic_f16c_1.lst \ intrinsic_f16c_2.lst \ intrinsic_f16c_3.lst \ intrinsic_f16c_4.lst \ intrinsic_fma3_1.lst \ intrinsic_fma3_2.lst \ intrinsic_fma3_3.lst \ intrinsic_fma3_4.lst \ intrinsic_fma3_5.lst \ intrinsic_avx_512_k_registers.lst \ intrinsic_avx_512_vblendps.c \ intrinsic_avx_512_addps.c \ intrinsic_avx_512_compress.c clean: rm *.lst rm *.o %.lst: %.o objdump -d -M intel -S $< > $@ simd04_1.o: simd04.c gcc -c -O0 -mno-sse -g -o $@ $< simd04_2.o: simd04.c gcc -c -O0 -g -o $@ $< simd04B_1.o: simd04B.c gcc -c -O0 -mno-sse -g -o $@ $< simd04B_2.o: simd04B.c gcc -c -O0 -g -o $@ $< simd07_1.o: simd07.c gcc -c -mno-sse -g -o $@ $< simd07_2.o: simd07.c gcc -c -g -o $@ $< simd08_1.o: simd08.c gcc -c -mno-sse -g -o $@ $< simd08_2.o: simd08.c gcc -c -g -o $@ $< simd12_1.o: simd12.c gcc -c -O0 -mno-sse -g -o $@ $< simd12_2.o: simd12.c gcc -c -O0 -g -o $@ $< simd13_1.o: simd13.c gcc -c -O0 -mno-sse -g -o $@ $< simd13_2.o: simd13.c gcc -c -O0 -g -o $@ $< simd13_3.o: simd13.c gcc -c -O3 -mno-sse -g -o $@ $< simd13_4.o: simd13.c gcc -c -O3 -g -o $@ $< simd14_1.o: simd14.c gcc -c -O0 -mno-sse -g -o $@ $< simd14_2.o: simd14.c gcc -c -O0 -g -o $@ $< simd14_3.o: simd14.c gcc -c -O3 -mno-sse -g -o $@ $< simd14_4.o: simd14.c gcc -c -O3 -g -o $@ $< simd15_1.o: simd15.c gcc -c -O0 -mno-sse -g -o $@ $< simd15_2.o: simd15.c gcc -c -O0 -g -o $@ $< simd15_3.o: simd15.c gcc -c -O3 -mno-sse -g -o $@ $< simd15_4.o: simd15.c gcc -c -O3 -g -o $@ $< simd16_1.o: simd16.c gcc -c -O0 -mno-sse -g -o $@ $< simd16_2.o: simd16.c gcc -c -O0 -g -o $@ $< simd16_3.o: simd16.c gcc -c -O3 -mno-sse -g -o $@ $< simd16_4.o: simd16.c gcc -c -O3 -g -o $@ $< simd17_1.o: simd17.c gcc -c -O0 -mno-sse -g -o $@ $< simd17_2.o: simd17.c gcc -c -O0 -g -o $@ $< simd17_3.o: simd17.c gcc -c -O3 -mno-sse -g -o $@ $< simd17_4.o: simd17.c gcc -c -O3 -g -o $@ $< simd18_1.o: simd18.c gcc -c -O0 -mno-sse -g -o $@ $< simd18_2.o: simd18.c gcc -c -O0 -g -o $@ $< simd18_3.o: simd18.c gcc -c -O3 -mno-sse -g -o $@ $< simd18_4.o: simd18.c gcc -c -O3 -g -o $@ $< simd19_sse.o: simd19.c gcc -c -O0 -msse -mno-avx -g -o $@ $< simd19_avx.o: simd19.c gcc -c -O0 -mavx -g -o $@ $< simd19_avx2.o: simd19.c gcc -c -O0 -mavx2 -g -o $@ $< simd20_sse.o: simd20.c gcc -c -O0 -msse -mno-avx -g -o $@ $< simd20_avx.o: simd20.c gcc -c -O0 -mavx -g -o $@ $< simd20_avx2.o: simd20.c gcc -c -O0 -mavx2 -g -o $@ $< simd21_sse.o: simd21.c gcc -c -O0 -msse -mno-avx -g -o $@ $< simd21_avx.o: simd21.c gcc -c -O0 -mavx -g -o $@ $< simd21_avx2.o: simd21.c gcc -c -O0 -mavx2 -g -o $@ $< intrinsic_mmx_1.o: intrinsic_mmx_1.c gcc -c -O0 -g -o $@ $< intrinsic_mmx_2.o: intrinsic_mmx_2.c gcc -c -O0 -g -o $@ $< intrinsic_mmx_3.o: intrinsic_mmx_3.c gcc -c -O0 -g -o $@ $< intrinsic_mmx_4.o: intrinsic_mmx_4.c gcc -c -O0 -g -o $@ $< intrinsic_mmx_5.o: intrinsic_mmx_5.c gcc -c -O0 -g -o $@ $< intrinsic_sse_1.o: intrinsic_sse_1.c gcc -c -O0 -g -o $@ $< intrinsic_sse_2.o: intrinsic_sse_2.c gcc -c -O0 -g -o $@ $< intrinsic_sse_3.o: intrinsic_sse_3.c gcc -c -O0 -g -o $@ $< intrinsic_sse_4.o: intrinsic_sse_4.c gcc -c -O0 -g -o $@ $< intrinsic_sse_5.o: intrinsic_sse_5.c gcc -c -O0 -g -o $@ $< intrinsic_sse_6.o: intrinsic_sse_6.c gcc -c -O0 -g -o $@ $< intrinsic_sse_7.o: intrinsic_sse_7.c gcc -c -O0 -g -o $@ $< intrinsic_sse_8.o: intrinsic_sse_8.c gcc -c -O0 -g -o $@ $< intrinsic_sse_9.o: intrinsic_sse_9.c gcc -c -O0 -g -o $@ $< intrinsic_sse_A.o: intrinsic_sse_A.c gcc -c -O0 -g -o $@ $< intrinsic_sse_B.o: intrinsic_sse_B.c gcc -c -O0 -g -o $@ $< intrinsic_avx_1.o: intrinsic_avx_1.c gcc -c -mavx -O0 -g -o $@ $< intrinsic_avx_2.o: intrinsic_avx_2.c gcc -c -mavx -O0 -g -o $@ $< intrinsic_avx_3.o: intrinsic_avx_3.c gcc -c -mavx -O0 -g -o $@ $< intrinsic_f16c_1.o: intrinsic_f16c_1.c gcc -c -mf16c -O0 -g -o $@ $< intrinsic_f16c_2.o: intrinsic_f16c_2.c gcc -c -mf16c -O0 -g -o $@ $< intrinsic_f16c_3.o: intrinsic_f16c_3.c gcc -c -mf16c -O0 -g -o $@ $< intrinsic_f16c_4.o: intrinsic_f16c_4.c gcc -c -mf16c -O0 -g -o $@ $< intrinsic_fma3_1.o: intrinsic_fma3_1.c gcc -c -mfma -O0 -g -o $@ $< intrinsic_fma3_2.o: intrinsic_fma3_2.c gcc -c -mfma -O0 -g -o $@ $< intrinsic_fma3_3.o: intrinsic_fma3_3.c gcc -c -mfma -O0 -g -o $@ $< intrinsic_fma3_4.o: intrinsic_fma3_4.c gcc -c -mfma -O0 -g -o $@ $< intrinsic_fma3_5.o: intrinsic_fma3_5.c gcc -c -mfma -O0 -g -o $@ $< intrinsic_avx_512_k_registers.o: intrinsic_avx_512_k_registers.c gcc -c -mavx512f -O0 -g -o $@ $< intrinsic_avx_512_vblendps.o: intrinsic_avx_512_vblendps.c gcc -c -mavx512f -O0 -g -o $@ $< intrinsic_avx_512_addps.o: intrinsic_avx_512_addps.c gcc -c -mavx512f -O0 -g -o $@ $< intrinsic_avx_512_compress.o: intrinsic_avx_512_compress.c gcc -c -mavx512f -O0 -g -o $@ $<
18. Repositář s demonstračními příklady
Demonstrační příklady napsané v jazyku C, které jsou určené pro překlad pomocí překladače GCC C, byly uložen do Git repositáře, který je dostupný na adrese https://github.com/tisnik/presentations. Jednotlivé demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již velmi rozsáhlý) repositář:
# | Příklad | Stručný popis | Adresa |
---|---|---|---|
1 | simd01.c | vektor celých čísel typu short int | https://github.com/tisnik/presentations/blob/master/SIMD/simd01.c |
2 | simd02.c | ukázka použití vektorů s celočíselnými typy bez znaménka | https://github.com/tisnik/presentations/blob/master/SIMD/simd02.c |
3 | simd03.c | ukázka použití vektorů s celočíselnými typy se znaménkem | https://github.com/tisnik/presentations/blob/master/SIMD/simd03.c |
4 | simd04.c | paralelní součet celočíselných prvků vektorů | https://github.com/tisnik/presentations/blob/master/SIMD/simd04.c |
5 | simd04B.c | úprava pro další datové typy | https://github.com/tisnik/presentations/blob/master/SIMD/simd04B.c |
6 | simd05.c | přístup k jednotlivým prvkům vektorů | https://github.com/tisnik/presentations/blob/master/SIMD/simd05.c |
7 | simd05B.c | korektnější výpočet počtu prvků vektoru | https://github.com/tisnik/presentations/blob/master/SIMD/simd05B.c |
8 | simd05C.c | definice typu vektoru | https://github.com/tisnik/presentations/blob/master/SIMD/simd05C.c |
9 | simd06.c | vektor čísel s plovoucí řádovou čárkou | https://github.com/tisnik/presentations/blob/master/SIMD/simd06.c |
10 | simd07.c | paralelní součet prvků vektorů (typ float) | https://github.com/tisnik/presentations/blob/master/SIMD/simd07.c |
11 | simd08.c | paralelní součet prvků vektorů (typ double) | https://github.com/tisnik/presentations/blob/master/SIMD/simd08.c |
12 | simd09.c | překročení délky vektoru | https://github.com/tisnik/presentations/blob/master/SIMD/simd09.c |
13 | simd10.c | přístup k jednotlivým prvkům vektorů | https://github.com/tisnik/presentations/blob/master/SIMD/simd10.c |
14 | simd11.c | překročení délky vektoru | https://github.com/tisnik/presentations/blob/master/SIMD/simd11.c |
15 | simd12.c | dlouhý vektor s 256 bajty | https://github.com/tisnik/presentations/blob/master/SIMD/simd12.c |
16 | simd13.c | operace součtu pro vektory s celočíselnými prvky rozličné bitové šířky bez znaménka | https://github.com/tisnik/presentations/blob/master/SIMD/simd13.c |
17 | simd14.c | operace součtu pro vektory s celočíselnými prvky rozličné bitové šířky se znaménkem | https://github.com/tisnik/presentations/blob/master/SIMD/simd14.c |
18 | simd15.c | operace součtu pro vektory s prvky rozličné bitové šířky s plovoucí řádovou čárkou | https://github.com/tisnik/presentations/blob/master/SIMD/simd15.c |
19 | simd16.c | operace součtu pro dlouhé vektory s prvky rozličné bitové šířky s plovoucí řádovou čárkou | https://github.com/tisnik/presentations/blob/master/SIMD/simd16.c |
20 | simd17.c | všechny podporované binární operace nad vektory s celočíselnými prvky se znaménkem | https://github.com/tisnik/presentations/blob/master/SIMD/simd17.c |
21 | simd18.c | všechny podporované binární operace nad vektory s prvky typu float | https://github.com/tisnik/presentations/blob/master/SIMD/simd18.c |
23 | intrinsic_mmx1.c | intrinsic pro technologii MMX: instrukce paddb | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx1.c |
24 | intrinsic_mmx2.c | intrinsic pro technologii MMX: instrukce paddw | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx2.c |
25 | intrinsic_mmx3.c | intrinsic pro technologii MMX: instrukce paddb (přetečení) | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx3.c |
26 | intrinsic_mmx4.c | intrinsic pro technologii MMX: instrukce paddsb (saturace) | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx4.c |
27 | intrinsic_mmx5.c | intrinsic pro technologii MMX: instrukce pupckhbw (kombinace dvou vektorů) | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx5.c |
28 | intrinsic_sse1.c | součet dvou vektorů s šestnácti prvky typu char instrukcí paddb128 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse1.c |
29 | intrinsic_sse2.c | součet dvou vektorů s osmi prvky typu short instrukcí paddw128 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse2.c |
30 | intrinsic_sse3.c | součet dvou vektorů se čtyřmi prvky typu int instrukcí paddd128 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse3.c |
31 | intrinsic_sse4.c | součet dvou vektorů se dvěma prvky typu long instrukcí paddq128 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse4.c |
32 | intrinsic_sse5.c | součet dvou vektorů se čtyřmi prvky typu float instrukcí addps | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse5.c |
33 | intrinsic_sse6.c | součet dvou vektorů se dvěma prvky typu double instrukcí addpd | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse6.c |
34 | intrinsic_sse7.c | porovnání celočíselných prvků instrukcemi pcmpeqb128 a pcmpgtb128 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse7.c |
35 | intrinsic_sse8.c | všech šest relačních operací pro vektory s prvky typu float | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse8.c |
36 | intrinsic_sse9.c | unární operace pro výpočet převrácené hodnoty, druhé odmocniny a převrácené hodnoty druhé odmocniny | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse9.c |
37 | intrinsic_sse_A.c | instrukce shufps a její intrinsic | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse_A.c |
38 | intrinsic_sse_B.c | instrukce unpckhps a unpcklps a jejich intrinsics | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse_B.c |
39 | simd19.c | operace součtu vektorů o délce 256 bitů s celočíselnými prvky bez znaménka | https://github.com/tisnik/presentations/blob/master/SIMD/simd19.c |
40 | simd20.c | operace součtu vektorů o délce 256 bitů s celočíselnými prvky se znaménkem | https://github.com/tisnik/presentations/blob/master/SIMD/simd20.c |
41 | simd21.c | operace součtu vektorů o délce 256 bitů s prvky typu float a double | https://github.com/tisnik/presentations/blob/master/SIMD/simd21.c |
42 | test_extensions.c | test, které instrukční sady mikroprocesor podporuje | https://github.com/tisnik/presentations/blob/master/SIMD/test_extensions.c |
43 | test_avx512_extensions.c | test, které instrukční sady mikroprocesor podporuje, rozšíření o AVX-512 | https://github.com/tisnik/presentations/blob/master/SIMD/test_avx512_extensions |
44 | intrinsic_f16c1.c | převod 128bitového vektoru s prvky typu float na half a zpět | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c1.c |
45 | intrinsic_f16c2.c | převod 128bitového vektoru s prvky typu float na half a zpět, zpracování velkých hodnot | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c2.c |
46 | intrinsic_f16c3.c | převod 128bitového vektoru s prvky typu float na half s volbou režimu zaokrouhlení | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c3.c |
47 | intrinsic_f16c4.c | převod 256bitového vektoru s prvky typu float na half a zpět | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c4.c |
48 | intrinsic_fma3_1.c | využití instrukce pro provedení vektorové operace x = a*b+c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_1.c |
49 | intrinsic_fma3_2.c | dtto, ale pro odlišné hodnoty | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_2.c |
50 | intrinsic_fma3_3.c | dtto, ale vynásobení maximálními možnými FP hodnotami | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_3.c |
51 | intrinsic_fma3_4.c | využití instrukce pro provedení vektorové operace x = -a*b+c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_4.c |
52 | intrinsic_fma3_5.c | využití instrukce pro provedení vektorové operace x = a*b-c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_5.c |
53 | decode_half_float.c | dekódování hodnot s plovoucí řádovou čárkou uložených ve formátu half float | https://github.com/tisnik/presentations/blob/master/SIMD/decode_half_float.c |
54 | intrinsic_avx512_k_registers.c | bitové operace s maskovacími registry | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_k_registers.c |
55 | intrinsic_avx512_vblendps.c | operace typu blend založená na maskovacím registru | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_vblendps.c |
56 | intrinsic_avx512_addps.c | operace typu addps s maskováním | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_addps.c |
57 | intrinsic_avx512_compress.c | operace typu compress s maskováním | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_compress.c |
58 | intrinsic_avx512_permute.c | operace typu permute s maskováním | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_permute.c |
59 | Makefile | Makefile pro překlad všech výše uvedených demonstračních příkladů | https://github.com/tisnik/presentations/blob/master/SIMD/Makefile |
Soubory vzniklé překladem z jazyka C do assembleru procesorů x86–64:
# | Příklad | Stručný popis | Adresa |
---|---|---|---|
1 | simd04_1.lst | překlad zdrojového kódu simd04_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd04_1.lst |
2 | simd04_2.lst | překlad zdrojového kódu simd04_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd04_2.lst |
3 | simd04B1.lst | překlad zdrojového kódu simd04B1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd04B1.lst |
4 | simd04B2.lst | překlad zdrojového kódu simd04B2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd04B2.lst |
5 | simd07_1.lst | překlad zdrojového kódu simd07_1.c s přepínači -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd07_1.lst |
6 | simd07_2.lst | překlad zdrojového kódu simd07_2.c s přepínači -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd07_2.lst |
7 | simd08_1.lst | překlad zdrojového kódu simd08_1.c s přepínači -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd08_1.lst |
8 | simd08_2.lst | překlad zdrojového kódu simd08_2.c s přepínači -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd08_2.lst |
9 | simd12_1.lst | překlad zdrojového kódu simd12_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd12_1.lst |
10 | simd12_2.lst | překlad zdrojového kódu simd12_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd12_2.lst |
11 | simd13_1.lst | překlad zdrojového kódu simd13_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd13_1.lst |
12 | simd13_2.lst | překlad zdrojového kódu simd13_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd13_2.lst |
13 | simd13_3.lst | překlad zdrojového kódu simd13_3.c s přepínači -O3 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd13_3.lst |
14 | simd13_4.lst | překlad zdrojového kódu simd13_4.c s přepínači -O3 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd13_4.lst |
15 | simd14_1.lst | překlad zdrojového kódu simd14_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd14_1.lst |
16 | simd14_2.lst | překlad zdrojového kódu simd14_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd14_2.lst |
17 | simd14_3.lst | překlad zdrojového kódu simd14_3.c s přepínači -O3 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd14_3.lst |
18 | simd14_4.lst | překlad zdrojového kódu simd14_4.c s přepínači -O3 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd14_4.lst |
19 | simd15_1.lst | překlad zdrojového kódu simd15_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd15_1.lst |
20 | simd15_2.lst | překlad zdrojového kódu simd15_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd15_2.lst |
21 | simd15_3.lst | překlad zdrojového kódu simd15_3.c s přepínači -O3 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd15_3.lst |
22 | simd15_4.lst | překlad zdrojového kódu simd15_4.c s přepínači -O3 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd15_4.lst |
23 | simd16_1.lst | překlad zdrojového kódu simd16_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd16_1.lst |
24 | simd16_2.lst | překlad zdrojového kódu simd16_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd16_2.lst |
25 | simd16_3.lst | překlad zdrojového kódu simd16_3.c s přepínači -O3 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd16_3.lst |
26 | simd16_4.lst | překlad zdrojového kódu simd16_4.c s přepínači -O3 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd16_4.lst |
27 | simd17_1.lst | překlad zdrojového kódu simd17_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd17_1.lst |
28 | simd17_2.lst | překlad zdrojového kódu simd17_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd17_2.lst |
29 | simd17_3.lst | překlad zdrojového kódu simd17_3.c s přepínači -O3 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd17_3.lst |
30 | simd17_4.lst | překlad zdrojového kódu simd17_4.c s přepínači -O3 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd17_4.lst |
31 | simd18_1.lst | překlad zdrojového kódu simd18_1.c s přepínači -O0 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd18_1.lst |
32 | simd18_2.lst | překlad zdrojového kódu simd18_2.c s přepínači -O0 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd18_2.lst |
33 | simd18_3.lst | překlad zdrojového kódu simd18_3.c s přepínači -O3 -mno-sse -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd18_3.lst |
34 | simd18_4.lst | překlad zdrojového kódu simd18_4.c s přepínači -O3 -g | https://github.com/tisnik/presentations/blob/master/SIMD/simd18_4.lst |
35 | intrinsic_mmx1.lst | překlad zdrojového kódu intrinsic_mmx1.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx1.lst |
36 | intrinsic_mmx2.lst | překlad zdrojového kódu intrinsic_mmx2.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx2.lst |
37 | intrinsic_mmx3.lst | překlad zdrojového kódu intrinsic_mmx3.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx3.lst |
39 | intrinsic_mmx5.lst | překlad zdrojového kódu intrinsic_mmx5.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_mmx5.lst |
40 | intrinsic_sse1.lst | překlad zdrojového kódu intrinsic_sse1.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse1.lst |
41 | intrinsic_sse2.lst | překlad zdrojového kódu intrinsic_sse2.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse2.lst |
42 | intrinsic_sse3.lst | překlad zdrojového kódu intrinsic_sse3.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse3.lst |
43 | intrinsic_sse4.lst | překlad zdrojového kódu intrinsic_sse4.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse4.lst |
44 | intrinsic_sse5.lst | překlad zdrojového kódu intrinsic_sse5.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse5.lst |
45 | intrinsic_sse6.lst | překlad zdrojového kódu intrinsic_sse6.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse6.lst |
46 | intrinsic_sse7.lst | překlad zdrojového kódu intrinsic_sse7.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse7.lst |
47 | intrinsic_sse8.lst | překlad zdrojového kódu intrinsic_sse8.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse8.lst |
48 | intrinsic_sse9.lst | překlad zdrojového kódu intrinsic_sse9.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse9.lst |
49 | intrinsic_sse_A.lst | překlad zdrojového kódu intrinsic_sse_A.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse_A.lst |
50 | intrinsic_sse_B.lst | překlad zdrojového kódu intrinsic_sse_B.c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_sse_B.lst |
51 | simd19_sse.lst | překlad zdrojového kódu simd19.c s přepínačem -msse -mno-avx | https://github.com/tisnik/presentations/blob/master/SIMD/simd19_sse.lst |
52 | simd19_avx.lst | překlad zdrojového kódu simd19.c s přepínačem -mavx | https://github.com/tisnik/presentations/blob/master/SIMD/simd19_avx.lst |
53 | simd19_avx2.lst | překlad zdrojového kódu simd19.c s přepínačem -mavx2 | https://github.com/tisnik/presentations/blob/master/SIMD/simd19_avx2.lst |
54 | simd20_sse.lst | překlad zdrojového kódu simd20.c s přepínačem -msse -mno-avx | https://github.com/tisnik/presentations/blob/master/SIMD/simd20_sse.lst |
55 | simd20_avx.lst | překlad zdrojového kódu simd20.c s přepínačem -mavx | https://github.com/tisnik/presentations/blob/master/SIMD/simd20_avx.lst |
56 | simd20_avx2.lst | překlad zdrojového kódu simd20.c s přepínačem -mavx2 | https://github.com/tisnik/presentations/blob/master/SIMD/simd20_avx2.lst |
57 | simd21_sse.lst | překlad zdrojového kódu simd21.c s přepínačem -msse -mno-avx | https://github.com/tisnik/presentations/blob/master/SIMD/simd21_sse.lst |
58 | simd21_avx.lst | překlad zdrojového kódu simd21.c s přepínačem -mavx | https://github.com/tisnik/presentations/blob/master/SIMD/simd21_avx.lst |
59 | simd21_avx2.lst | překlad zdrojového kódu simd21.c s přepínačem -mavx3 | https://github.com/tisnik/presentations/blob/master/SIMD/simd21_avx2.lst |
60 | intrinsic_f16c1.lst | překlad zdrojového kódu intrinsic_f16c1.c s přepínačem -mf16c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c1.lst |
61 | intrinsic_f16c2.lst | překlad zdrojového kódu intrinsic_f16c2.c s přepínačem -mf16c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c2.lst |
62 | intrinsic_f16c3.lst | překlad zdrojového kódu intrinsic_f16c3.c s přepínačem -mf16c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c3.lst |
63 | intrinsic_f16c4.lst | překlad zdrojového kódu intrinsic_f16c4.c s přepínačem -mf16c | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_f16c4.lst |
64 | intrinsic_fma3_1.lst | překlad zdrojového kódu intrinsic_fma3_1.c s přepínačem -mfma | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_1.lst |
65 | intrinsic_fma3_2.lst | překlad zdrojového kódu intrinsic_fma3_2.c s přepínačem -mfma | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_2.lst |
66 | intrinsic_fma3_3.lst | překlad zdrojového kódu intrinsic_fma3_3.c s přepínačem -mfma | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_3.lst |
67 | intrinsic_fma3_4.lst | překlad zdrojového kódu intrinsic_fma3_4.c s přepínačem -mfma | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_4.lst |
68 | intrinsic_fma3_5.lst | překlad zdrojového kódu intrinsic_fma3_5.c s přepínačem -mfma | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_fma3_5.lst |
69 | intrinsic_avx512_k_registers.lst | překlad zdrojového kódu intrinsic_avx512_k_registers.c s přepínačem -mavx512 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_k_registers.lst |
70 | intrinsic_avx512_vblendps.lst | překlad zdrojového kódu intrinsic_avx512_vblendps.c s přepínačem -mavx512 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_vblendps.lst |
71 | intrinsic_avx512_addps.lst | překlad zdrojového kódu intrinsic_avx512_addps.c s přepínačem -mavx512 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_addps.lst |
72 | intrinsic_avx512_compress.lst | překlad zdrojového kódu intrinsic_avx512_compress.c s přepínačem -mavx512 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_compress.lst |
73 | intrinsic_avx512_permute.lst | překlad zdrojového kódu intrinsic_avx512_permute.c s přepínačem -mavx512 | https://github.com/tisnik/presentations/blob/master/SIMD/intrinsic_avx512_permute.lst |
19. Seznam všech předchozích částí tohoto seriálu
- Užitečné rozšíření GCC: podpora SIMD (vektorových) instrukcí
https://www.root.cz/clanky/uzitecne-rozsireni-gcc-podpora-simd-vektorovych-instrukci/ - Užitečné rozšíření GCC – podpora SIMD (vektorových) instrukcí: nedostatky technologie
https://www.root.cz/clanky/uzitecne-rozsireni-gcc-podpora-simd-vektorovych-instrukci-nedostatky-technologie/ - Podpora SIMD (vektorových) instrukcí na RISCových procesorech
https://www.root.cz/clanky/podpora-simd-vektorovych-instrukci-na-riscovych-procesorech/ - Podpora SIMD operací v GCC s využitím intrinsic pro nízkoúrovňové optimalizace
https://www.root.cz/clanky/podpora-simd-operaci-v-gcc-s-vyuzitim-intrinsic-pro-nizkourovnove-optimalizace/ - Podpora SIMD operací v GCC s využitím intrinsic: technologie SSE
https://www.root.cz/clanky/podpora-simd-operaci-v-gcc-s-vyuzitim-intrinsic-technologie-sse/ - Rozšíření instrukční sady „Advanced Vector Extensions“ na platformě x86–64
https://www.root.cz/clanky/rozsireni-instrukcni-sady-advanced-vector-extensions-na-platforme-x86–64/ - Rozšíření instrukční sady F16C, FMA a AVX-512 na platformě x86–64
https://www.root.cz/clanky/rozsireni-instrukcni-sady-f16c-fma-a-avx-512-na-platforme-x86–64/
20. Odkazy na Internetu
- GCC documentation: Extensions to the C Language Family
https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions - GCC documentation: Using Vector Instructions through Built-in Functions
https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html - SSE (Streaming SIMD Extentions)
http://www.songho.ca/misc/sse/sse.html - Timothy A. Chagnon: SSE and SSE2
http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf - Intel corporation: Extending the Worldr's Most Popular Processor Architecture
http://download.intel.com/technology/architecture/new-instructions-paper.pdf - SIMD architectures:
http://arstechnica.com/old/content/2000/03/simd.ars/ - Tour of the Black Holes of Computing!: Floating Point
http://www.cs.hmc.edu/~geoff/classes/hmc.cs105…/slides/class02_floats.ppt - 3Dnow! Technology Manual
AMD Inc., 2000 - Intel MMXTM Technology Overview
Intel corporation, 1996 - MultiMedia eXtensions
http://softpixel.com/~cwright/programming/simd/mmx.phpi - AMD K5 („K5“ / „5k86“)
http://www.pcguide.com/ref/cpu/fam/g5K5-c.html - Sixth Generation Processors
http://www.pcguide.com/ref/cpu/fam/g6.htm - Great Microprocessors of the Past and Present
http://www.cpushack.com/CPU/cpu1.html - Very long instruction word (Wikipedia)
http://en.wikipedia.org/wiki/Very_long_instruction_word - CPU design (Wikipedia)
http://en.wikipedia.org/wiki/CPU_design - Bulldozer (microarchitecture)
https://en.wikipedia.org/wiki/Bulldozer_(microarchitecture) - SIMD Instructions Considered Harmful
https://www.sigarch.org/simd-instructions-considered-harmful/ - GCC Compiler Intrinsics
https://iq.opengenus.org/gcc-compiler-intrinsics/ - Scalable_Vector_Extension_(SVE)
https://en.wikipedia.org/wiki/AArch64#Scalable_Vector_Extension_(SVE) - FADD/FADDP/FIADD — Add
https://www.felixcloutier.com/x86/fadd:faddp:fiadd - ADDPS — Add Packed Single-Precision Floating-Point Values
https://www.felixcloutier.com/x86/addps - ADDPD — Add Packed Double-Precision Floating-Point Values
https://www.felixcloutier.com/x86/addpd - FDIV/FDIVP/FIDIV — Divide
https://www.felixcloutier.com/x86/fdiv:fdivp:fidiv - IDIV — Signed Divide
https://www.felixcloutier.com/x86/idiv - PADDB/PADDW/PADDD/PADDQ — Add Packed Integers
https://www.felixcloutier.com/x86/paddb:paddw:paddd:paddq - PSUBB/PSUBW/PSUBD — Subtract Packed Integers
https://www.felixcloutier.com/x86/psubb:psubw:psubd - PMULLW — Multiply Packed Signed Integers and Store Low Result
https://www.felixcloutier.com/x86/pmullw - PUNPCKLBW/PUNPCKLWD/PUNPCKLDQ/PUNPCKLQDQ — Unpack Low Data
https://www.felixcloutier.com/x86/punpcklbw:punpcklwd:punpckldq:punpcklqdq - PUNPCKHBW/PUNPCKHWD/PUNPCKHDQ/PUNPCKHQDQ — Unpack High Data
https://www.felixcloutier.com/x86/punpckhbw:punpckhwd:punpckhdq:punpckhqdq - PACKUSWB — Pack with Unsigned Saturation
https://www.felixcloutier.com/x86/packuswb - ADDPS — Add Packed Single-Precision Floating-Point Values
https://www.felixcloutier.com/x86/addps - SUBPS — Subtract Packed Single-Precision Floating-Point Values
https://www.felixcloutier.com/x86/subps - MULPS — Multiply Packed Single-Precision Floating-Point Values
https://www.felixcloutier.com/x86/mulps - DIVPS — Divide Packed Single-Precision Floating-Point Values
https://www.felixcloutier.com/x86/divps - CBW/CWDE/CDQE — Convert Byte to Word/Convert Word to Doubleword/Convert Doubleword to Quadword
https://www.felixcloutier.com/x86/cbw:cwde:cdqe - PAND — Logical AND
https://www.felixcloutier.com/x86/pand - POR — Bitwise Logical OR
https://www.felixcloutier.com/x86/por - PXOR — Logical Exclusive OR
https://www.felixcloutier.com/x86/pxor - Improve the Multimedia User Experience
https://www.arm.com/technologies/neon - NEON Technology (stránky ARM)
https://developer.arm.com/technologies/neon - SIMD Assembly Tutorial: ARM NEON – Xiph.org
https://people.xiph.org/~tterribe/daala/neon_tutorial.pdf - Ne10
http://projectne10.github.io/Ne10/ - NEON and Floating-Point architecture
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/BABIGHEB.html - An Introduction to ARM NEON
http://peterdn.com/post/an-introduction-to-ARM-NEON.aspx - ARM NEON Intrinsics Reference
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf - Arm Neon Intrinsics vs hand assembly
https://stackoverflow.com/questions/9828567/arm-neon-intrinsics-vs-hand-assembly - ARM NEON Optimization. An Example
http://hilbert-space.de/?p=22 - AArch64 NEON instruction format
https://developer.arm.com/docs/den0024/latest/7-aarch64-floating-point-and-neon/73-aarch64-neon-instruction-format - ARM SIMD instructions
https://developer.arm.com/documentation/dht0002/a/Introducing-NEON/What-is-SIMD-/ARM-SIMD-instructions - Learn the architecture – Migrate Neon to SVE Version 1.0
https://developer.arm.com/documentation/102131/0100/?lang=en - 1.2.2. Comparison between NEON technology and other SIMD solutions
https://developer.arm.com/documentation/den0018/a/Introduction/Comparison-between-ARM-NEON-technology-and-other-implementations/Comparison-between-NEON-technology-and-other-SIMD-solutions?lang=en - NEON Programmer’s Guide
https://documentation-service.arm.com/static/63299276e68c6809a6b41308 - Brain Floating Point – nový formát uložení čísel pro strojové učení a chytrá čidla
https://www.root.cz/clanky/brain-floating-point-ndash-novy-format-ulozeni-cisel-pro-strojove-uceni-a-chytra-cidla/ - Other Built-in Functions Provided by GCC
https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html - GCC: 6.60 Built-in Functions Specific to Particular Target Machines
https://gcc.gnu.org/onlinedocs/gcc/Target-Builtins.html#Target-Builtins - Advanced Vector Extensions
https://en.wikipedia.org/wiki/Advanced_Vector_Extensions - AVX-512
https://en.wikipedia.org/wiki/AVX-512 - AVX-512
https://iq.opengenus.org/avx512/ - Downclocking pro AVX-512
https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Downclocking - BLENDPS — Blend Packed Single Precision Floating-Point Values
https://www.felixcloutier.com/x86/blendps - BLENDPD — Blend Packed Double Precision Floating-Point Values
https://www.felixcloutier.com/x86/blendpd - Why Intel is betting on BFLOAT16 to be a game changer for deep learning training? Hint: Range trumps Precision
https://hub.packtpub.com/why-intel-is-betting-on-bfloat16-to-be-a-game-changer-for-deep-learning-training-hint-range-trumps-precision/ - half-rs (pro Rust)
https://github.com/starkat99/half-rs - float16 (pro Go)
https://github.com/x448/float16 - bfloat16 – Hardware Numerics Definition
https://software.intel.com/en-us/download/bfloat16-hardware-numerics-definition - Intel Prepares To Graft Google’s Bfloat16 Onto Processors
https://www.nextplatform.com/2019/07/15/intel-prepares-to-graft-googles-bfloat16-onto-processors/ - A Study of BFLOAT16 for Deep Learning Training
https://arxiv.org/pdf/1905.12322.pdf - BFloat16s.jl
https://github.com/JuliaComputing/BFloat16s.jl - Half Precision Arithmetic: fp16 Versus bfloat16
https://nhigham.com/2018/12/03/half-precision-arithmetic-fp16-versus-bfloat16/ - bfloat16 floating-point format (Wikipedia)
https://en.wikipedia.org/wiki/Bfloat16_floating-point_format - Unum (number format)
https://en.wikipedia.org/wiki/Unum_(number_format)#Posit - Performance Benefits of Half Precision Floats
https://software.intel.com/en-us/articles/performance-benefits-of-half-precision-floats - Norma IEEE 754 a příbuzní: formáty plovoucí řádové tečky
https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/ - IEEE-754 Floating-Point Conversion
http://babbage.cs.qc.cuny.edu/IEEE-754.old/32bit.html - Small Float Formats
https://www.khronos.org/opengl/wiki/Small_Float_Formats - Binary-coded decimal
https://en.wikipedia.org/wiki/Binary-coded_decimal - Floating-Point Formats
http://www.quadibloc.com/comp/cp0201.htm - Data types (SciPy)
https://docs.scipy.org/doc/numpy-1.13.0/user/basics.types.html - New 16-bit floating point type – NumPy 1.6.0 Release Notes
https://github.com/numpy/numpy/blob/7cfec2403486456b52b525eccf7541e1562d9ab3/doc/release/1.6.0-notes.rst#new-16-bit-floating-point-type - RFC pro Rust
https://github.com/joshtriplett/rfcs/blob/f16b/text/0000-f16b.md - IEEE-754 Floating Point Converter
https://www.h-schmidt.net/FloatConverter/IEEE754.html - Mediump float calculator
https://oletus.github.io/float16-simulator.js/ - IEEE 754 Calculator
http://weitz.de/ieee/ - BFloat16 (Swift for TensorFlow)
https://www.tensorflow.org/swift/api_docs/Structs/BFloat16 - Using bfloat16 with TensorFlow models
https://cloud.google.com/tpu/docs/bfloat16 - What is tf.bfloat16 “truncated 16-bit floating point”?
https://stackoverflow.com/questions/44873802/what-is-tf-bfloat16-truncated-16-bit-floating-point - BFloat16 processing for Neural Networks on Armv8-A
https://community.arm.com/developer/ip-products/processors/b/ml-ip-blog/posts/bfloat16-processing-for-neural-networks-on-armv8_2d00_a - Mixed precision training
https://arxiv.org/pdf/1710.03740.pdf - [R] Mixed Precision Training
https://www.reddit.com/r/MachineLearning/comments/75phd2/r_mixed_precision_training/ - Floating Point Numbers
https://floating-point-gui.de/formats/fp/ - Float exposed
https://float.exposed/0×40490000 - Float Toy
http://evanw.github.io/float-toy/ - IEEE-754 visualization
https://bartaz.github.io/ieee754-visualization/ - Advantages Of BFloat16 For AI Inference
https://semiengineering.com/advantages-of-bfloat16-for-ai-inference/ - ARMv8-A bude podporovat nový formát čísel BFloat16
https://www.root.cz/zpravicky/armv8-a-bude-podporovat-novy-format-cisle-bfloat16/ - Intel oznámil nový formát BFloat16 pro budoucí procesory
https://www.root.cz/zpravicky/intel-oznamil-novy-format-bfloat16-pro-budouci-procesory/ - Nový formát čísel Intelu BFloat16 bude v GCC 10 a Clang 9
https://www.root.cz/zpravicky/novy-format-cisel-intelu-bfloat16-bude-v-gcc-10-a-clang-9/ - Mixed precision
https://www.tensorflow.org/guide/keras/mixed_precision - Training Performance: A user’s guide to converge faster (TensorFlow Dev Summit 2018)
https://www.youtube.com/watch?v=SxOsJPaxHME - Programování GPU na Raspberry Pi: použití Quad Processor Unit(s)
https://www.root.cz/clanky/programovani-gpu-na-raspberry-pi-pouziti-quad-processor-unit-s/ - “Half Precision” 16-bit Floating Point Arithmetic
https://blogs.mathworks.com/cleve/2017/05/08/half-precision-16-bit-floating-point-arithmetic/ - Half Precision Arithmetic in Numerical Linear Algebra
https://nla-group.org/2018/10/03/half-precision-arithmetic-in-numerical-linear-algebra/ - Enable BF16 support
https://gcc.gnu.org/ml/gcc-patches/2019–04/msg00477.html - Survey of Floating-Point Formats
https://mrob.com/pub/math/floatformats.html - VCVTPS2PH — Convert Single-Precision FP value to 16-bit FP value
https://www.felixcloutier.com/x86/vcvtps2ph - VCVTPH2PS — Convert 16-bit FP values to Single-Precision FP values
https://www.felixcloutier.com/x86/vcvtph2ps - KMOV
https://www.felixcloutier.com/x86/kmovw:kmovb:kmovq:kmovd - KNOT
https://www.felixcloutier.com/x86/knotw:knotb:knotq:knotd - KAND
https://www.felixcloutier.com/x86/kandw:kandb:kandq:kandd - KANDN
https://www.felixcloutier.com/x86/kandnw:kandnb:kandnq:kandnd - KOR
https://www.felixcloutier.com/x86/korw:korb:korq:kord - KXOR
https://www.felixcloutier.com/x86/kxorw:kxorb:kxorq:kxord - KXNOR
https://www.felixcloutier.com/x86/kxnorw:kxnorb:kxnorq:kxnord - KORTEST
https://www.felixcloutier.com/x86/kortestw:kortestb:kortestq:kortestd - KSHIFTL
https://www.felixcloutier.com/x86/kshiftlw:kshiftlb:kshiftlq:kshiftld - KSHIFTR
https://www.felixcloutier.com/x86/kshiftrw:kshiftrb:kshiftrq:kshiftrd - KUNPCK
https://www.felixcloutier.com/x86/kunpckbw:kunpckwd:kunpckdq - VBLENDMPD
https://www.felixcloutier.com/x86/vblendmpd:vblendmps - VBLENDMPS
https://www.felixcloutier.com/x86/vblendmpd:vblendmps - VPBLENDMD
https://www.felixcloutier.com/x86/vpblendmd:vpblendmq - VPBLENDMQ
https://www.felixcloutier.com/x86/vpblendmd:vpblendmq - VPTESTMB/VPTESTMW/VPTESTMD/VPTESTMQ
https://www.felixcloutier.com/x86/vptestmb:vptestmw:vptestmd:vptestmq - VPCMPD/VPCMPUD
https://www.felixcloutier.com/x86/vpcmpd:vpcmpud - VPCMPQ/VPCMPUQ
https://www.felixcloutier.com/x86/vpcmpq:vpcmpuq - VCOMPRESSPD
https://www.felixcloutier.com/x86/vcompresspd - VCOMPRESSPS
https://www.felixcloutier.com/x86/vcompressps - VPCOMPRESSQ
https://www.felixcloutier.com/x86/vpcompressq - VPCOMPRESSD
https://www.felixcloutier.com/x86/vpcompressd - VEXPANDPD
https://www.felixcloutier.com/x86/vexpandpd - VEXPANDPS
https://www.felixcloutier.com/x86/vexpandps - VPEXPANDD
https://www.felixcloutier.com/x86/vpexpandd - VPEXPANDQ
https://www.felixcloutier.com/x86/vpexpandq - VPERMI2PD
https://www.felixcloutier.com/x86/vpermi2w:vpermi2d:vpermi2q:vpermi2ps:vpermi2pd - VPERMI2PS
https://www.felixcloutier.com/x86/vpermi2w:vpermi2d:vpermi2q:vpermi2ps:vpermi2pd - VPERMI2D
https://www.felixcloutier.com/x86/vpermi2w:vpermi2d:vpermi2q:vpermi2ps:vpermi2pd - VPERMI2Q
https://www.felixcloutier.com/x86/vpermi2w:vpermi2d:vpermi2q:vpermi2ps:vpermi2pd - VPERMT2PD
https://www.felixcloutier.com/x86/vpermt2w:vpermt2d:vpermt2q:vpermt2ps:vpermt2pd - VPERMT2PS
https://www.felixcloutier.com/x86/vpermt2w:vpermt2d:vpermt2q:vpermt2ps:vpermt2pd - VPERMT2D
https://www.felixcloutier.com/x86/vpermt2w:vpermt2d:vpermt2q:vpermt2ps:vpermt2pd - VPERMT2Q
https://www.felixcloutier.com/x86/vpermt2w:vpermt2d:vpermt2q:vpermt2ps:vpermt2pd - VSHUFF32×4
https://www.felixcloutier.com/x86/vshuff32×4:vshuff64×2:vshufi32×4:vshufi64×2 - VSHUFF64×2
https://www.felixcloutier.com/x86/vshuff32×4:vshuff64×2:vshufi32×4:vshufi64×2 - VSHUFI32×4
https://www.felixcloutier.com/x86/vshuff32×4:vshuff64×2:vshufi32×4:vshufi64×2 - VSHUFI64×2
https://www.felixcloutier.com/x86/vshuff32×4:vshuff64×2:vshufi32×4:vshufi64×2 - VPDPBUSD
https://www.felixcloutier.com/x86/vpdpbusd - VPDPBUSDS
https://www.felixcloutier.com/x86/vpdpbusds - VPDPWSSD
https://www.felixcloutier.com/x86/vpdpwssd - VPDPWSSDS
https://www.felixcloutier.com/x86/vpdpwssds