2009-11-20 12 views
8

Por lo general, yo trabajo con vectores 3D utilizando siguientes tipos:C - Cómo acceder a los elementos del vector utilizando GCC SSE extensión vector

typedef vec3_t float[3]; 

inicializar vectores usando algo bajo. como:

vec3_t x_basis = {1.0, 0.0, 0.0}; 
vec3_t y_basis = {0.0, 1.0, 0.0}; 
vec3_t z_basis = {0.0, 0.0, 1.0}; 

y acceder a ellos usando smth. como:

x_basis[X] * y_basis[X] + ... 

Ahora necesito una aritmética vectorial usando instrucciones SSE. Tengo el siguiente código:

typedef float v4sf __attribute__ ((mode(V4SF))) 
int main(void) 
{ 
    v4sf a,b,c; 
    a = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    b = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    c = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    a = b + c; 
    printf("a=%f \n", a); 
    return 0; 
} 

GCC es compatible. Pero ... Primero, me da 0.00000 como resultado. En segundo lugar, no puedo acceder a los elementos de dichos vectores. Mi pregunta es: ¿cómo puedo acceder a los elementos de dichos vectores? Necesito algo. como un [0] para acceder elemento X, un [1] para acceder elemento Y, etc.

PD: compilar este código usando:

gcc -msse testgcc.c -o testgcc 
+0

Las preguntas no fueron tan difíciles, y no me considero un experto en gcc. La próxima vez uso un título más inofensivo, casi salte la pregunta. – hirschhornsalz

Respuesta

16

La manera segura y recomendada de acceder a los elementos es mediante una unión, en lugar de un tipo de punteo, que engaña los mecanismos de detección de alias del compilador y puede provocar un código inestable.

union Vec4 { 
    v4sf v; 
    float e[4]; 
}; 

Vec4 vec; 
vec.v = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
printf("%f %f %f %f\n", vec.e[0], vec.e[1], vec.e[2], vec.e[3]); 

+1

no, elder_george ha dado un ejemplo más práctico: es lo suficientemente seguro si implementa su consejo en una macro o en una línea – psihodelia

+2

Parece que no estaba lo suficientemente claro. El tipo de juego de palabras con punteros es malo, ya que al desreferenciar un puntero con puntaje de tipo se romperán las reglas de alias estrictas. Esto da como resultado un comportamiento indefinido. No se vuelve más seguro mediante la creación de líneas o macrofotografía. Pero puede usar la opción del compilador _-fno-strict-aliasing_, que está hecha exactamente para código roto como este. Los binarios resultantes pueden ser algo más lentos porque niega al compilador una optimización. Lea sobre esto y por qué es malo en gcc.gnu.org/onlinedocs/gcc/... en "-fstrict-aliasing". – hirschhornsalz

+1

Sí, @drhirsh tiene razón, para la muestra provista por @psihodelia mi solución funciona, pero falla después de pequeños cambios debido a una alineación rota. –

5

Están olvidando que es necesario reinterpretar como a conjunto de flotadores. Siguiente código funciona correctamente:

int main(){ 
    v4sf a,b,c; 
    a = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    b = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    c = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    a = b + c; 
    float* pA = (float*) &a; 
    printf("a=[%f %f %f %f]\n",pA[0], pA[1], pA[2], pA[3]); 
    return 0; 
} 

P.S .: gracias por esta pregunta, yo no sabía que gcc tiene ese apoyo SSE.

ACTUALIZACIÓN: esta solución falla una vez que las matrices se han desalineado. La solución proporcionada por @drhirsh está libre de este problema.

+0

omg ¡MUCHAS GRACIAS! – psihodelia

+4

El tipo de juego de palabras es peligroso. – hirschhornsalz

6

Nota que gcc 4.6 ahora supports vectores subindicadas:

En los vectores C tienen subíndices como si el vector eran una matriz con el mismo número de elementos y el tipo de base. Los accesos no vinculados invocan un comportamiento indefinido en el tiempo de ejecución. Las advertencias para los accesos fuera de límite para la suscripción de vectores se pueden habilitar con -Warray-bounds.

+1

Esto solo funciona en C, no en C++. Hay un error pendiente: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51033 –

+1

@DavidGiven Ahora está marcado como fijo. –

Cuestiones relacionadas