Autor: | Wojciech Muła |
---|---|
Dodany: | 22.07.2002 |
Aktualizacja: | 21.05.2003 |
Dana jest macierz M 4x4:
[a0 a1 a2 a3] [b0 b1 b2 b3] [c0 c1 c2 c3] [d0 d1 d2 d3]
Wyznacznik liczymy z rozwinięcia Laplace'a:
detM = a0*b1*c2*d3 - a0*b1*c3*d2 - a0*b2*c1*d3 + a0*b2*c3*d1 + a0*b3*c1*d2 - a0*b3*c2*d1 - a1*b0*c2*d3 + a1*b0*c3*d2 + a1*b2*c0*d3 - a1*b2*c3*d0 - a1*b3*c0*d2 + a1*b3*c2*d0 + a2*b0*c1*d3 - a2*b0*c3*d1 - a2*b1*c0*d3 + a2*b1*c3*d0 + a2*b3*c0*d1 - a2*b3*c1*d0 - a3*b0*c1*d2 + a3*b0*c2*d1 + a3*b1*c0*d2 - a3*b1*c2*d0 - a3*b2*c0*d1 + a3*b2*c1*d0
Po wyciągnięciu przed nawiasy otrzymujemy:
detM = (a0*b1-a1*b0)*(c2*d3-c3*d2) + (a2*b0-a0*b2)*(c1*d3-c3*d1) + (a0*b3-a3*b0)*(c1*d2-c2*d1) + (a1*b2-a2*b1)*(c0*d3-c3*d0) + (a2*b3-a3*b2)*(c0*d1-c1*d0) + (a3*b1-a1*b3)*(c0*d2-c2*d0)
W wyjściowym wzorze należało wykonać 72 mnożenia i 23 dodawania, po uproszczeniu liczby te zredukowały się odpowiednio do 24 i 17.
Oto „fragment” powyższego równania, który doskonale nadaje się do wektoryzacji:
(a0*b1-a1*b0) [x0] (a2*b0-a0*b2) = [x1] (a0*b3-a3*b0) [x2] (a1*b2-a2*b1) [x3] A' B' A”B”
Jeśli dane są wektory A = [a0, a1, a2, a3] oraz B = [b0, b1, b2, b3], to wyrażenie można opisać jako: X = A' ⋅ B' − A” ⋅ B”, gdzie A', B', itd. to wektory A, B z odpowiednio przestawionymi elementami. Ponieważ indeksy w A' i B” oraz A” i B' są takie same, wystarczą zatem dwa argumenty definiujące rozmieszczenie elementów.
macro.mac:
; makro oblicza wyrażenie wektorowe A'B'-A”B” ; %1 - wektor A ; %2 - wektor B ; %3 - stała dla rozkazu shufps która wygeneruje wektory A' i B” ; %4 - stała dla rozkazu shufps która wygeneruje wektory B' i A” ; %5, %6 - rejestry robocze -- niszczone ; %7 - rejestr wynikowy %macro calc 7 movaps %7, %1 movaps %6, %2 shufps %7, %3 ; A' shufps %6, %4 ; B' mulps %7, %6 ; %7 := A'B' movaps %5, %1 movaps %6, %2 shufps %5, %4 ; A” shufps %6, %3 ; B” mulps %6, %5 ; %6 := A”B” subps %7, %6 ; %7 := A'B' - A”B” %endmacro
Chciałbym zwrócić uwagę na jedną rzecz. Mianowicie w przytoczonym „fragmencie” wzoru wektor A” można otrzymać z wektora A', przez co jeden z rozkazów movaps staje się zbędny.
Do generowania stałej dla rozkazu shufps proponuję utworzyć makrodefinicję, dzięki czemu kod stanie się przejrzystszy; może ona wyglądać tak:
macro.mac:
; xmm = |d|c|b|a| %define sh(d,b,c,a) (((d&3) << 6) | ((c&3) << 4) | ((b&3) << 2) | ((a&3) << 0))
Żeby maksymalnie wykorzystać moc obliczeniową należy obliczać wyznaczniki dwóch macierzy jednocześnie. Ramką zostały otoczone wyrażenia obliczane przez makro calc.
I II +-------------+ +-------------+ detM1 = |(a0*b1-a1*b0)|*|(c2*d3-c3*d2)| + |(a2*b0-a0*b2)|*|(c1*d3-c3*d1)| + => xmm3 4 |(a0*b3-a3*b0)|*|(c1*d2-c2*d1)| + |(a1*b2-a2*b1)|*|(c0*d3-c3*d0)| + +-------------+ +-------------+ III IV +-------------+ +-------------+ |(a2*b3-a3*b2)|*|(c0*d1-c1*d0)| + |(a3*b1-a1*b3)|*|(c0*d2-c2*d0)| => xmm4 5 detM2 = |(e2*f3-e3*f2)|*|(g0*h1-g1*h0)| + |(e3*f1-e1*f3)|*|(g0*h2-g2*h0)| + +-------------+ +-------------+ V VI +-------------+ +-------------+ |(e0*f1-e1*f0)|*|(g2*h3-g3*h2)| + |(e2*f0-e0*f2)|*|(g1*h3-g3*h1)| + => xmm5 7 |(e0*f3-e3*f0)|*|(g1*h2-g2*h1)| + |(e1*f2-e2*f1)|*|(g0*h3-g3*h0)| +-------------+ +-------------+
sse_det4x4.asm:
; esi+0x00 -> a0 a1 a2 a3 = A ; esi+0x10 -> b0 b1 b1 b3 = B ; esi+0x20 -> c0 c1 c2 c3 = C ; esi+0x30 -> d0 d1 d2 d3 = D ; edi+0x00 -> e0 e1 e2 e3 = E ; edi+0x10 -> f0 f1 f2 f3 = F ; edi+0x20 -> g0 g1 g2 g3 = G ; edi+0x30 -> h0 h1 h2 h3 = H ; rejestry robocze: xmm6, xmm7 ; xmm3 = wektor I movups xmm0, [esi+0x00] ; A movups xmm1, [esi+0x10] ; B calc xmm0, xmm1, sh(1,0,2,0), sh(2,3,0,1), xmm6, xmm7, xmm3 ; xmm4 = wektor II movups xmm0, [esi+0x20] ; C movups xmm1, [esi+0x30] ; D calc xmm0, xmm1, sh(0,1,1,2), sh(3,2,3,3), xmm6, xmm7, xmm5 ; xmm3 *= xmm4 (wektor I * wektor II) mulps xmm3, xmm4 ; xmm5 = wektor V movups xmm0, [edi+0x00] ; E movups xmm1, [edi+0x10] ; F calc xmm0, xmm1, sh(1,0,2,0), sh(2,3,0,1), xmm6, xmm7, xmm5 ; xmm4 = wektor VI movups xmm0, [edi+0x20] ; G movups xmm1, [edi+0x30] ; H calc xmm0, xmm1, sh(0,1,1,2), sh(3,2,3,3), xmm6, xmm7, xmm4 ; xmm5 *= xmm4 (wektor V * wektor VI) mulps xmm3, xmm4 ; xmm2 = wektor III movups xmm0, [esi+0x00] ; A-E shufps xmm0, [edi+0x00], sh(3,2,3,2) movups xmm1, [esi+0x10] ; B-F shufps xmm1, [edi+0x10], sh(1,3,1,3) calc xmm0, xmm1, sh(3,2,1,0), sh(3,2,1,0), xmm6, xmm7, xmm2 ; xmm4 = wektor IV movups xmm0, [esi+0x20] ; C-G shufps xmm0, [edi+0x20], sh(0,0,0,0) movups xmm1, [esi+0x30] ; D-H shufps xmm1, [edi+0x30], sh(2,1,2,1) calc xmm0, xmm1, sh(3,2,1,0), sh(3,2,1,0), xmm6, xmm7, xmm4 ; xmm4 *= xmm2 (wektor III * wektor IV) mulps xmm4, xmm2 ; teraz sytuacja przedstawia się następująco: ; ; | mm3 | mm4 | mm5 | ; |M11 M12 M13 M14|M15 M16|M21 M22|M23 M24 M25 M26| ; ; detM1 = M11+...+M16, detM2 = M21+...+M26 movaps xmm0, xmm5 shufps xmm0, xmm3, sh(1,0,3,2) ; xmm0 = |M13 M14|M23 M24| shufps xmm5, xmm3, sh(3,2,1,0) ; xmm5 = |M11 M12|M25 M26| ; xmm4 = |M15 M16|M21 M22| addps xmm0, xmm4 addps xmm0, xmm5 ; xmm0 = |M1' M1”|M2' M2”| movaps xmm1, xmm0 shufps xmm1, xmm1, sh(2,3,0,1) ; xmm1 = |M1” M1' |M2” M2' | addps xmm0, xmm1 ; xmm0 = |detM1 detM1|detM2 detM2|