告诉优化器(O2)两个指针是“相同的”(LLVM Linux Armv7)

问题描述 投票:0回答:1

我有一个类,它有 2 个指向外部存储器的指针 p_Data 和 p_DataWrite。大多数时候,这两个指针都指向同一内存,并用于读取所述内存(p_Data)或写入所述内存(p_DataWrite)。我现在有一个情况,我写入内存(使用 p_DataWrite),然后读取内存(使用 p_Data)。当我使用 O2 在 Linux 的 ARMv7 平台上使用 clang++ 编译此代码时,我得到的效果是首先读取内存,然后写入内存。我尝试使用p_Data指针写入内存,效果没有了。这不是该项目的选择。

我只看到至少具有 O2 的 ARMv7 Linux 的效果。我还为 x86_64 Linux 和 x64 Windows 构建了我的项目,并且可以使用 O2 及更高版本进行编译,而不会出现此问题。

如何告诉编译器/优化器这两个指针是“相同的”并且不允许更改执行顺序?

编辑添加示例代码:

        *((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;

        unsigned short In_Word = *((unsigned short *)IN_Class.p_DataUser + 0);
        unsigned short Out_Word = (unsigned short)((In_Word >> 8) | (In_Word << 8));

        In_Word = *((unsigned short *)IN_Class.p_DataUser + 1);

        *((unsigned short *)OUT_CLass.p_DataUserWrite + 1) = Out_Word;
        Out_Word = (In_Word >> 8) | (In_Word << 8);
       
        *((unsigned short *)OUT_CLass.p_DataUserWrite) = Out_Word;

翻译为

;         *((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
   1f2b8: e5923034      ldr r3, [r2, #0x34]
   1f2bc: e5920030      ldr r0, [r2, #0x30]
;         *((unsigned short *)OUT_CLass.p_DataUserWrite + 1) = Out_Word;
   1f2c0: e5911030      ldr r1, [r1, #0x30]
;         unsigned short In_Word = *((unsigned short *)IN_Class.p_DataUser + 0);
   1f2c4: e1d320b0      ldrh    r2, [r3]
;         In_Word = *((unsigned short *)IN_Class.p_DataUser + 1);
   1f2c8: e1d330b2      ldrh    r3, [r3, #2]
;         *((unsigned short *)OUT_CLass.p_DataUserWrite + 1) = Out_Word;
   1f2cc: e6bf2fb2      rev16   r2, r2
   1f2d0: e1c120b2      strh    r2, [r1, #2]
   1f2d4: e3052678      movw    r2, #0x5678
   1f2d8: e3412234      movt    r2, #0x1234
;         *((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
   1f2dc: e5802000      str r2, [r0]
;         *((unsigned short *)OUT_CLass.p_DataUserWrite) = Out_Word;
   1f2e0: e6bf0fb3      rev16   r0, r3
   1f2e4: e1c100b0      strh    r0, [r1]
;     }
   1f2e8: e12fff1e      bx  lr

c++ compiler-optimization clang++
1个回答
0
投票

使用

-fno-strict-aliasing
进行编译。

*((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
中,您使用类型
unsigned int
写入地址。这与其他行中用于访问地址的类型不同,其中使用
unsigned short

使用 C++ 2020 7.2.1 [basic.lval] 11 中列出的两种不同类型访问同一内存违反了该段落中的别名规则。那么该行为不是由 C++ 标准定义的。其重要性在于,编译器不必将访问视为

unsigned int
并将访问视为
unsigned short
,就好像它们可能访问相同的内存一样。因此优化器可以自由地重新排列此代码,就好像地址不同一样。

Clang 有一个功能可以告诉编译器支持不同类型的别名内存,并且

-fno-strict-aliasing
开关要求这样做。

或者,您可以修改代码以仅使用

unsigned short
来访问内存,将
0x12345678
的写入分为两次
unsigned short
的写入。

© www.soinside.com 2019 - 2024. All rights reserved.