Mnożenie rejestru MMX razy Single Precision Float w Asemblerze

0

Cześć, mam następujący problem:
Piszę program który nakłada filtry na bitmapy, żeby przyśpieszyć jego działanie postanowiłem napisać go w ASM-ie, i generalnie wczytuję sobie dane i dzielę na 3 rejestry MMX tak że dziele to kolorami czyli do 1 rejestru przychodzi 8 bajtów koloru czerwonego, do innego 8 bajtów koloru zielonego itp.
W rejestrze XMM0 wstawiam 8 Bajtów danych, rozpakowywuję te 8 Bajtów na 8 słów do rejestru XMM0 (pmovzxbw xmm1, xmm0), dzięki temu w rejestrze XMM1 widzę ję jako np. m128_i16 = {116, 117, 118, 120, 123, 122, 120, 118}. Chciałbym każdą z tych danych pomnożyć przez współczynnik np 0,299, próbuję to robić wszystkimi możliwymi mnożeniami ale za każdym razem wynik końcowy nie jest taką reprezentacją jaką oczekuję czyli mnożąc każdy bajt rejestru oczekiwałbym wyniku w debugerze m128_i16 * 0,299 = {35, 35, 35, 36, 37, 36, 36, 35}. Generalnie nie wiem czy może to trzeba podzielić na 2 rejestry XMM, żeby mnożyć przez single precision float, w sumie kończą mi się pomysły. Będę wdzięczny za każdą podpowiedź :)

0

Piszę program który nakłada filtry na bitmapy
w czym?

żeby przyśpieszyć jego działanie postanowiłem napisać go w ASM-ie
lepiej jednak użyć tzw. compiler intrinsics, Visual C++ coś takiego ma, GCC zdaje się też: odpowiednie funkcje do zabawy z SIMD bez męczenia się asmem.

W rejestrze XMM0
rejestry XMM to jest SSE. to w końcu zdecyduj się, czy MMX czy SSE/2/3/itd.

Chciałbym każdą z tych danych pomnożyć przez współczynnik np 0,299
ładujesz liczby całkowite a potem chcesz traktować je jak floaty. to tak nie działa. musisz załadować liczby jako float i dopiero mnożyć.

0

No generalnie piszę w VS 2015, i niestety muszę męczyć się z ASMem bo prowadzący mają swoje widzimisie, używam SSE. W zasadzie myślę że wystarczy coś takiego:
.DATA
dlr dd 0.299

.CODE
movq XMM0, QWORD PTR [rleft] ; wczytanie 128-bitów z tablicy źródłowej dla koloru czerwonego do rej. XMM 0
pmovzxbw xmm1, xmm0 ; rozpakowanie 8 -bajtów na 8 słów
movss xmm9, dword ptr[dlr] ;przepisanie dworda do xmm9
shufps xmm9, xmm9, 0 ;0.299 jest na 2 bajtach, propagujemy je na pozostałe 6
MOVLHPS xmm7, xmm1 ;przenosimy do xmm7 dolną połówkę xmm1
MOVHLPS xmm8, xmm1 ; górną do xmm8
MOVHLPS xmm7, xmm7 ; w xmm7 przenosimy bajty z górnej połówki na dolną
pmovzxbw xmm7, xmm7 ;rozpakowanie tych 4 bajtów z dolnej połówki na postać {x, 0, x, 0, x, 0, x, 0} w xmm7
pmovzxbw xmm8, xmm8 ;rozpakowanie tych 4 bajtów z dolnej połówki na postać {x, 0, x, 0, x, 0, x, 0} w xmm8
mulps xmm7, xmm9 ;mnożymy xmm7 przez floaty w xmm9
mulps xmm8, xmm9 ;to samo na xmm8
packuswb xmm7, xmm7 ;pakujemy z powrotem liczby w xmm7 czyli: {x, 0, x, 0, x, 0, x, 0} do postaci {x, x, x, x, 0, 0, 0, 0}
packuswb xmm8, xmm8 ;dokładnie to samo w xmm8
movlhps xmm7, xmm8 ;przenosimy dolną półwke z xmm8 do xmm7 czyli mamy wszystkie bity zajęte
movaps xmm1, xmm7 ;przepisujemy wynik do xmm1

generalnie mi to działa, wynik pokazuje taki jak chciałem uzyskać, choć cechuje się to dość sporym błędem obliczeniowym
np wynik BYTE może się wahać w granicach od -1 do 1, czyli jak powinno być np 127 to może być równie dobrze 126 jak i 128
taka rozbieżność wyniku jest nawet do zaakceptowania, ale każdy dąży do perfekcji więc w teraz będę myślał jak ten kod udoskonalić bo na razie przez to że dzielę wektory to efektywność tego algorytmu spadła o połowę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1