C - 如何使用GCC SSE向量扩展访问向量元素

psi*_*lia 9 gcc sse

通常我使用以下类型处理3D矢量:

typedef vec3_t float[3];
Run Code Online (Sandbox Code Playgroud)

使用smth初始化向量.喜欢:

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};
Run Code Online (Sandbox Code Playgroud)

并使用smth访问它们.喜欢:

x_basis[X] * y_basis[X] + ...
Run Code Online (Sandbox Code Playgroud)

现在我需要一个使用SSE指令的矢量算术.我有以下代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

GCC支持这种方式.但是......首先,它给了我0.00000的结果.其次,我无法访问这些向量的元素.我的问题是:我如何访问这些载体的元素?我需要smth.像[0]访问X元素,[1]访问Y元素等

PS:我使用以下代码编译此代码:

gcc -msse testgcc.c -o testgcc
Run Code Online (Sandbox Code Playgroud)

Gun*_*iez 17

访问元素的安全和推荐方法是使用union,而不是指针类型,这会欺骗编译器的别名检测机制,并可能导致代码不稳定.

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]);
Run Code Online (Sandbox Code Playgroud)

  • 看来我还不够清楚.使用指针键入punning是不好的,因为取消引用类型惩罚指针将破坏严格的别名规则.这导致未定义的行为.通过内联或宏观化不会更安全.但是你可以使用编译器选项_-fno-strict-aliasing_,它完全针对像这样的破坏代码.生成的二进制文件可能会稍慢,因为您拒绝编译器进行优化.在"-fstrict-aliasing"下的gcc.gnu.org/onlinedocs/gcc/...上阅读它及其原因. (2认同)

Ale*_*mez 6

请注意,gcc 4.6现在支持下标向量:

在C向量中可以下标,就像向量是具有相同数量的元素和基类型的数组一样.超出限制的访问在运行时调用未定义的行为.可以使用-Warray-bounds启用向量订阅的超出访问的警告.


eld*_*rge 5

您忘记了需要重新解释a为浮点数组.以下代码正常工作:

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;
}
Run Code Online (Sandbox Code Playgroud)

PS:感谢这个问题,我不知道gcc有这样的SSE支持.

更新:一旦数组未对齐,此解决方案将失败.提供的解决方案@drhirsh没有这个问题.

  • 打字是危险的. (5认同)