我正在尝试使用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
答案 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
如果分配了适当的缓冲区,则可以省略对齐循环和尾循环。这些部分没有特别有效的编码,因为它们不是必须的 - 大部分工作都在中间。