https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70341
--- Comment #15 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Created attachment 45789 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=45789&action=edit gcc9-pr70341.patch Untested fix for e.g.: #define A(N) void foo##N (int); #define B(N) A(N##0) A(N##1) A(N##2) A(N##3) #define C(N) B(N##0) B(N##1) B(N##2) B(N##3) #define D C(1) C(2) D struct E { int a, b, c, d; }; struct F { struct E e[1]; }; void test (struct F *x, int y) { struct E *p = &x->e[y]; #undef A #define A(N) case N: foo##N (p->c); break; switch (p->b) { D default: __builtin_unreachable (); } } at -O2 on both arm and aarch64 - by making sure the casesi MEM load is mem/u/c try_head_merge_bb is willing to move over the loads across the casesi.