https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108199

Andreas Krebbel <krebbel at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Target|                            |x86_64
              Build|                            |x86_64
           Keywords|                            |wrong-code
               Host|                            |x86_64

--- Comment #2 from Andreas Krebbel <krebbel at gcc dot gnu.org> ---
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 <dst$val_9, 8, 0>;  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.

Reply via email to