2014-11-20 1 views
-1

ASM 기능의 속도를 향상시키기 위해 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 
+2

_ "아무 것도 작동하지 않음"_을 정의하십시오. 어떤 방법으로 작동하지 않습니까? 결과가 예상 한 것과 어떻게 다릅니 까? 디버깅 측면에서 무엇을 했습니까? – Michael

+2

자신 만의 많은 작업을하고 있습니다. C에서이 작업을 수행하고 필요할 경우 SSE 내장 함수를 사용할 수 있습니다.이 작업을 수행하는 것보다 슬픔의 10 % 정도는 비슷한 성능을 얻을 수 있습니다. asm. –

+0

"아무것도 작동하지 않는다"는 것은 "문제가 정렬 된로드에서 잘못 정렬 된 주소라고 말하지 않는 이상한 오류가 발생했습니다"라는 의미입니다. 그러나 이것이 문제였습니다. 'sub eax, 7'에 의해 보장 된 첫 번째 또는 두 번째 중 하나가 잘못 정렬되었습니다. – harold

답변

1

많은 문제가 있습니다. xmm 레지스터가 16 바이트라는 것을 잊어 버린 것처럼 보입니다. 대신 반복 당 7 바이트를 처리하고 "1 끝"에서 시작하여 (끝에서 15 바이트 끝까지 튀어 나오 듯이) 가장합니다. 관련되지 않은 코드에서 가끔 충돌 :

다행히 정렬로드, 그렇지 않으면 당신은 완전히 깨진 출력 및 디버그에 가장 짜증나는 것들 중 하나를 얻었을 것입니다, 그것을 붙 잡았다.

첫 번째 문제를 해결 한 후에 정렬되지 않은로드를 사용할 수는 있지만 최종적으로 "배열의 끝"을 올바르게 처리해야합니다 (길이가 16의 배수가 아닌 부분 조각을 반전 한 경우) 결국 거기에있는 일이 무엇이든 망가뜨릴 것입니다.) 루프 반복 당 2 개 점프를 사용하여 옆으로

, 그것은 배열 (16)가 정렬 될 것이라고 보장하기 쉽게, 당신은 1

모든 것을 해결와 함께 할 수 필요가 없습니다 코드를 많이 만들고 당신이 그 보증을 할 수없는 경우 (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 

당신은 정렬을 남길 수 있습니다 루프와 꼬리 루프가 필요합니다. 이러한 부분은 특별히 효율적으로 코드화되지 않습니다. 왜냐하면 반드시 그럴 필요는 없기 때문에 대부분의 작업이 중간에 있습니다.

+0

그래, 이론 상으로는 어떻게 작동하는지 알지만 실제로 예제 코드로도 할 수는 없다. 나는 ASM에서 글쓰기에 아무런 기술이 없으며 단지 이것을 극복하기를 원한다. – Infinito

+0

@Infinito 당신은 이것을 복사하고 붙여 넣을 수있다. 어쩌면 stdcall – harold

+0

에 맞 춥니 다.하지만 예제에 따르면 무엇이 ebp에 있으며, 첫 줄은 무엇입니까? 내 배열? – Infinito