c++ - ¿Obtener miembro de__m128 por índice?
clang sse (4)
Como una modificación de la solución de hirschhornsalz, si i
es una constante de tiempo de compilación, podría evitar la ruta de la unión por completo utilizando una aleatoria / tienda:
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
}
Tengo un código, originalmente dado por alguien que trabaja con MSVC, y estoy tratando de que funcione en Clang. Aquí está la función con la que estoy teniendo problemas:
float vectorGetByIndex( __m128 V, unsigned int i )
{
assert( i <= 3 );
return V.m128_f32[i];
}
El error que recibo es el siguiente:
Member reference has base type ''__m128'' is not a structure or union.
Miré a mi alrededor y descubrí que Clang (y quizás GCC) tiene un problema con el tratamiento de __m128 como una estructura o unión. Sin embargo, no he logrado encontrar una respuesta directa sobre cómo puedo recuperar estos valores. He intentado usar el operador de subíndices y no pude hacer eso, y he echado un vistazo a la enorme lista de funciones intrínsecas SSE y todavía no he encontrado una adecuada.
Incluso si SSE4.1 está disponible y i
es una constante de tiempo de compilación, no puede usar pextract
etc. de esta manera:
// broken code starts here
template<unsigned i>
float vectorGetByIndex( __m128 V) {
return _mm_extract_epi32(V, i);
}
// broken code ends here
No lo borro porque es un recordatorio útil de cómo no hacer las cosas y dejar que sea una humillación pública.
Mejor uso
template<unsigned i>
float vectorGetByIndex( __m128 V) {
union {
__m128 v;
float a[4];
} converter;
converter.v = V;
return converter.a[i];
}
que funcionará independientemente del conjunto de instrucciones disponibles.
La forma en que uso es
union vec { __m128 sse, float f[4] };
float accessmember(__m128 v, int index)
{
vec v.sse = v;
return v.f[index];
}
Parece que funciona bastante bien para mí.
Una unión es probablemente la forma más portátil de hacer esto:
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];
}