tags:

views:

754

answers:

2

Usually I work with 3D vectors using following types:

typedef vec3_t float[3];

initializing vectors using smth. like:

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

and accessing them using smth. like:

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

Now I need a vector arithmetics using SSE instructions. I have following code:

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 supports such way. But... First, it gives me 0.00000 as result. Second, I cannot access the elements of such vectors. My question is: how can I access elements of such vectors? I need smth. like a[0] to access X element, a[1] to access Y element, etc.

PS: I compile this code using:

gcc -msse testgcc.c -o testgcc
+2  A: 

You are forgetting that you need to reinterpret a as array of floats. Following code works properly:

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.: thanks for this question, I didn't know that gcc has such SSE support.

UPDATE: This solution fails once arrays got unaligned. Solution provided by @drhirsh is free from this problem.

elder_george
omgTHANK YOU SO MUCH!!!
psihodelia
Type punning is dangerous.
drhirsch
+5  A: 

The safe and recommended way to access the elements is with a union, instead of pointer type punning, which fools the aliasing detection mechanisms of the compiler and may lead to unstable code.

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]);
drhirsch
no, elder_george has given a more practical example - it's safe enough if you implement his advice in a macros or in an inline
psihodelia
It seems I wasn't clear enough. Type punning with pointers is bad because dereferencing a type-punned pointer will break strict aliasing rules. This results in undefined behaviour. It doesn't get safer by inlining or macroing. But you can use the compiler option _-fno-strict-aliasing_, which is exactly made for broken code like this. The resulting binaries may be somewhat slower, because you deny the compiler an optimization. Read about it and why it is bad at gcc.gnu.org/onlinedocs/gcc/… under "-fstrict-aliasing".
drhirsch
Yes, @drhirsh is right, for sample provided by @psihodelia my solution works, but it fails after small changes because of broken alignment.
elder_george