https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108199
Andreas Krebbel changed:
What|Removed |Added
Target||x86_64
Build||x86_64
Keywords||wrong-code
Host||x86_64
--- Comment #2 from Andreas Krebbel ---
The testcase does an assigned between two struct with endianess differing from
host endianess (assumed to be little). Here the required byteswaps are supposed
to cancel each other out. After that a bitfield comparison on the target struct
is done. This comparison uses the wrong byte offset into the bitfield:
testb $64, 7(%rdi)
jne .L11
On a big endian target the first bits in the bitfield are supposed to reside in
the first bytes in memory.
The problem appears to get introduced when dead store elimination removes the
assignment to the target struct in FRE.
Before FRE we have the following:
_1 = src_6(D)->a; bswap
dst$val_9 = _1; bswap
_2 = BIT_FIELD_REF ; bswap
_3 = _2 & 64;
if (_3 != 0)
...
This would result in 3 bswaps chained to each other. However, after FRE we have
only two because the dead store to dst$val is removed.
_1 = src_6(D)->a;
_2 = BIT_FIELD_REF <_1, 8, 0>;
_3 = _2 & 64;
if (_3 != 0)
Now we have only which cancel each other out.
Looks like we have to prevent depending stores/loads with different endianess
from getting removed - perhaps by making them also volatile? I think we have to
keep the number of memory accesses with foreign endianess constant over the
optimizations.