2016-11-16 10 views
7

Jaki jest najlepszy sposób na załadowanie i zapisanie rejestrów celów generowania do/z rejestrów SIMD? Do tej pory używam tego stosu jako tymczasowy. Na przykład,Najlepszy sposób na załadowanie/zapisanie z/do rejestrów ogólnego przeznaczenia do/z rejestru xmm/mmm

mov [rsp + 0x00], r8 
mov [rsp + 0x08], r9 
mov [rsp + 0x10], r10 
mov [rsp + 0x18], r11 
vmovdqa ymm0, [rsp] ; stack is properly aligned first. 

Nie sądzę, jest jakaś instrukcja może to zrobić bezpośrednio (lub inny kierunek), ponieważ oznaczałoby to dyspozycję z pięciu argumentów. Jednak powyższy kod wydaje mi się głupi. Czy istnieje lepszy sposób na zrobienie tego? Mogę tylko wymyślić jedną alternatywę, skorzystam z pinsrd i pokrewnych instrukcji. Ale to nie wydaje się być lepsze.

Motywacją jest to, że czasami szybciej jest robić pewne rzeczy w AVX2, podczas gdy inne mają rejestr ogólnego przeznaczenia. Na przykład, powiedzmy w małym kawałku kodu, istnieją cztery 64-bitowe liczby całkowite bez znaku, potrzebuję czterech xor, dwóch mulx z BMI2. Szybsze będzie wykonywanie xor z vpxor, jednak nie ma ono odpowiednika AVX2. Jakakolwiek wydajność wzmocnienia vpxor vs 4 xor jest tracona z powodu procesu pakowania i rozpakowywania.

Odpowiedz

5

Czy Twoje opóźnienie, przepustowość lub zlewozmywak w domenie topowej jest skrócony? Jeśli jest to opóźnienie, to przechowywanie/przeładowanie jest straszne, ze względu na przechowalnię składowania z wąskich magazynów do dużego ładunku.

W przypadku przepustowości i topologii w domenie bezpiecznej nie jest to straszne: wystarczy 5 zgubionych domen, upuszczenie w porcie sklepu. Jeśli otaczający kod jest w większości zbiorem ALU, warto wziąć pod uwagę.


Dla użytkowej przypadku proponujemy:

wydając dużo instrukcje/UOPs na przenoszenie danych pomiędzy całkowitymi i wektorowych regs jest zazwyczaj zły pomysł. PMULUDQ daje ekwiwalent 32-bitowego mulxa, ale masz rację, że 64-bitowe mnożenia nie są dostępne bezpośrednio w AVX2. (AVX512 je ma).

Można wykonać wektor 64-bitowy mnożąc przy użyciu zwykłej techniki precyzyjnej precyzji za pomocą PMULUDQ. Moja odpowiedź na temat Fastest way to multiply an array of int64_t? wykazała, że ​​wektoryzacja mnożników 64 x 64 => 64b była warta z wektorami AVX2 256b, ale nie z wektorami 128b. Ale to było z danymi w pamięci, a nie z danymi zaczynającymi się i kończącymi w wektorowych regach.

W tym przypadku może być warte budowania rozmiarach 64x64 => 128B pełny mnożenie z wielokrotnym 32x32 => 64-bitowy wektor mnoży, ale może to zająć wiele wskazówek, że to nie jest po prostu warto. Jeśli potrzebujesz wyników w górnej połowie, rozpakowanie do skalaru (lub wykonanie całego skalaru) może być najlepsze.

Integer XOR jest niezwykle tani, z doskonałym ILP (opóźnienie = 1, przepustowość = 4 na zegar). Zdecydowanie nie warto przenosić danych do wektorowych regów tylko po to, aby je XOR, jeśli nie masz w tym nic bardziej wektorowego. Zobacz linki do wydajności w zakresie tag wiki.


Prawdopodobnie najlepszym sposobem na opóźnienia jest:

vmovq xmm0, r8 
vmovq xmm1, r10   # 1uop for p5 (SKL), 1c latency 
vpinsrq xmm0, r9, 1   # 2uops for p5 (SKL), 3c latency 
vpinsrq xmm1, r11, 1 
vinserti128 ymm0, ymm0, ymm1, 1 # 1uop for p5 (SKL), 3c latency 

Razem: 7 UOPs do P5, z wystarczającą ILP uruchomić je prawie wszystkie back-to-back. Ponieważ prawdopodobnie r8 będzie gotowy o dwa lub więcej cykli wcześniej niż r10, nie tracisz zbyt wiele.


również warte rozważenia: cokolwiek robisz, aby produkować r8..r11, zrób to z instrukcji wektorowych liczbą całkowitą, więc dane są już w regs xmm. Następnie nadal trzeba je potasować, używając 2x PUNPCKLQDQ i VINSERTI128.

+0

Dzięki za szczegółową odpowiedź ponownie. 'xor' jest prawdopodobnie złym przykładem. Faktem jest, że wszystko oprócz 'mulx' może być wykonane z AVX2. Jednak nie wystarczy uzasadnić koszt załadunku/sklepu. Poza tym ładowanie z YMM do r/64 będzie wymagało kilku tasowań/permutacji lub 'pextrq' itd. Chociaż niektóre opóźnienia mogą być ukryte przez przetwarzanie wielu bloków (YMM) w iteracji jednej pętli. Myślę, że muszę po prostu eksperymentować i sam się przekonać. –

+0

@YanZhou: YMM-> liczba całkowita ze składowaniem/ponownym załadowaniem jest znacznie niższym opóźnieniem niż w przeciwnym kierunku, ponieważ przekazywanie do sklepu działa z wyrównanego szerokiego sklepu do wąskich obciążeń, które w pełni pokrywają się z nim. Ponadto obciążenia mają dwukrotnie większą przepustowość niż sklepy. Możliwe, że wydobycie do skalaru na coś może być tego warte, jeśli jest wystarczająco dużo pracy wektorowej. –

+0

@YanZhou: Och, właśnie przypomniałem sobie, że budowanie 64-bitowego wektora mnożącego się z 32-bitowych wektorów mnożnikowych może faktycznie być bardziej wydajne niż przejście do skalarnego iz powrotem. Zobacz [moja odpowiedź na to pytanie] (http://stackoverflow.com/questions/37296289/fastest-way-to-multiply-an-array-of-int64-t) dla wydajnego wektora 64 x 64 => 64bit . Jeśli potrzebujesz wyników w górnej połowie dla wektora 64 x 64 => 128-bitowego, pomnóż, zajmie to dodatkowe instrukcje. (Zapomniałem o ile więcej pracy, może za dużo.) –

Powiązane problemy