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.
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
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
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 –