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

            Bug ID: 65401
           Summary: [5 Regression] make_field_assignment broken for
                    big-endian
           Product: gcc
           Version: 5.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jakub at gcc dot gnu.org

struct S { unsigned short s[64]; };

__attribute__((noinline, noclone)) void
foo (struct S *x)
{
  unsigned int i;
  unsigned char *s;

  s = (unsigned char *) x->s;
  for (i = 0; i < 64; i++)
    x->s[i] = s[i * 2] | (s[i * 2 + 1] << 8);
}  

int
main ()
{
  unsigned int i;
  struct S s;
  for (i = 0; i < 64; i++)
    s.s[i] = i + ((64 - i) << 8);
  foo (&s);
  for (i = 0; i < 64; i++)
    if (s.s[i] != (64 - i) + (i << 8))
      __builtin_abort ();
  return 0;
}

is miscompiled on s390x-linux with -m64 -march=z9-109 -mtune=z10 -O2 -fPIC
since r220249, but most likely has been latent before that.
make_field_assignment during combine misoptimizes:
(set (mem:HI (plus:DI (reg/v/f:DI 126 [ x ])
            (reg:DI 125 [ ivtmp.11 ])) [2 MEM[base: x_3(D), index: ivtmp.11_41,
offset: 0B]+0 S2 A16])
    (ior:HI (zero_extend:HI (mem:QI (plus:DI (reg/v/f:DI 126 [ x ])
                    (reg:DI 125 [ ivtmp.11 ])) [0 MEM[base: s_4, index:
ivtmp.11_41, offset: 0B]+0 S1 A8]))
        (subreg:HI (reg:SI 128 [ D.1536 ]) 2)))
into:
(set (mem:QI (plus:DI (reg/v/f:DI 126 [ x ])
            (reg:DI 125 [ ivtmp.11 ])) [2 MEM[base: x_3(D), index: ivtmp.11_41,
offset: 0B]+0 S1 A16])
    (subreg:QI (lshiftrt:SI (reg:SI 128 [ D.1536 ])
            (const_int 8 [0x8])) 3))
which is just wrong for big-endian.

Reply via email to