261 lines
6.4 KiB
ArmAsm
261 lines
6.4 KiB
ArmAsm
# Jan Potocki 2020
|
|
|
|
.globl filter
|
|
.type filter, @function
|
|
|
|
.data
|
|
# Pozwala uzyc rozkazu movdqa zamiast movdqu
|
|
.align 16
|
|
|
|
# Macierz k w 4 kopiach - do rejestru xmm zmiescimy dane dla 4 pikseli splotu
|
|
# 1. wiersz macierzy dopelniony do 32 bitow
|
|
kernel128_1:
|
|
.byte -1, -1, 0, 0
|
|
.byte -1, -1, 0, 0
|
|
.byte -1, -1, 0, 0
|
|
.byte -1, -1, 0, 0
|
|
# 2. wiersz macierzy dopelniony do 32 bitow
|
|
kernel128_2:
|
|
.byte -1, 0, 1, 0
|
|
.byte -1, 0, 1, 0
|
|
.byte -1, 0, 1, 0
|
|
.byte -1, 0, 1, 0
|
|
# 3. wiersz macierzy dopelniony do 32 bitow
|
|
kernel128_3:
|
|
.byte 0, 1, 1, 0
|
|
.byte 0, 1, 1, 0
|
|
.byte 0, 1, 1, 0
|
|
.byte 0, 1, 1, 0
|
|
|
|
# Stala na potrzeby normalizacji - wartosc splotu z k miesci sie w przedziale
|
|
# od 3*(-1*255) do 3*(1*255) czyli <-765,765>, wiec dodanie 765 pozwoli
|
|
# przesunac ja w przedzial <0,1530>.
|
|
# Na tym etapie obliczen liczby beda zapisane w 16-bitowej reprezentacji.
|
|
bias128: .word 765, 765, 765, 765, 765, 765, 765, 765
|
|
|
|
# Argumenty:
|
|
# rdi - adres M
|
|
# rsi - adres W
|
|
# rdx - rozdzielczosc w poziomie
|
|
# rcx - rozdzielczosc w pionie
|
|
|
|
.text
|
|
|
|
filter:
|
|
push %rbp
|
|
mov %rsp, %rbp
|
|
push %r15
|
|
push %r14
|
|
push %r13
|
|
push %r12
|
|
|
|
# r15 - warunek stopu dla petli SIMD, tyle ile zmiesci sie w wierszu
|
|
mov %rdx, %r15
|
|
sub $17, %r15
|
|
# r14 - warunek stopu dla petli indeksujacej wiersze
|
|
mov %rcx, %r14
|
|
sub $2, %r14
|
|
# r12 - warunek stopu dla petli pomocniczej, dokonczenie wiersza
|
|
mov %rdx, %r12
|
|
sub $2, %r12
|
|
# ...w tej implementacji skrajne piksele obrazu wynikowego pomijamy
|
|
|
|
# Wpisanie stalych do rejestrow aby przyspieszyc obliczenia
|
|
movdqa bias128, %xmm12
|
|
movdqa kernel128_1, %xmm13
|
|
movdqa kernel128_2, %xmm14
|
|
movdqa kernel128_3, %xmm15
|
|
|
|
# r9 - pomocniczy indeks adresujacy wiersze w pamieci
|
|
xor %r9, %r9
|
|
# r10 - indeks rozdzielczosci pionowej (wierszy)
|
|
xor %r10, %r10
|
|
|
|
# Petla indeksujaca wiersze
|
|
lp1:
|
|
# r11 - indeks rozdzielczosci poziomej (pikseli w wierszu)
|
|
xor %r11, %r11
|
|
|
|
# Podstawowa petla SIMD (16 pikseli na iteracje)
|
|
lp2:
|
|
# r8 - adres pikseli w pamieci (suma adresu wiersza i indeksu pikseli)
|
|
mov %r9, %r8
|
|
add %r11, %r8
|
|
|
|
# Instrukcja pinsrd kopiuje 4 kolejne 8-bitowe piksele do fragmentu xmm,
|
|
# czyli tyle ile trzeba aby obliczyc splot z jednym wierszem k. Ostatni piksel
|
|
# zachodzi na pierwszy kolejnego splotu - to nie ma znaczenia, bo kazdy wiersz
|
|
# macierzy k jest do 32-bitowej postaci dopelniony zerem na ostatnim bajcie.
|
|
# Instrukcja pmaddubsw oblicza iloczyn 8-bitowych pikseli obrazu i wartosci
|
|
# kernela, sumuje dwa sasiednie iloczyny i w ich miejsce zapisuje wynik
|
|
# w 16-bitowej reprezentacji U2.
|
|
|
|
# Gorny wiersz macierzy k
|
|
pinsrd $0, 0(%rdi, %r8, 1), %xmm0
|
|
pinsrd $1, 1(%rdi, %r8, 1), %xmm0
|
|
pinsrd $2, 2(%rdi, %r8, 1), %xmm0
|
|
pinsrd $3, 3(%rdi, %r8, 1), %xmm0
|
|
pmaddubsw %xmm13, %xmm0
|
|
|
|
pinsrd $0, 4(%rdi, %r8, 1), %xmm1
|
|
pinsrd $1, 5(%rdi, %r8, 1), %xmm1
|
|
pinsrd $2, 6(%rdi, %r8, 1), %xmm1
|
|
pinsrd $3, 7(%rdi, %r8, 1), %xmm1
|
|
pmaddubsw %xmm13, %xmm1
|
|
|
|
pinsrd $0, 8(%rdi, %r8, 1), %xmm6
|
|
pinsrd $1, 9(%rdi, %r8, 1), %xmm6
|
|
pinsrd $2, 10(%rdi, %r8, 1), %xmm6
|
|
pinsrd $3, 11(%rdi, %r8, 1), %xmm6
|
|
pmaddubsw %xmm13, %xmm6
|
|
|
|
pinsrd $0, 12(%rdi, %r8, 1), %xmm7
|
|
pinsrd $1, 13(%rdi, %r8, 1), %xmm7
|
|
pinsrd $2, 14(%rdi, %r8, 1), %xmm7
|
|
pinsrd $3, 15(%rdi, %r8, 1), %xmm7
|
|
pmaddubsw %xmm13, %xmm7
|
|
|
|
add %rdx, %r8
|
|
# Przechowanie adresu srodkowego wiersza na pozniej, do zapisu wyniku splotu
|
|
mov %r8, %r13
|
|
|
|
# Srodkowy wiersz macierzy k
|
|
pinsrd $0, 0(%rdi, %r8, 1), %xmm2
|
|
pinsrd $1, 1(%rdi, %r8, 1), %xmm2
|
|
pinsrd $2, 2(%rdi, %r8, 1), %xmm2
|
|
pinsrd $3, 3(%rdi, %r8, 1), %xmm2
|
|
pmaddubsw %xmm14, %xmm2
|
|
|
|
pinsrd $0, 4(%rdi, %r8, 1), %xmm3
|
|
pinsrd $1, 5(%rdi, %r8, 1), %xmm3
|
|
pinsrd $2, 6(%rdi, %r8, 1), %xmm3
|
|
pinsrd $3, 7(%rdi, %r8, 1), %xmm3
|
|
pmaddubsw %xmm14, %xmm3
|
|
|
|
pinsrd $0, 8(%rdi, %r8, 1), %xmm8
|
|
pinsrd $1, 9(%rdi, %r8, 1), %xmm8
|
|
pinsrd $2, 10(%rdi, %r8, 1), %xmm8
|
|
pinsrd $3, 11(%rdi, %r8, 1), %xmm8
|
|
pmaddubsw %xmm14, %xmm8
|
|
|
|
pinsrd $0, 12(%rdi, %r8, 1), %xmm9
|
|
pinsrd $1, 13(%rdi, %r8, 1), %xmm9
|
|
pinsrd $2, 14(%rdi, %r8, 1), %xmm9
|
|
pinsrd $3, 15(%rdi, %r8, 1), %xmm9
|
|
pmaddubsw %xmm14, %xmm9
|
|
|
|
add %rdx, %r8
|
|
|
|
# Dolny wiersz macierzy k
|
|
pinsrd $0, 0(%rdi, %r8, 1), %xmm4
|
|
pinsrd $1, 1(%rdi, %r8, 1), %xmm4
|
|
pinsrd $2, 2(%rdi, %r8, 1), %xmm4
|
|
pinsrd $3, 3(%rdi, %r8, 1), %xmm4
|
|
pmaddubsw %xmm15, %xmm4
|
|
|
|
pinsrd $0, 4(%rdi, %r8, 1), %xmm5
|
|
pinsrd $1, 5(%rdi, %r8, 1), %xmm5
|
|
pinsrd $2, 6(%rdi, %r8, 1), %xmm5
|
|
pinsrd $3, 7(%rdi, %r8, 1), %xmm5
|
|
pmaddubsw %xmm15, %xmm5
|
|
|
|
pinsrd $0, 8(%rdi, %r8, 1), %xmm10
|
|
pinsrd $1, 9(%rdi, %r8, 1), %xmm10
|
|
pinsrd $2, 10(%rdi, %r8, 1), %xmm10
|
|
pinsrd $3, 11(%rdi, %r8, 1), %xmm10
|
|
pmaddubsw %xmm15, %xmm10
|
|
|
|
pinsrd $0, 12(%rdi, %r8, 1), %xmm11
|
|
pinsrd $1, 13(%rdi, %r8, 1), %xmm11
|
|
pinsrd $2, 14(%rdi, %r8, 1), %xmm11
|
|
pinsrd $3, 15(%rdi, %r8, 1), %xmm11
|
|
pmaddubsw %xmm15, %xmm11
|
|
|
|
# Suma kolumn splotu
|
|
paddw %xmm2, %xmm0
|
|
paddw %xmm3, %xmm1
|
|
paddw %xmm8, %xmm6
|
|
paddw %xmm9, %xmm7
|
|
paddw %xmm4, %xmm0
|
|
paddw %xmm5, %xmm1
|
|
paddw %xmm10, %xmm6
|
|
paddw %xmm11, %xmm7
|
|
|
|
# Suma wierszy splotu
|
|
phaddw %xmm1, %xmm0
|
|
phaddw %xmm7, %xmm6
|
|
|
|
# Normalizacja wyniku splotu - dodanie zdefiniowanego obciazenia i skalowanie
|
|
# z powrotem do 8-bitowej reprezentacji.
|
|
# Dokladny wynik pozwoliloby uzyskac dzielenie przez 6 (1530/6=255),
|
|
# przesuniecie o 3 bity w prawo jest wydajniejsze, a wciaz pozwala uzyskac
|
|
# rozsadna dokladnosc (1530>>3=191)
|
|
paddw %xmm12, %xmm0
|
|
paddw %xmm12, %xmm6
|
|
psrlw $3, %xmm0
|
|
psrlw $3, %xmm6
|
|
|
|
# Spakowanie 8-bitowych wynikow do jednego rejestru i zapis do pamieci
|
|
packuswb %xmm6, %xmm0
|
|
movdqu %xmm0, 1(%rsi, %r13, 1)
|
|
|
|
# Sprawdzenie, czy nastepna iteracja petli SIMD zmiesci sie w wierszu
|
|
add $16, %r11
|
|
cmp %r15, %r11
|
|
jl lp2
|
|
|
|
# Sprawdzenie, czy wiersz zostal przeliczony w calosci...
|
|
cmp %r12, %r11
|
|
je next_row
|
|
|
|
# ...jesli nie - na dobieg pomocnicza petla (1 piksel na iteracje)
|
|
lp2a:
|
|
mov %r9, %r8
|
|
add %r11, %r8
|
|
|
|
# Gorny wiersz macierzy k
|
|
pinsrd $0, 0(%rdi, %r8, 1), %xmm0
|
|
pmaddubsw %xmm13, %xmm0
|
|
add %rdx, %r8
|
|
mov %r8, %r13
|
|
|
|
# Srodkowy wiersz macierzy k
|
|
pinsrd $0, 0(%rdi, %r8, 1), %xmm2
|
|
pmaddubsw %xmm14, %xmm2
|
|
add %rdx, %r8
|
|
|
|
# Dolny wiersz macierzy k
|
|
pinsrd $0, 0(%rdi, %r8, 1), %xmm4
|
|
pmaddubsw %xmm15, %xmm4
|
|
|
|
# Suma i normalizacja splotu
|
|
paddw %xmm2, %xmm0
|
|
paddw %xmm4, %xmm0
|
|
phaddw %xmm0, %xmm0
|
|
paddw %xmm12, %xmm0
|
|
psrlw $3, %xmm0
|
|
|
|
# Spakowanie 8-bitowego wyniku w najmlodszym fragmencie rejestru i zapis
|
|
packuswb %xmm0, %xmm0
|
|
pextrb $0, %xmm0, 1(%rsi, %r13, 1)
|
|
|
|
# Sprawdzenie, czy tym razem wiersz jest juz przeliczony w calosci
|
|
inc %r11
|
|
cmp %r12, %r11
|
|
jl lp2a
|
|
|
|
next_row:
|
|
# Przesuniecie adresu wiersza w dol
|
|
add %rdx, %r9
|
|
# Sprawdzenie, czy caly obraz jest przeliczony
|
|
inc %r10
|
|
cmp %r14, %r10
|
|
jl lp1
|
|
|
|
pop %r12
|
|
pop %r13
|
|
pop %r14
|
|
pop %r15
|
|
pop %rbp
|
|
ret
|