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.