m_sincos[t]
является выражением C. Однако в инструкции по сборке (__asm
?) Это интерпретируется как режим адресации x86 с совершенно другим результатом. Например, VS2008 SP1 компилируется:
movaps xmm0, m_sincos[t]
into: (см. Окно разборки при сбое приложения в режиме отладки)
movaps xmm0, xmmword ptr [t]
Эта интерпретация пытается скопировать 128-битное значение, хранящееся по адресу переменной t
, в xmm0. t
, однако, является 32-битным значением по вероятному невыровненному адресу. Выполнение инструкции может вызвать сбой выравнивания и приведет к неверным результатам в нечетном случае, когда адрес t
выровнен.
Вы можете исправить это, используя соответствующий режим адресации x86. Вот медленная, но ясная версия:
__asm mov eax, m_sincos ; eax <- m_sincos
__asm mov ebx, dword ptr t
__asm shl ebx, 4 ; ebx <- t * 16 ; each array element is 16-bytes (128 bit) long
__asm movaps xmm0, xmmword ptr [eax+ebx] ; xmm0 <- m_sincos[t]
Sidenote:
Когда я помещаю это в полную программу, происходит что-то странное:
#include <math.h>
#include <tchar.h>
#include <xmmintrin.h>
int main()
{
static __m128 *m_sincos;
int Bins = 4;
m_sincos = (__m128*) _aligned_malloc(Bins*sizeof(__m128), 16);
for (int t=0; t<Bins; t++) {
m_sincos[t] = _mm_set_ps(cos((float) t), sin((float) t), sin((float) t), cos((float) t));
__asm movaps xmm0, m_sincos[t];
__asm mov eax, m_sincos
__asm mov ebx, t
__asm shl ebx, 4
__asm movaps xmm0, [eax+ebx];
}
return 0;
}
Когда вы запустите это, если вы будете следить за окном регистров, вы можете заметить что-то странное. Хотя результаты верны, xmm0
получает правильное значение до того, как будет выполнена инструкция movaps
. Как это происходит?
Просмотр сгенерированного кода сборки показывает, что _mm_set_ps()
загружает результаты sin / cos в xmm0
, а затем сохраняет их по адресу памяти m_sincos[t]
. Но значение остается там и в xmm0
. _mm_set_ps
является «внутренним», а не вызовом функции; он не пытается восстановить значения регистров, которые он использует после того, как это сделано.
Если вы можете извлечь из этого урок, возможно, при использовании встроенных функций SSE используйте их повсюду, чтобы компилятор мог оптимизировать ситуацию для вас. В противном случае, если вы используете встроенную сборку, используйте это также повсюду.