Skip to main content
5 of 6
deleted 28 characters in body
JS1
  • 28.6k
  • 3
  • 41
  • 83

##Wrong increment##

First, there is a bug in your main loop. This line:

    add     ebx, 1

should be:

    add     ebx, 4

because you are operating on 4 floats at a time. Right now, you are doing array elements [0..3] following by [1..4]. On my computer the program crashed because it had a problem doing an unaligned load.

##Simplify divide by 4##

This part where you divide ecx by 4:

    push    eax                     
    mov     edx, 0                  
    mov     eax, ecx                
    mov     ebx, 4                  
    div     ebx                     
    mov     ecx, eax                ; ecx becomes the counter for the packed iterations
    pop     eax          

can be simplified to this:

    mov     edx, ecx
    and     edx, 3
    shr     ecx, 2

Explanation: shr is the shift right instruction. When you shift right by 2 it is the same thing as dividing by 4. To get the remainder of something divided by 4, you just need to and that number with 3. C equivalent code:

    remainder = length & 3;
    length >>= 2;

##Remove one jump from main loop##

Your main loop:

.loopP: movaps  xmm1, [esi+ebx*4]
        movaps  xmm2, [edi+ebx*4]
        subps   xmm1, xmm2
        mulps   xmm1, xmm1
        dec     ecx
        haddps  xmm1, xmm1
        haddps  xmm1, xmm1
        addps   xmm0, xmm1
        jz      .loopC
        add     ebx, 4
        jmp     .loopP

.loopC  cmp     edx, 0
        je      .endD

Can be rewritten to remove one of the jumps at the end:

.loopP: movaps  xmm1, [esi+ebx*4]
        movaps  xmm2, [edi+ebx*4]
        subps   xmm1, xmm2
        add     ebx, 4
        mulps   xmm1, xmm1
        dec     ecx
        haddps  xmm1, xmm1
        haddps  xmm1, xmm1
        addps   xmm0, xmm1
        jnz      .loopP

        cmp     edx, 0
        je      .endD

##Loading the mask##

The part where you do a chain of compares to load one of three masks:

.dU1:   cmp     edx, 1          
        jne     .dU2
        movaps  xmm7, [mask1]           
        jmp     .dU

.dU2:   cmp     edx, 2
        jne     .dU3
        movaps  xmm7, [mask2]
        jmp     .dU

.dU3:   movaps  xmm7, [mask3]

can be simplified to this:

.dU1:   shl     edx, 4
        movaps  xmm7, [mask1 + edx - 16]

Explanation: Your masks are located in memory in consecutive order like an array of 128 bit values. So you can load them by index. Note that edx is 1..3 here. The shl instruction is shift left, and shifting left by 4 multiplies edx by 16. Then we load from mask1 + edx - 16. The minus 16 is because edx started at one instead of zero. Equivalent C code is something like this:

        uint8_t mask1[48] = { /* values */ };
        mask128 = *(__m128 *) &mask1[(remainder<<4)-16];

##Stack push/pop##

I'm not sure if this is part of your calling convention, but your prologue and epilogue have extraneous instructions:

    push    ebp
    mov     ebp, esp
    sub     esp, 4
    push    ebx
    push    esi
    push    edi

    pop     edi 
    pop     esi
    pop     ebx
    mov     esp, ebp
    pop     ebp
    ret

Could be changed to:

    push    ebp
    mov     ebp, esp
    push    ebx
    push    esi
    push    edi

    pop     edi
    pop     esi
    pop     ebx
    pop     ebp
    ret

Furthermore, you are not utilizing eax. If you used eax instead of ebx everywhere in your function, you wouldn't have to save ebx because you wouldn't ever use it. You can load the result pointer into eax at the very end instead of at the beginning.

##Comments##

In general I liked all your comments. The one thing I thought you could add a comment for was that this double instruction:

        haddps  xmm1, xmm1
        haddps  xmm1, xmm1

adds all 4 floats in xmm1 into the first float in xmm1. I wasn't familiar with the haddps instruction and I initially thought you made a typo (I thought a single haddps would do the whole job).

##Alignment required##

I was able to use the function successfully, but when I modified my main(), the program crashed. The difference was that my modification caused the arrays I passed to distance() to be not aligned to 16 bytes. Since the movaps instruction expects 128 bit alignment, the arrays passed in need to have 128 bit alignment. I think you should switch to the movups instruction which handles unaligned floats.

JS1
  • 28.6k
  • 3
  • 41
  • 83