Obtener miembro de m128 por índice?


Tengo un código, originalmente dado a mí por alguien que trabaja con MSVC, y estoy tratando de que funcione en Clang. Esta es 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 obtengo es el siguiente:

Member reference has base type '__m128' is not a structure or union.

He mirado alrededor y he encontrado que Clang (y tal vez 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índice y no pude haz eso, y he echado un vistazo a la enorme lista de funciones intrínsecas de SSE y aún no he encontrado una apropiada.

Author: svick, 2012-09-27

4 answers

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];
}
 17
Author: Paul R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-27 15:16:17

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 elimino porque es un recordatorio útil de cómo no hacer las cosas y dejar que se presente como 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 disponible.

 17
Author: Gunther Piez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-29 11:53:13

Como una modificación a la solución de hirschhornsalz, si i es una constante en tiempo de compilación, podría evitar la ruta de unión por completo usando un 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
Author: Jason R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-22 21:56:30

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 funcionar bastante bien para mí.

 4
Author: Jordan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-10 04:16:33