.intel_syntax noprefix

.data
zero:   .float  0               # Broj 0.
        
.text
.global shortest_distance

	## Funkcija shortest_distance() izracunava najkrace rastojanje
        ## izmedju dve prave, pri cemu je svaka prava odredjena sa po
	## dve tacke.  Argumenti funkcije su:
        ##   rdi, rsi - adrese sa koordinatama tacaka koje
	##                       odredjuju prvu pravu
        ##   rdx, rcx - adrese sa koordinatama tacaka koje
	##                        odredjuju drugu pravu
        ##   r8 - adresa na koju treba smestiti izracunato
	##              rastojanje
        ## Pretpostavka je da date prave nisu paralelne. Funkcija se u
	## potpunosti podvrgava C konvencijama pozivanja.
	##
	## UPUTSTVO:
	## Neka su date dve prave s i t odredjene sa po dve tacke
	## s - S0 i S1, i t - T0 i T1. Vektori pravaca ove dve prave
	## DS i DT se dobijaju kao razlike vektora OS1 i OS0, odnosno
	## OT1 i OT0, gde je O koordinatni pocetak.
	## DS = S1 - S0
	## DT = T1 - T0
	## Neka je ST vektor od tacke S0 do T0
	##
	## Najkrace rastojanje izmedju dve prave s i t se racuna tako sto se
	## izracuna normalizovani vektor pravca V najkraceg rastojanja, a to je
	## vektor koji je normalan na obe prave (dobija se kao vektorski 
	## proizvod V = DS x DT). Zatim se izracuna apsolutna vrednost 
	## skalarnog proizvoda V i ST.
	##
	## Skalarni proizvod vektora A (az, ay, ax) i B (bz, by, bx):
	## AB = azbz + ayby + axbx
	##
	## Vektorski proizvod vektora A (az, ay, ax) i B (bz, by, bx):
	## |x  y  z |
	## |ax ay az|
	## |bx by bz|
	## A x B = (axby-aybx, azbx-axbz, aybz-azby)
	##
	## Normalizacija vektora A (az, ay, ax):
	## A = A/|r| gde je |r| = sqrt(az^2+ay^2+ax^2).
	
shortest_distance:
        ## Prolog funkcije.
	enter   16, 0
	
        mov r9, rdx
        mov r10, rcx
        
        ## Proverava se da li procesor podrzava SSE instrukcije.
        mov     rax, 1
        cpuid
        test    rdx, 0x2000000
        jz not_supported

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

        ## Preko pomocnog niza, u registar xmm0 se upisuju koordinate
        ## prve tacke prve prave (u oznaci tacka S0).
	mov rax, [rdi]
	mov [rbp-16], rax
	mov eax, [rdi+8]
	mov [rbp-8], eax
        movups  xmm0, [rbp-16]

        ## Na isti nacin, u registre xmm1, xmm2 i xmm3 se upisuju
        ## koordinate druge tacke prve prave odn. prve i druge tacke
	## druge prave (u oznaci tacke S1, T0 i T1).
	mov rax, [rsi]
	mov [rbp-16], rax
	mov eax, [rsi+8]
	mov [rbp-8], eax
        movups  xmm1, [rbp-16]

	mov rax, [r9]
	mov [rbp-16], rax
	mov eax, [r9+8]
	mov [rbp-8], eax
        movups  xmm2, [rbp-16]

	mov rax, [r10]
	mov [rbp-16], rax
	mov eax, [r10+8]
	mov [rbp-8], eax
        movups  xmm3, [rbp-16]

        
        ## U registrima xmm1 i xmm2 se formiraju vektori pravca pravih
        ## (u oznaci vektori DS i DT), a u registru xmm0 vektor od tacke
	## S0 do tacke T0 (u oznaci vektor ST).
        subps   xmm1, xmm0	# xmm1 <- DS
        subps   xmm3, xmm2	# xmm3 <- DT
        subps   xmm2, xmm0	# xmm2 <- ST
        movaps  xmm0, xmm2	# xmm0 <- ST
        movaps  xmm2, xmm3	# xmm2 <- DT

        
        ## U registru xmm1 se izracunava vektorski proizvod vektora DS i
        ## DT (u oznaci vektor V, ovaj vektor je vektor pravca najkraceg
	## rastojanja izmedju pravih).
	## a x b = (axby - aybx, azbx - axbz, aybz - azby)
	## za 0 - x, 1 - y, 2 - z raspored je
	## 021*102 - 102*021
        movaps  xmm3, xmm1		# xmm3 <- DS
        movaps  xmm4, xmm2		# xmm4 <- DT
        shufps  xmm1, xmm1, 0xc9	# xmm1 <- 3,0,2,1 od DS
        shufps  xmm2, xmm2, 0xd2	# xmm2 <- 3,1,0,2 od DT
        shufps  xmm3, xmm3, 0xd2	# xmm3 <- 3,1,0,2 od DS
        shufps  xmm4, xmm4, 0xc9	# xmm4 <- 3,0,2,1 od DT        
        mulps   xmm1, xmm2		# xmm1 <- 33,01,20,12
        mulps   xmm3, xmm4		# xmm3 <- 33,10,02,21
        subps   xmm1, xmm3		# xmm1 <- 33-33,01-10,20-02,12-21

        ## Normalizuje se vektor V, pri cemu se norma izracunava u
	## registru xmm2.
	## |r| = sqrt(a0^2+a1^2+a2^2), a = a/|r|
        movaps  xmm2, xmm1
        mulps   xmm2, xmm2
        movaps  xmm3, xmm2
        shufps  xmm3, xmm3, 0x01
        movaps  xmm4, xmm2
        shufps  xmm4, xmm4, 0x02
        addss   xmm2, xmm3
        addss   xmm2, xmm4
        
        rsqrtss xmm2, xmm2
        shufps  xmm2, xmm2, 0x00
        mulps   xmm1, xmm2

        ## Trazeno rastojanje jednako je apsolutnoj vrednosti
	## skalarnog proizvoda vektora ST i V.
        mulps   xmm0, xmm1
        movaps  xmm1, xmm0
        shufps  xmm1, xmm1, 0x01
        movaps  xmm2, xmm0
        shufps  xmm2, xmm2, 0x02
        addss   xmm0, xmm1
        addss   xmm0, xmm2

        movss   xmm1, zero
        comiss  xmm0, xmm1
        jae store_result
        subss   xmm1, xmm0
        movss   xmm0, xmm1
store_result:              
        movss   [r8], xmm0

        ## Vraca se prethodni sadrzaj u registre koprocesora i SSE
        ## registre.
        fxrstor [rsp]
        mov     rsp, rdx

done:        
	## Epilog funkcije.
	leave
        ret

not_supported:
	mov rdi, 1
	call exit
