I have a class that has 2 pointers to a external memory p_Data and p_DataWrite. Most of the time, both of those pointers point to the same memory and are used to read said memory (p_Data) or write said memory (p_DataWrite). I now have a case in which I write the memory (using p_DataWrite), then read the memory (using p_Data). When I compile this with clang++ for the ARMv7 platform for Linux using O2 I get the effect, that the memory gets read first und written afterwards. I tried using the p_Data pointer to write the memory and the effect is gone. That is not a option for the project.
I see the effect only for ARMv7 Linux with at least O2. I also build my project for x86_64 Linux and for x64 Windows and can compile with O2 and above without this issue.
How can I tell the compiler/optimizer that those two pointers are the 'same' and it is not allowed to change the execution order?
Edit Add Example Code:
*((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;
translates to
; *((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
Compile with -fno-strict-aliasing
.
In *((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
you write to the address using the type unsigned int
. This differs from the type used to access the address in other lines, where unsigned short
is used.
Accessing the same memory with two different types other than as listed in C++ 2020 7.2.1 [basic.lval] 11 violates the aliasing rule in that paragraph. Then the behavior is not defined by the C++ standard. The import of this is that the compiler does not have to treat an access as unsigned int
and an access as unsigned short
as if they might access the same memory. So the optimizer is free to rearrange this code as if the addresses were different.
Clang has a feature to tell the compiler to support aliasing memory with different types, and the -fno-strict-aliasing
switch requests that.
Alternatively, you could modify the code to use only unsigned short
to access the memory, separating the write of 0x12345678
into two writes of an unsigned short
.