2017-05-29 1 views
1

J'ai un problème avec la multiplication de deux registres dans l'assemblage sse. Ici il y a mon code:multiplication du registre xmm

moltiplicazionePuntoPunto: 
    mov edx,[esp+20]     ; edx = fxx 
    mov esi,[esp+4]     ; esi = fx 
    mov edi,[esp+8]     ; edi = fy 
    xor eax,eax      ; i=0 
fori: cmp eax,[esp+12]   ; confronta i con N 
    jge endfori 
    xor ebx,ebx      ; j=0 
forj: cmp ebx,[esp+16]    ; confronta j con M 
    jge endforj 
    mov ecx,eax 
    imul ecx,[esp+16]     ; ecx = i*M 
    add ecx,ebx      ; ecx = i*M+j 
    movss xmm5,[esi+ecx*4]   ; xmm5 = fx[i*M+j] 
    movss xmm6,[edi+ecx*4]   ; xmm6 = fy[i*M+j] 
    mulps xmm5,xmm6     ; xmm7 = fx[i*M+j]*fx[i*M+j] 
    movss [edx+ecx*4],xmm5   ; fxx[i*M+j] = fx*fx 
    inc ebx 
    jmp forj 
endforj: 
    inc eax 
    jmp fori 
endfori: 

Ce code modifie la matrice FXX où le FXX élément [i * M + j] = fx [i * M + j] * fy [i * j M +]. Le problème est quand je fais l'opération mulps xmm5,xmm6 le résultat est 0.

+1

si 'mulps xmm5, xmm6' est zéro, l'un des' xmm5' ou 'xmm6' était zéro. Alors, lequel c'est? Et pourquoi n'utilisez-vous pas par exemple C++, cela produirait certainement une boucle plus rapide, au moins cela optimiserait le 'i * M', etc ... plus il serait probablement plus facile à déboguer et à maintenir. – Ped7g

+0

En fait, il y a bien sûr d'autres cas où float x * float y = 0, même si x/y sont tous les deux non-nuls, car float lui-même a une précision limitée, par exemple '1e-23 * 1e-23 = 0 ', etc ... Sans certains exemples de données du débogueur, il est impossible de dire ce que vous avez rencontré, et si vous voyez les données, vous voyez probablement aussi la réponse. – Ped7g

+0

Je pense que le problème est l'isolation de mulps pas la valeur des registres. Parce que si je change les mulps d'istruction avec les additions d'istruction, le code fonctionne –

Répondre

0

Par exemple le C++ simplifié, il passera juste par tous les éléments de la matrice, parce que c'est ce que fait votre boucle imbriquée [i,j]. Vous n'avez pas besoin de calculer i*M+j, comme votre formule n'utilise pas i/j d'une manière particulière, il va juste à travers tous les éléments une fois:

void muldata(float* fxx, const float* fx, const float* fy, const unsigned int M, const unsigned int N) { 
    int ofs = 0; 
    do { 
     fxx[ofs] = fx[ofs] * fy[ofs]; 
     ++ofs; 
    } while (ofs < M*N); 
} 

Fera clang -O3 -m32 (v4.0.0) produire ceci:

muldata(float*, float const*, float const*, unsigned int, unsigned int):     # @muldata(float*, float const*, float const*, unsigned int, unsigned int) 
     push ebp 
     push ebx 
     push edi 
     push esi 
     sub  esp, 12 
     mov  esi, dword ptr [esp + 48] 
     mov  edi, dword ptr [esp + 40] 
     mov  ecx, dword ptr [esp + 36] 
     mov  edx, dword ptr [esp + 32] 
     mov  eax, 1 
     imul esi, dword ptr [esp + 44] 
     cmp  esi, 1 
     cmova eax, esi 
     xor  ebp, ebp 
     cmp  eax, 8 
     jb  .LBB0_7 
     mov  ebx, eax 
     and  ebx, -8 
     je  .LBB0_7 
     mov  dword ptr [esp + 4], eax # 4-byte Spill 
     cmp  esi, 1 
     mov  eax, 1 
     mov  dword ptr [esp], ebx # 4-byte Spill 
     cmova eax, esi 
     lea  ebx, [ecx + 4*eax] 
     lea  edi, [edx + 4*eax] 
     mov  dword ptr [esp + 8], ebx # 4-byte Spill 
     mov  ebx, dword ptr [esp + 40] 
     cmp  edx, dword ptr [esp + 8] # 4-byte Folded Reload 
     lea  eax, [ebx + 4*eax] 
     sbb  bl, bl 
     cmp  ecx, edi 
     sbb  bh, bh 
     and  bh, bl 
     cmp  edx, eax 
     sbb  al, al 
     cmp  dword ptr [esp + 40], edi 
     mov  edi, dword ptr [esp + 40] 
     sbb  ah, ah 
     test bh, 1 
     jne  .LBB0_7 
     and  al, ah 
     and  al, 1 
     jne  .LBB0_7 
     mov  eax, dword ptr [esp] # 4-byte Reload 
     lea  ebx, [edi + 16] 
     lea  ebp, [ecx + 16] 
     lea  edi, [edx + 16] 
.LBB0_5:        # =>This Inner Loop Header: Depth=1 
     movups xmm0, xmmword ptr [ebp - 16] 
     movups xmm2, xmmword ptr [ebx - 16] 
     movups xmm1, xmmword ptr [ebp] 
     movups xmm3, xmmword ptr [ebx] 
     add  ebp, 32 
     add  ebx, 32 
     mulps xmm2, xmm0 
     mulps xmm3, xmm1 
     movups xmmword ptr [edi - 16], xmm2 
     movups xmmword ptr [edi], xmm3 
     add  edi, 32 
     add  eax, -8 
     jne  .LBB0_5 
     mov  eax, dword ptr [esp] # 4-byte Reload 
     mov  edi, dword ptr [esp + 40] 
     cmp  dword ptr [esp + 4], eax # 4-byte Folded Reload 
     mov  ebp, eax 
     je  .LBB0_8 
.LBB0_7:        # =>This Inner Loop Header: Depth=1 
     movss xmm0, dword ptr [ecx + 4*ebp] # xmm0 = mem[0],zero,zero,zero 
     mulss xmm0, dword ptr [edi + 4*ebp] 
     movss dword ptr [edx + 4*ebp], xmm0 
     inc  ebp 
     cmp  ebp, esi 
     jb  .LBB0_7 
.LBB0_8: 
     add  esp, 12 
     pop  esi 
     pop  edi 
     pop  ebx 
     pop  ebp 
     ret 

Ce qui est de loin supérieur à votre code (inclut la vectorisation de boucle par défaut).

Et cela produirait probablement même quelque chose de mieux, si vous souhaitez spécifier l'alignement des pointeurs et rendre M/N temps de compilation constant.


Je viens de vérifier le fonctionnement de la variante C++ en allant cpp.sh site et de l'étendre à ceci:

#include <iostream> 

void muldata(float* fxx, const float* fx, const float* fy, const unsigned int M, const unsigned int N) { 
    unsigned int ofs = 0; 
    do { 
     fxx[ofs] = fx[ofs] * fy[ofs]; 
     ++ofs; 
    } while (ofs < M*N); 
} 

int main() 
{ 
    // constexpr unsigned int M = 1; 
    // constexpr unsigned int N = 1; 
    // const float fx[M*N] = { 2.2f }; 
    // const float fy[M*N] = { 3.3f }; 

    constexpr unsigned int M = 3; 
    constexpr unsigned int N = 2; 
    const float fx[M*N] = { 2.2f, 1.0f, 0.0f, 
          1.0f, 1.0f, 1e-24f }; 
    const float fy[M*N] = { 3.3f, 3.3f, 3.3f, 
          5.5f, 1e30f, 1e-24f }; 

    float fr[M*N]; 
    muldata(fr, fx, fy, M, N); 
    for (unsigned int i = 0; i < N; ++i) { 
     for (unsigned int j = 0; j < M; ++j) std::cout << fr[i*M+j] << " "; 
     std::cout << std::endl; 
    } 
} 

sortie:

7.26 3.3 0 
5.5 1e+30 0 

Il y a également ajouté un commentaire sur les données d'entrée 1x1 , ce qui devrait être la première chose à déboguer dans votre cas. Essayez de faire fonctionner cet exemple dans votre IDE C++ favori, puis remplacez le muldata par votre code d'assemblage, et déboguez-le, pour voir où cela se passe.