.intel_syntax noprefix

.data
mask:   .int    0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff # Maska za 
#izracunavanje apsolutnih vrednosti brojeva u nekom SSE registru.

.text
.global norms

	## Funkcija norms() izracunava uniformnu i euklidsku normu date
	## matrice. Argumenti funkcije su:
        ##   edi, esi - dimenzije matrice
        ##   rdx - adresa niza sa adresama na koje su smesteni
	##              elementi pojedinacnih redova date matrice
        ##   rcx, r8 - adrese lokacija na koje treba upisati
	##                        izracunate vrednosti uniformne,
	##                         odn. euklidske, norme date matrice
        ## Pretpostavka je da su dimenzije matrice pozitivni brojevi.
	## Funkcija se u potpunosti podvrgava C konvencijama pozivanja.
norms:
        ## Prolog funkcije.
        enter   0, 0
	
	## Cuvaju se vrednosti rdx, rcx, jer ce biti promenjene narednim
	## instrukcijama.
	mov r10, rdx
	mov r9, rcx

        ## Proverava se da li procesor podrzava SSE instrukcije.
        mov     rax, 1
        cpuid
        test    rdx, 0x2000000
        jz done

        ## Cuva se sadrzaj SSE registara i registara koprocesora.
        mov     rdx, rsp
        and     rsp, 0xfffffffffffffff0
        sub     rsp, 512
        fxsave  [rsp]

        ## Na poziciji najmanje tezine u registru xmm0 bice cuvana
        ## tekuca vrednost uniformne norme, dok ce registar xmm1
        ## sadrzati parcijalne sume za racunanje euklidske norme.  U
	## registar xmm7 se ucitava bitska maska koja sluzi za
        ## izracunavanje apsolutne vrednosti brojeva u nekom registru.
        xorps   xmm0, xmm0
        xorps   xmm1, xmm1
        movups  xmm7, mask

        ## Registar rcx ce sluziti kao brojac u spoljasnjoj i
        ## unutrasnjoj petlji izracunavanja koje sledi, i
        ## inicijalizuje se na broj redova matrice.  Broj kolona matrice
        ## ce biti cuvan u registru rax.  Registar r10 ce cuvati adresu
	## na kojoj se nalazi adresa prvog elementa tekuceg reda
	## matrice.
        mov     ecx, edi
        mov	eax, esi

next_row:
        ## Registar ecx se, kao brojac za unutrasnju petlju
        ## inicijalizuje na broj kolona matrice.  Registar rsi ce
        ## sadrzati adresu na kojoj se nalazi tekuci element tekuceg
        ## reda matrice.  Registar xmm2 ce sluziti za akumuliranje
        ## parcijalnih suma pri racunanju sume apsolutnih vrednosti
	## elemenata tekuceg reda matrice.
        push    rcx
        mov     ecx, eax
        mov     rsi, [r10]
        xorps   xmm2, xmm2

next_four:
        ## Proverava se da li ima 4 ili vise preostalih elemenata u
        ## tekucem redu matrice i, ako to nije slucaj, prelazi se na
	## procesiranje pojedinacnih preostalih elemenata tekuceg reda
	## matrice.
        cmp     ecx, 4
        jb next_one

        ## Ucitavaju se naredna 4 elementa tekuceg reda matrice, i
        ## azuriraju se parcijalne sume za racunanje sume apsolutnih
        ## vrednosti elemenata tekuceg reda, odn. za racunanje
	## euklidske norme matrice.
        movups  xmm3, [rsi]
        andps   xmm3, xmm7
        addps   xmm2, xmm3
        mulps   xmm3, xmm3
        addps   xmm1, xmm3

        ## Prelazi se na narednu iteraciju.
        add     rsi, 16
        sub     ecx, 4
        jmp next_four
        
next_one:
        ## Proverava se da li ima preostalih elemenata u tekucem redu
        ## matrice i, ako to nije slucaj, prelazi se na eventualno
	## azuriranje uniformne norme matrice.
        jecxz update_uniform_norm

        ## Ucitava se naredni elementa tekuceg reda matrice, i azuriraju
        ## se parcijalne sume za racunanje sume apsolutnih vrednosti
        ## elemenata tekuceg reda, odn. za racunanje euklidske norme
	## matrice.
        movss   xmm3, [rsi]
        andps   xmm3, xmm7
        addss   xmm2, xmm3
        mulss   xmm3, xmm3
        addss   xmm1, xmm3

        ## Prelazi se na narednu iteraciju.
        add     rsi, 4
        dec     ecx
        jmp next_one
        
update_uniform_norm:
        ## Izracunava se suma apsolutnih vrijednosti elemenata tekuceg
        ## reda matrice i prema potrebi se azurira vrednost uniformne
	## norme matrice.
        movhlps xmm3, xmm2
        addps   xmm2, xmm3
        movaps  xmm3, xmm2
        shufps  xmm3, xmm3, 0b01010101
        addss   xmm2, xmm3
        comiss  xmm0, xmm2
        jae continue
        movaps  xmm0, xmm2
                  
continue:
        ## Prelazi se na procesiranje narednog reda matrice.
        add     r10, 8
        pop     rcx       
        
        loop next_row

        ## Upisuje se vrednost uniformne norme matrice u za to
	## predvidjenu lokaciju u memoriji.
        movss   [r9], xmm0

        ## Izracunava se, i upisuje u za to predvidjenu lokaciju u
	## memoriji, vrednost euklidske norme matrice.
        movhlps xmm2, xmm1
        addps   xmm1, xmm2
        movaps  xmm2, xmm1
        shufps  xmm2, xmm2, 0b01010101
        addss   xmm1, xmm2
        sqrtss  xmm1, xmm1
        movss   [r8], xmm1
        
        ## Vraca se prethodni sadrzaj u registre koprocesora i SSE
        ## registre.
        fxrstor [rsp]
        mov     rsp, rdx

done:
	## Epilog funkcije.
	leave
        ret
