使用AVX指令和-O3编译选项获得错误的结果

时间:2015-03-27 19:20:39

标签: c compiler-optimization avx

我用AVX指令编写了非常简单的程序,但是当我使用-O3选项编译代码和g ++编译器的-O1选项时,我得到的结果不同,这是我的代码:

int main(int argc, char *argv[])
{

    int d = 120;
    __m256i r = _mm256_set1_epi32(d);
    int * p = (int *) &r;

    printf("r[0]: %d, ",p[0]);
    printf("r[1]: %d, ",p[1]);
    printf("r[2]: %d, ",p[2]);
    printf("r[3]: %d, ",p[3]);
    printf("r[4]: %d, ",p[4]);
    printf("r[5]: %d, ",p[5]);
    printf("r[6]: %d, ",p[6]);
    printf("r[7]: %d \n",p[7]);                    

    return 0;
}

这是我用这些选项编译时的输出(g ++ test1.c -o test1 -m64 -O3 -ffast-math -march = native -mavx):

r [0]:0,r [1]:0,r [2]:4195520,r [3]:0,r [4]: - 1880829792,r [5]:32767,r [6] :0,r [7]:0

这是我使用这些选项编译时的输出(g ++ test1.c -o test1 -m64 -O1 -ffast-math -march = native -mavx):

r [0]:120,r [1]:120,r [2]:120,r [3]:120,r [4]:120,r [5]:120,r [6]: 120,r [7]:120

第二个结果(-O1)是正确的,但第一个是错误的。我不知道为什么会这样。

2 个答案:

答案 0 :(得分:6)

禁用严格别名会降低整个程序的性能!

&r投射到(int*)没有已定义的行为。 __m256i r是一个固有的AVX寄存器,不一定映射到内存。通过获取指针,可以强制编译器将其写入内存,并且最终可能会将其映射到int [8]向量。

它可能适用于某些编译器,有些选项,在某些情况下。但是,您不应该在代码中使用它,因为它可能会停止工作而不会发出警告。

“定义行为”的方式是:

int[8] p;
_mm256_storeu_si128((__m256i*)p, r);
printf("r[0]: %d, ",p[0]);
printf("r[1]: %d, ",p[1]);
printf("r[2]: %d, ",p[2]);
printf("r[3]: %d, ",p[3]);
printf("r[4]: %d, ",p[4]);
printf("r[5]: %d, ",p[5]);
printf("r[6]: %d, ",p[6]);
printf("r[7]: %d \n",p[7]); 

然后你明确地将寄存器写入内存。这将做同样的事情,但无论编译器选项如何都将始终有效。由于禁用严格别名会降低整体代码优化,因此整个程序运行速度更快。

答案 1 :(得分:1)

我刚看了你的评论说你已经解决了问题,但在搜索引擎上它仍然显示为"没有回答",这对有类似问题的人有点误导。这里的原始答案实际上是错误的,但原始海报还没有改变正确答案的答案,所以我会更新这个答案。

简短的回答是,将&r投射到(int*)没有明确的行为。有关详细信息,请参阅galinette的答案。

执行此操作的已定义行为方式是将寄存器显式写入内存:

int[8] p;
_mm256_storeu_si128((__m256i*)p, r);
相关问题