Assembly xmm寄存器的乘法
我对汇编sse中两个寄存器的乘法有问题。 这是我的代码:Assembly xmm寄存器的乘法,assembly,x86,simd,Assembly,X86,Simd,我对汇编sse中两个寄存器的乘法有问题。 这是我的代码: 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:
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:
此代码修改矩阵fxx,其中元素fxx[i*M+j]=fx[i*M+j]*fy[i*M+j]。问题是,当我执行mulps xmm5、xmm6操作时,结果是0 > P> >简化的C++,它只需遍历矩阵的所有元素,因为这就是您的<代码> [ i,j] < /COD>嵌套循环。您不需要计算
i*M+j
,因为您的公式不以任何特定方式使用i/j,它只需遍历所有元素一次:
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);
}
这远远优于您的代码(默认情况下包括循环的矢量化)
若您指定指针的对齐方式并使M/N编译时为常量,它可能会产生更好的结果
<>我刚刚通过Cpp.SH站点验证了C++变体作品,并将其扩展到:
#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;
}
}
还有注释掉的1x1输入数据,这应该是在您的情况下调试的第一件事。试着让这个例子在你最喜欢的C++ IDE中运行,然后用汇编代码替换<代码> MulDATA<代码>,并通过它调试,看看它是在哪里运行的。 < P>问题解决了。问题是,我从C传递了一个int矩阵。相反,如果我传递了一个float矩阵,代码就会工作。如果
mulps xmm5,xmm6
为零,那么xmm5
或xmm6
中的一个为零。那是哪一个呢?你为什么不使用C++,它会产生更快的循环,至少它会优化<代码> I*M等等。此外,它可能更容易调试和维护。事实上,当然还有其他一些特殊情况,其中float x*float y=0,即使x/y都非零,因为float本身的精度有限,例如1e-23*1e-23=0
,等等。。。如果没有来自调试器的一些示例数据,就不可能知道您遇到了什么,如果您看到了数据,您可能也看到了答案。我认为问题在于mulps指令,而不是寄存器的值。因为如果我用istruction addps更改istruction mulps,代码工作起来就像你的CPU坏了,mulps
没有做它应该做的,对吗?根据常识,90%的软件在这种机器上会出现故障。问题在于代码和/或数据,而不是指令,指令工作正常。您没有提供任何特定的测试用例(包括输入数据、预期输出数据和实际输出数据)。我尝试了我的C++下面的答案,通过CPP.SH在线网站,它工作如预期,我将更新答案与完整的工作示例。问题解决。问题是我从C传递了一个int矩阵。相反,如果我传递了一个float矩阵,代码就可以工作了。谢谢大家。对不起,我是新来的
#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;
}
}
7.26 3.3 0
5.5 1e+30 0