我正在尝试使用 iPhone 上的矢量浮点编写 Matrix3x3 乘法,但是我遇到了一些问题。这是我第一次尝试编写任何 ARM 程序集,所以它可能是一个我没有看到的失败的简单解决方案。
我目前正在使用我编写的数学库运行一个小型应用程序。我正在研究使用向量浮点单元提供的好处,因此我将矩阵相乘并将其转换为 asm。以前应用程序可以毫无问题地运行,但是现在我的对象将全部随机消失。这似乎是由于我的矩阵乘法的结果在某些时候变成了 NAN。
这是代码
IMatrix3x3 operator*(IMatrix3x3 & _A, IMatrix3x3 & _B)
{
IMatrix3x3 C;
//C++ code for the simulator
#if TARGET_IPHONE_SIMULATOR == true
C.A0 = _A.A0 * _B.A0 + _A.A1 * _B.B0 + _A.A2 * _B.C0;
C.A1 = _A.A0 * _B.A1 + _A.A1 * _B.B1 + _A.A2 * _B.C1;
C.A2 = _A.A0 * _B.A2 + _A.A1 * _B.B2 + _A.A2 * _B.C2;
C.B0 = _A.B0 * _B.A0 + _A.B1 * _B.B0 + _A.B2 * _B.C0;
C.B1 = _A.B0 * _B.A1 + _A.B1 * _B.B1 + _A.B2 * _B.C1;
C.B2 = _A.B0 * _B.A2 + _A.B1 * _B.B2 + _A.B2 * _B.C2;
C.C0 = _A.C0 * _B.A0 + _A.C1 * _B.B0 + _A.C2 * _B.C0;
C.C1 = _A.C0 * _B.A1 + _A.C1 * _B.B1 + _A.C2 * _B.C1;
C.C2 = _A.C0 * _B.A2 + _A.C1 * _B.B2 + _A.C2 * _B.C2;
//VPU ARM asm for the device
#else
//create a pointer to the Matrices
IMatrix3x3 * pA = &_A;
IMatrix3x3 * pB = &_B;
IMatrix3x3 * pC = &C;
//asm code
asm volatile(
//turn on a vector depth of 3
"fmrx r0, fpscr \n\t"
"bic r0, r0, #0x00370000 \n\t"
"orr r0, r0, #0x00020000 \n\t"
"fmxr fpscr, r0 \n\t"
//load matrix B into the vector bank
"fldmias %1, {s8-s16} \n\t"
//load the first row of A into the scalar bank
"fldmias %0!, {s0-s2} \n\t"
//calulate C.A0, C.A1 and C.A2
"fmuls s17, s8, s0 \n\t"
"fmacs s17, s11, s1 \n\t"
"fmacs s17, s14, s2 \n\t"
//save this into the output
"fstmias %2!, {s17-s19} \n\t"
//load the second row of A into the scalar bank
"fldmias %0!, {s0-s2} \n\t"
//calulate C.B0, C.B1 and C.B2
"fmuls s17, s8, s0 \n\t"
"fmacs s17, s11, s1 \n\t"
"fmacs s17, s14, s2 \n\t"
//save this into the output
"fstmias %2!, {s17-s19} \n\t"
//load the third row of A into the scalar bank
"fldmias %0!, {s0-s2} \n\t"
//calulate C.C0, C.C1 and C.C2
"fmuls s17, s8, s0 \n\t"
"fmacs s17, s11, s1 \n\t"
"fmacs s17, s14, s2 \n\t"
//save this into the output
"fstmias %2!, {s17-s19} \n\t"
//set the vector depth back to 1
"fmrx r0, fpscr \n\t"
"bic r0, r0, #0x00370000 \n\t"
"orr r0, r0, #0x00000000 \n\t"
"fmxr fpscr, r0 \n\t"
//pass the inputs and set the clobber list
: "+r"(pA), "+r"(pB), "+r" (pC) :
:"cc", "memory","s0", "s1", "s2", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19"
);
#endif
return C;
}
据我所知,这是有道理的。在调试时我设法注意到,如果我_A = C
在返回之前和 ASM 之后说,_A
不一定等于C
这只会增加我的困惑。我曾认为这可能是由于我给 VFPU 的指针被诸如"fldmias %0!, {s0-s2} \n\t"
但是我对 asm 的理解不足以正确理解问题,也没有看到该代码行的替代方法。
无论如何,我希望比我更了解的人能够看到解决方案,任何帮助将不胜感激,谢谢:-)
编辑:我发现pC
尽管设置了 asm 代码,但它似乎是 NULL pC = &C
。我假设这是由于编译器重新排列了庄园中的代码,这会破坏它吗?我已经尝试过各种方法来阻止这种情况的发生(比如在输入列表中添加所有相关的内容——我认为这甚至不应该是必要的,因为我在 clobber 列表中列出了“内存”)而且我还在同样的问题。
编辑#2:是的,内存问题似乎是由我引起的,不包括"r0"
在clobber列表中,但是修复它(如果它确实已修复)似乎并没有解决问题。我注意到将旋转矩阵乘以单位矩阵不能正常工作,而是将 0.88 作为矩阵中的最后一项而不是 1:
| 0.88 0.48 0 | | 1 0 0 | | 0.88 0.48 0 |
|-0.48 0.88 0 | * | 0 1 0 | = |-0.48 0.88 0 |
| 0 0 1 | | 0 0 1 | | 0 0 0.88|
然后我想我的逻辑一定是错误的,所以我逐步完成了程序集。直到最后一个 "fmacs s17, s14, s2 \n\t" 之前一切似乎都很好,其中:
s0 = 0 s14 = 0 s17 = 0
s1 = 0 s15 = 0 s18 = 0
s2 = 1 s16 = 1 s19 = 0
所以肯定fmacs
是在执行操作:
s17 = s17 + s14 * s2 = 0 + 0 * 1 = 0
s18 = s18 + s15 * s2 = 0 + 0 * 1 = 0
s19 = s19 + s16 * s2 = 0 + 1 * 1 = 1
然而,结果让s19 = 0.88
我更加困惑:我误解了它的fmacs
工作原理吗?(PS 很抱歉现在变成了一个很长的问题:-P)