Получить член __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 и пока не нашел подходящего.

23

Решение

Объединение, вероятно, самый переносимый способ сделать это:

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];
}
17

Другие решения

Даже если 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];
}

который будет работать независимо от доступного набора команд.

17

В качестве модификации решения Хиршхорнсальца, если 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
}
14

То, как я использую это

union vec { __m128 sse, float f[4] };

float accessmember(__m128 v, int index)
{
vec v.sse = v;
return v.f[index];
}

Кажется, у меня все хорошо получается.

4
По вопросам рекламы [email protected]