AVX2

Z HPM wiki
Přejít na: navigace, hledání

AVX2 v červnu roku 2013[1] doplnilo stávající AVX instrukce. Rozšiřuje na 256 bitů i celočíselné operace. Přináší také zcela nový způsob indexování pole polem, který můžete znát z Matlabu, ale přímo v hardwarové implementaci je to opravdu překvapivé.

Co bude po AVX2? Intel Xeon Phi coprocessor používá 32 ZMM registrů šířky 512 bitů, třeba se v budoucnosti s tímto rozšířením setkáme v PC. (Jistě jste poznali, že je to reinkarnace Larrabee.) V roce 2015 tu mělo být AVX-512, bude až v 2016...

Intel Intrinsics Guide - výborná dokumentace všech intrinsics

gigantický plakát na stěnu se všemi intrinsics až po AVX2, docela přehledný

Obsah

Příklady instrukcí

Čistě vertikální operace s 16 celými čísly délky 16 bitů

Tyto operace používají registry délky 256 bitů jako 16 zcela nezávislých celých čísel délky 16 bitů. Operace se provede se stejnolehlými šestnáctibitovými čísly - provede se 16 operací, které se vzájemně nijak neovlivňují. Zatímco u AVX bylo jasné, že 8 čísel typu float je správná volba, protože celočíselné operace stále nešly dělat s 256 bity najednou, u AVX2 už to jde a často budeme zvažovat, zda nepohodlné řešení výpočtů ve fixed-pointu nebude rychlejší.

_mm256_mulhrs_epi16 VPMULHRSW (((a * b) >>14) + 1)>>1
_mm256_mullo_epi16 vpmullw a * b
_mm256_mulhi_epu16 VPMULHUW (a * b) >>16
_mm256_mulhi_epi16 VPMULHW (a * b) >>16
_mm256_add_epi16 VPADDW a + b
_mm256_adds_epi16 VPADDSW ssat(a + b)
_mm256_adds_epu16 VPADDUSW usat(a + b)
_mm256_abs_epi16 VPABSW abs( a )
_mm256_avg_epu16 vpavgw (a + b + 1) >> 1
_mm256_cmpeq_epi16 vpcmpeqw a == b ? 0xFFFF : 0
_mm256_cmpgt_epi16 vpcmpgtw a > b ? 0xFFFF : 0
_mm256_maddubs_epi16 vpmaddubsw sat(ah * bh + al * bl)
_mm256_max_epi16 vpmaxsw max(a, b)
_mm256_max_epu16 vpmaxuw max(a, b)
_mm256_min_epi16 vpminsw min(a, b)
_mm256_min_epu16 vpminuw min(a, b)
_mm256_sign_epi16 vpsignw a * sign( b )
_mm256_sll_epi16 vpsllw a << count
_mm256_slli_epi16 vpsllw a << imm8
_mm256_sra_epi16 vpsraw a >> count
_mm256_srai_epi16 vpsraw a >> imm8
_mm256_srl_epi16 vpsrlw a >> count
_mm256_srli_epi16 vpsrlw a >> imm8
_mm256_sub_epi16 vpsubw a - b
_mm256_subs_epi16 vpsubsw ssat(a - b)
_mm256_subs_epu16 vpsubusw usat(a - b)

Čistě vertikální operace s 32 byty

Tyto operace používají registry délky 256 bitů jako 32 zcela nezávislých čísel délky 8 bitů. Operace se provede se stejnolehlými byty - provede se 32 operací, které se vzájemně nijak neovlivňují.

_mm256_blendv_epi8 VPBLENDVB c < 0 ? a : b

"Cross-lane" operace

Většina AVX2 operací s registry délky 256 bitů dělá totéž s horními polovinami registrů i s dolními, přičemž se horní a dolní poloviny nijak neovlivňují. Hardware je tak jednodušší, protože data při provádění instrukce procházejí cestami ("lane") šířky jen 128 bitů (logické obvody umožňují přesuny dat v rámci cesty, a vzájemných propojení je pro užší cestu podstatně méně). Také je tak snazší upravovat AVX programy pro AVX2, protože řada operací dělá to samé, jenom dvakrát. Výjimku tvoří třeba instrukce VPMOVZXBW a VPMOVSXBW, která jednotlivé byty z dolních 128 bitů rozšíří (doplněním nulami či rozšířením znaménka) na šestnáctibitová čísla v celých 256 bitech. Dochází tedy k přesunu mezi cestami šířky 128 bitů, "cross-lane".

Další je VPERMD - umožňuje ve 256 bitech libovolně přemístit každé z 8 čísel délky 32 bitů. Je možná libovolná permutace a každé z čísel může být ve výsledku i několikrát. Totéž dělá VPERMPS, ale čísla jsou považována za FP (i když jde o stejnou operaci, může být ta správná rychlejší).

Operace s normálními registry

AVX2 přidává i několik instrukcí, které pracují s běžnými registry délky 32 nebo 64 bitů. Kromě variací na téma "count leading zeros" jsou to i velmi zajímavé instrukce PEXT (Parallel Bits Extract), která umožňuje podle masky vybrat libovolné jednotlivé bity a umístit je do nejnižších bitů výsledku, a PDEP (Parallel Bits Deposit), která naopak bity libovolně rozmístí:

PEXT.pngPDEP.png

Indexování polem

Matlab/Octave umožňuje získat část pole indexem ve tvaru from:to, například:

octave> x=[2 3 5 7 11 13 17 19];
octave> x(2:4)
ans =
   3   5   7

Málokdo si ale uvědomuje, že index je tu také pole, jen obvykle naplněné řadou čísel jdoucích po sobě:

octave> 2:4
ans =
  2  3  4

Indexování tedy můžeme použít i obecněji:

octave> x([8 1 3])
ans =
   19    2    5

AVX2 zavádí operace, které dělají něco podobného, například VGATHERDPS.

Floating point v 16 bitech

Instrukce VCVTPS2PH a VCVTPH2PS převádějí čísla typu float (32 bitů, PS) na úspornou reprezentaci v 16 bitech (PH) a zpět (osm převodů najednou). Žádné instrukce přímo s tímto kratším formátem výpočty neprovádějí, je použitelný jen pro úsporné (a méně přesné) uložení dat. (Výpočty přímo s tímto formátem provádějí některé grafické karty, první taková byla GeForce FX.) Tyto instrukce Intel přidal už do procesoru Ivy Bridge, který má jen AVX. Pokud ale chcete mít jen verze procedur pro AVX a pro AVX2, můžete je pro jednoduchost považovat za součást AVX2.

#include <stdio.h>
#include <immintrin.h>
#include <f16cintrin.h>

/*
gcc -march=core-avx-i x.c -o x && ./x   ... this works on MacBook Air

__m256 _mm256_cvtph_ps (__m128i a)
__m128i _mm256_cvtps_ph (__m256 a, int rounding)

rounding:
 (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) to nearest (and suppress exceptions)
 (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC)     down
 (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC)     up
 (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC)        truncate
 _MM_FROUND_CUR_DIRECTION                       use MXCSR.RC; see _MM_SET_ROUNDING_MODE
*/

typedef union {
  float f[ 8 ];
  int i[ 8 ];
  __m256 v;
} YMM;

typedef union {
  short s[ 8 ];
  __m128i v;
} SMM;

main(){
  YMM f32 = {0.00001,0.1,1,4,50,60000,65535,80000};
  SMM f16;
  int i;
  printf("test 16bit float conversions\n");
  f16.v = _mm256_cvtps_ph ( f32.v, (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC));
  f32.v = _mm256_cvtph_ps ( f16.v );
  for( i=0; i<8; i++ ){
    printf("%g ", f32.f[i]);
  }
  return 0;
}

A toto je výstup:

test 16bit float conversions
1.00136e-05 0.0999756 1 4 50 60000 inf inf

AVX2 s gcc pod Linuxem

Potřebujete alespoň gcc verze 4.7.

Osobní nástroje
Jmenné prostory
Varianty
Akce
Navigace
Nástroje