9

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
pavium
  • 14,808
  • 4
  • 33
  • 50
psihodelia
  • 29,566
  • 35
  • 108
  • 157
  • The questions wasn't so hard, and I don't consider myself an gcc expert. Next time use a more harmless title, I almost skipped the question. – Gunther Piez Nov 20 '09 at 18:49

3 Answers3

17

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]);

Gunther Piez
  • 29,760
  • 6
  • 71
  • 103
  • 1
    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 Nov 20 '09 at 22:29
  • 2
    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". – Gunther Piez Nov 21 '09 at 00:24
  • 1
    Yes, @drhirsh is right, for sample provided by @psihodelia my solution works, but it fails after small changes because of broken alignment. – elder_george Nov 21 '09 at 07:33
6

Note that gcc 4.6 now supports subscripted vectors:

In C vectors can be subscripted as if the vector were an array with the same number of elements and base type. Out of bound accesses invoke undefined behavior at runtime. Warnings for out of bound accesses for vector subscription can be enabled with -Warray-bounds.

Alexandre Hamez
  • 7,725
  • 2
  • 28
  • 39
5

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
  • 7,849
  • 24
  • 31