ASM功能中的SSE指令

时间:2014-11-20 15:31:30

标签: assembly sse

我正在尝试使用SSE指令以提高ASM功能的速度。这个函数实际上做了位图的否定。这是我没有SSE的代码,它获取字节数组和数组大小。它完全有效,对位图有负面影响。

;-------------------------------------------------------------------------
.586 

.MODEL flat, stdcall


OPTION CASEMAP:NONE

INCLUDE    include\windows.inc
INCLUDE    include\user32.inc
INCLUDE    include\kernel32.inc 

.CODE

DllEntry PROC hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD

    mov eax, TRUE  
    ret

DllEntry ENDP

;-------------------------------------------------------------------------

Negatyw24 PROC stdcall uses eax ebx ecx edx, tab :dword, amount :dword

    mov EAX, tab    ;kopiuj adres 1 komorki
    add EAX, amount ;dodaj ilosc komorek
    sub EAX, 1      ;przjedz do ost komorki
petla:

    mov BL, [EAX]   ;pobierz komorke do rej
    mov CL, 255     ;laduj FF do CL
    sub CL, BL      ;neguj bajt w BL
    mov [EAX], CL   ;zapisz zaneg bajt do pao
    cmp EAX, tab    ;sprawdz koniec tablicy
    je koniec
    sub EAX, 1      ;przesun sie w tablicy o 1 komorke do tylu
    jmp petla
koniec: 

    ret 

Negatyw24 ENDP

;-------------------------------------------------------------------------

END DllEntry

现在我想使用MMX寄存器进行相同的操作。我做过类似的事情,尝试了其他一些方法,没有任何效果。有人可以帮我弄这个吗?这是我的实际代码:

    ;-------------------------------------------------------------------------
.686 
.mmx
.xmm
.MODEL flat, stdcall


OPTION CASEMAP:NONE

INCLUDE    include\windows.inc
INCLUDE    include\user32.inc
INCLUDE    include\kernel32.inc 

.CODE

DllEntry PROC hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD

    mov eax, TRUE  
    ret

DllEntry ENDP

;-------------------------------------------------------------------------

Negatyw24 PROC stdcall uses eax ebx ecx edx edi esi, tab :dword, amount :dword

    mov EAX, tab    ;adres początku tablicy
    add EAX, amount ;dodaj ilosc komorek
    sub EAX, 1      ;przejdz do ostatniej komorki

    mov EBX, 112    ;ilosc bajtow przeksztalcanych w jednym cyklu MMX

    pcmpeqd xmm0, xmm0

    ; -----------------------
    ; Petla negowania z SSE -
    ; -----------------------

    petlaSSE:
        cmp EAX, tab    ;jesli zostalo mniej niz 112 bajtow
        je koniecSSE    ;to koniec instrukcji SSE

        movaps xmm1, [EAX]
        ;movaps xmm1, [EAX-1]
        ;movaps xmm1, [EAX-2]
        ;movaps xmm1, [EAX-3]
        ;movaps xmm1, [EAX-4]
        ;movaps xmm1, [EAX-5]
        ;movaps xmm1, [EAX-6]

        pxor    xmm1, xmm0                  ; zanegowanie wartości rejestrów
        ;pxor   xmm2, xmm0
        ;pxor   xmm3, xmm0
        ;pxor   xmm4, xmm0
        ;pxor   xmm5, xmm0
        ;pxor   xmm6, xmm0
        ;pxor   xmm7, xmm0

        movaps [EAX], xmm1
        ;movaps [EAX-1], xmm2
        ;movaps [EAX-2], xmm3
        ;movaps [EAX-3], xmm4
        ;movaps [EAX-4], xmm5
        ;movaps [EAX-5], xmm6
        ;movaps [EAX-6], xmm7

        sub EAX, 7  ;zmniejszenie komorek o 7

        jmp petlaSSE

    koniecSSE:  

    ret 

Negatyw24 ENDP

;-------------------------------------------------------------------------

END DllEntry

1 个答案:

答案 0 :(得分:1)

有很多问题。您似乎忘记了xmm个寄存器是16个字节,而是假装每次迭代处理7个字节,并在结束之前从#34; 1开始。 (然后超过15个字节结束)。

幸运的是,对齐的加载捕获了它,否则你会得到一个完全损坏的输出和调试最烦人的事情之一:偶尔发生崩溃,可能是在不相关的代码中。

如果你修复了第一个问题,你可以使用未对齐的加载,但是你仍然必须确保你处理数组的最终结果"正确的(如果长度不是16的倍数,那么在最后反转部分片段会破坏那里发生的任何事情)。

顺便说一句,每次循环迭代使用2次跳转是不必要的,你可以用1来完成。

修复所有内容会产生大量代码,更容易保证数组将是16对齐且长度可被16整除。如果您无法做出这些保证,请在此处一些代码(未经测试),我改编自一个有效的例程,所以这可能也是如此:

    push ebp
    mov ebp, esp
    mov eax, [ebp + 8]
    mov ecx, [ebp + 12]
    pcmpeqb xmm0, xmm0
    test al, 15
    jz aligned_entry
unaligned:
    not byte ptr [eax]
    add eax, 1
    sub ecx, 1
    jz exit
    test al, 15
    jnz unaligned
aligned_entry:
    sub ecx, 32
    jb tail
aligned:  ; unrolled by 2 (32 bytes / iteration), was optimal on my old PC
    movdqa xmm1, [eax]
    pxor xmm1, xmm0
    movdqa [eax], xmm1
    movdqa xmm1, [eax + 16]
    pxor xmm1, xmm0
    movdqa [eax + 16], xmm1
    add eax, 32
    sub ecx, 32
    ja aligned
tail:
    add ecx, 32
    jz exit
tail_loop:
    not byte ptr [eax]
    add eax, 1
    sub ecx, 1
    jnz tail_loop
exit:
    leave
    ret

如果分配了适当的缓冲区,则可以省略对齐循环和尾循环。这些部分没有特别有效的编码,因为它们不是必须的 - 大部分工作都在中间。