Я ищу оптимизированные способы транспонирования матрицы на ЦП только с известным номером набора кеша и размером блока.Я обнаружил, что встроенные функции Intel содержат низкоуровневую транспонированную матрицу 4x4.Следующее:
#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \
do { \
__v4sf __r0 = (row0), __r1 = (row1), __r2 = (row2), __r3 = (row3); \
__v4sf __t0 = __builtin_ia32_unpcklps (__r0, __r1); \
__v4sf __t1 = __builtin_ia32_unpcklps (__r2, __r3); \
__v4sf __t2 = __builtin_ia32_unpckhps (__r0, __r1); \
__v4sf __t3 = __builtin_ia32_unpckhps (__r2, __r3); \
(row0) = __builtin_ia32_movlhps (__t0, __t1); \
(row1) = __builtin_ia32_movhlps (__t1, __t0); \
(row2) = __builtin_ia32_movlhps (__t2, __t3); \
(row3) = __builtin_ia32_movhlps (__t3, __t2); \
} while (0)
Функции, которые он использует, являются встроенными функциями компилятора GCC, которые используют команды сборки UNPCKHPS / LPS и MOVLHPS / HLPS x86.Это я понимаю, и я примерно понимаю, как эти команды будут работать вместе, чтобы транспонировать 4 строки.
Однако я хотел протестировать эти функции, поэтому я скопировал это в свой код и слегка его отредактировал.
Я обнаружил, что простая подстановка функции в аргументы без использования временной переменной сломала функцию.Вот пример этого:
#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \
do { \
__v4sf __r0 = (row0), __r1 = (row1), __r2 = (row2), __r3 = (row3); \
__v4sf __t1 = __builtin_ia32_unpcklps (__r2, __r3); \
__v4sf __t2 = __builtin_ia32_unpckhps (__r0, __r1); \
__v4sf __t3 = __builtin_ia32_unpckhps (__r2, __r3); \
(row0) = __builtin_ia32_movlhps (__builtin_ia32_unpcklps (__r0, __r1), __t1); \
(row1) = __builtin_ia32_movhlps (__t1, __builtin_ia32_unpcklps (__r0, __r1)); \
(row2) = __builtin_ia32_movlhps (__t2, __t3); \
(row3) = __builtin_ia32_movhlps (__t3, __t2); \
} while (0)
Кто-нибудь знает, почему это произойдет?Обычно, если вы измените порядок вызовов функций (при условии, что они не работают с одним и тем же указателем) не может повлиять на выполнение.