我用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)是正确的,但第一个是错误的。我不知道为什么会这样。
答案 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);