Я пытаюсь написать умножение Matrix3x3, используя вектор с плавающей запятой на iPhone, однако я сталкиваюсь с некоторыми проблемами. Это моя первая попытка написать любую сборку 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
кажется NULL, когда ассемблерный код срабатывает, несмотря на то, что он установлен pC = &C
. Я предполагаю, что это связано с тем, что компилятор перестраивает код в поместье, которое его нарушает? Я пробовал различные методы, которые я видел, чтобы остановить это (например, добавление всего соответствующего в список ввода - думал, что это даже не должно быть необходимо, так как я указываю "память" в списке уничтожения), и я все еще получаю те же проблемы.
Изменить № 2: верно, проблема с памятью, похоже, была вызвана тем, что я не включил "r0"
в список засорения, однако исправление этого (если оно действительно исправлено), похоже, не решило проблему. Я заметил, что умножение матрицы вращения на единичную матрицу работает неправильно и вместо 1 дает 0,88 в качестве последней записи в матрице:
| 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
? (P.S. извините за вопрос, который стал очень длинным :-P)