Получить член __m128 по индексу?
У меня есть код, первоначально предоставленный мне кем-то, работающим с 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 и еще не нашел подходящего.
Ответы
Ответ 1
Объединение, вероятно, является самым переносимым способом:
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];
}
Ответ 2
использование
template<unsigned i>
float vectorGetByIndex( __m128 V) {
union {
__m128 v;
float a[4];
} converter;
converter.v = V;
return converter.a[i];
}
который будет работать независимо от доступного набора команд.
Примечание. Даже если SSE4.1 доступен и i
pextract
постоянной времени компиляции, вы не можете использовать pextract
и т.д. Таким образом, поскольку эти инструкции извлекают 32-разрядное целое число, а не число с float
:
// broken code starts here
template<unsigned i>
float vectorGetByIndex( __m128 V) {
return _mm_extract_epi32(V, i);
}
// broken code ends here
Я не удаляю это, потому что это полезное напоминание, как не делать вещи.
Ответ 3
Как модификация решения hirschhornsalz, если i
является константой времени компиляции, вы можете полностью исключить путь объединения, используя тасование/хранилище:
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
}
Ответ 4
Я использую
union vec { __m128 sse, float f[4] };
float accessmember(__m128 v, int index)
{
vec v.sse = v;
return v.f[index];
}
Кажется, для меня это очень хорошо.