我编写了一个非常简单的程序,没有-O2,它的行为正常:

#include <stdio.h>
#include <stdint.h>

int main()
{
    uint32_t A[4] = { 1, 2, 3, 4 };
    float B[4] = { 0, 0, 0, 0 };
    float C[4] = { 5, 6, 7, 8 };
    int i;

    // convert integer A to float B
    for (i = 0; i < 4; i++)
        B[i] = (float)A[i];

    // memory copy from B to C
    uint32_t *src = (uint32_t*)(B);
    uint32_t *dst = (uint32_t*)(C);
    dst[0] = src[0];
    dst[1] = src[1];
    dst[2] = src[2];
    dst[3] = src[3];

#if 0
    // open this to correct the error
    __asm__("":::"memory");
#endif

    // print C, C should be [1.0, 2.0, 3.0, 4.0]
    for (i = 0; i < 4; i++)
        printf("%f\n", C[i]);

    return 0;
}


不使用-O2进行编译:

$ gcc error.c -o error
$ ./error
1.0000
2.0000
3.0000
4.0000

它按预期工作。但是,如果我添加了-O2:
$ gcc -O2 error.c -o error
$ ./error
-6169930235904.000000
0.000000
-6169804406784.000000
0.000000

另外,如果将#if 0切换为#if 1,它将再次正常工作。 asm ("":::"memory")在同一线程中应该没有必要。

这是-O2优化的错误吗?

有什么我可以告诉编译器注意的吗?我有一个函数可以将xmm寄存器存储到(void *)指针,例如:

inline void StoreRegister(void *ptr, const __m128& reg)
{
#if DONT_HAVE_SSE
    const uint32_t *src = reinterpret_cast<const uint32_t*>(&reg);
    uint32_t *dst = reinterpret_cast<uint32_t*>(ptr);
    dst[0] = src[0];
    dst[1] = src[1];
    dst[2] = src[2];
    dst[3] = src[3];
#else
    _mm_storeu_si128(reinterpret_cast<__m128*>(ptr), _mm_castps_si128(reg));
#endif
}
dst是上面代码中的C,可以在不修改函数签名的情况下使其正确。

最佳答案

不,这不是编译器错误的体现。

相反,由于您使用了强制转换(uint32_t*)(B)&c的结果,因此代码的行为是不确定的。这违反了严格的别名。

编译器-特别是gcc-在处理未定义的构造时正变得越来越积极。标准允许它们假定未发生未定义的行为,并且可以删除包含该行为的任何分支。

关于c++ - 是gcc -O2优化错误(与-O1不同的结果)吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61370485/

10-11 16:43