У меня есть какой-то код, изначально предоставленный мне кем-то, работающим с MSVC, и я пытаюсь заставить его работать на Clang. Вот функция, с которой у меня проблемы:
float vectorGetByIndex( __m128 V, unsigned int i )
{
assert( i <= 3 );
return V.m128_f32[i];
}
Я получаю следующую ошибку:
Member reference has base type '__m128' is not a structure or union.
Я посмотрел вокруг и обнаружил, что у Clang (и, возможно, GCC) есть проблема с обработкой __m128 как структуры или объединения. Однако мне не удалось найти прямой ответ относительно того, как я могу вернуть эти значения. Я попытался использовать оператор индекса и не смог этого сделать, и я осмотрел огромный список встроенных функций SSE и пока не нашел подходящего.
Объединение, вероятно, самый переносимый способ сделать это:
union {
__m128 v; // SSE 4 x float vector
float a[4]; // scalar array of 4 floats
} U;
float vectorGetByIndex(__m128 V, unsigned int i)
{
U u;
assert(i <= 3);
u.v = V;
return u.a[i];
}
Даже если SSE4.1 доступен и i
константа времени компиляции, вы не может использование pextract
и т.д. таким образом:
// broken code starts here
template<unsigned i>
float vectorGetByIndex( __m128 V) {
return _mm_extract_epi32(V, i);
}
// broken code ends here
Я не удаляю его, потому что это полезное напоминание о том, как не делать вещи, и пусть это будет публичным унижением.
Лучше использовать
template<unsigned i>
float vectorGetByIndex( __m128 V) {
union {
__m128 v;
float a[4];
} converter;
converter.v = V;
return converter.a[i];
}
который будет работать независимо от доступного набора команд.
В качестве модификации решения Хиршхорнсальца, если i
является константой времени компиляции, вы можете полностью избежать пути объединения, используя shuffle / store:
template<unsigned i>
float vectorGetByIndex( __m128 V)
{
#ifdef __SSE4_1__
return _mm_extract_epi32(V, i);
#else
float ret;
// shuffle V so that the element that you want is moved to the least-
// significant element of the vector (V[0])
V = _mm_shuffle_ps(V, V, _MM_SHUFFLE(i, i, i, i));
// return the value in V[0]
return _mm_cvtss_f32(V);
#endif
}
То, как я использую это
union vec { __m128 sse, float f[4] };
float accessmember(__m128 v, int index)
{
vec v.sse = v;
return v.f[index];
}
Кажется, у меня все хорошо получается.