https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71240
--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Perhaps better testcase that also shows a missed optimization: struct L { unsigned int l[2]; }; union U { double a; struct L l; } u; void foo (double a, struct L *p) { u.a = a; struct L l = u.l, m; m.l[0] = (((l.l[1] & 0xff000000) >> 24) | ((l.l[1] & 0x00ff0000) >> 8) | ((l.l[1] & 0x0000ff00) << 8) | ((l.l[1] & 0x000000ff) << 24)); m.l[1] = (((l.l[0] & 0xff000000) >> 24) | ((l.l[0] & 0x00ff0000) >> 8) | ((l.l[0] & 0x0000ff00) << 8) | ((l.l[0] & 0x000000ff) << 24)); *p = m; } void bar (double a, struct L *p) { foo (a, p); } Ideally we should turn this into a 64-bit bswap or at two 32-bit bswaps, but we manage to turn it only into one 32-bit bswap (the low 32-bits of the double). Guess not removing the BIT_FIELD_REF is not the right thing, we could have originally BIT_FIELD_REFs picking just 8 bits out of the double instead, like (which ICEs too): struct L { unsigned char l[8]; }; struct M { unsigned int m[2]; }; union U { double a; struct L l; } u; void foo (double a, struct M *p) { u.a = a; struct L l = u.l; struct M m; m.m[0] = l.l[7] | (l.l[6] << 8) | (l.l[5] << 16) | (l.l[4] << 24); m.m[1] = l.l[3] | (l.l[2] << 8) | (l.l[1] << 16) | (l.l[0] << 24); *p = m; } void bar (double a, struct M *p) { foo (a, p); } Here, we end up with src_stmt that has _7 = BIT_FIELD_REF <a_2(D), 8, 24>; but we'd still want to use BIT_FIELD_REF <a_2(D), 32, 0>. And again, we transform only one of the two bswaps. BTW, struct L { unsigned char l[8]; }; union U { double a; struct L l; } u; void foo (double a, unsigned long long *p) { u.a = a; struct L l = u.l; unsigned long long m; m = l.l[7] | (l.l[6] << 8) | (l.l[5] << 16) | (l.l[4] << 24); m |= ((unsigned long long) (l.l[3] | (l.l[2] << 8) | (l.l[1] << 16) | (l.l[0] << 24))) << 32; *p = m; } void bar (double a, unsigned long long *p) { foo (a, p); } isn't detected as 64-bit bswap either, but still ICEs. And struct L { unsigned char l[8]; }; union U { double a; struct L l; } u; void foo (double a, unsigned long long *p) { u.a = a; struct L l = u.l; unsigned long long m; m = l.l[7] | (l.l[6] << 8) | (l.l[5] << 16) | (l.l[4] << 24) | ((unsigned long long) l.l[3] << 32) | ((unsigned long long) l.l[2] << 40) | ((unsigned long long) l.l[1] << 48) | ((unsigned long long) l.l[0] << 56); *p = m; } void bar (double a, unsigned long long *p) { foo (a, p); } neither, but nothing is detected there at all.