Hi! The following testcase is miscompiled on s390x. The problem is that there is massive cross-jumping going on, and after that post_order_compute decides to call tidy_fallthru_edges, including on an edge from a bb ending with a table jump to a bb with now a single successor where all the jump_table_data entries point to. rtl_tidy_fallthru_edge happily removes the tablejump and anything in between the current bb and next bb (i.e. jump_table_data + its code_label + barrier if any), but doesn't care about any possible uses of the code_label (on the testcase e.g. the label reference is hoisted before the loop). Now, if I try some artificial testcase like: int a; #define A(n) case n: a++; break; #define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) A(n##5) A(n##6) A(n##7) A(n##8) A(n##9) #define C(n) B(n##0) B(n##1) B(n##2) B(n##3) B(n##4) B(n##5) B(n##6) B(n##7) B(n##8) B(n##9)
void foo (int x) { switch (x) { C(1) } } say on x86_64, tidy_fallthru_edges isn't called at all (it would be only if there are unrelated unreachable blocks in the function at the same time), so I think spending time on trying to handle tablejump_p right in rtl_tidy_fallthru_edge is wasteful, my preference (for both 4.9 and trunk) would be as the patch below just not handle tablejump_p in that function, and for trunk perhaps try to handle it elsewhere where it will be optimized even for the above testcase (somewhere in cfgcleanup?). Also, eventually it would be really nice if tree-ssa-tail-merge.c could handle this already at the GIMPLE level. Thoughts on this? Bootstrapped/regtested on x86_64-linux and i686-linux on the trunk and on {x86_64,i686,ppc64,ppc64le,s390,s390x,armv7hl}-linux on 4.9 branch. 2015-01-09 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/64536 * cfgrtl.c (rtl_tidy_fallthru_edge): Don't remove tablejumps. * gcc.dg/pr64536.c: New test. --- gcc/cfgrtl.c.jj 2015-01-05 13:07:12.000000000 +0100 +++ gcc/cfgrtl.c 2015-01-08 17:03:18.511218340 +0100 @@ -1782,10 +1782,14 @@ rtl_tidy_fallthru_edge (edge e) if (INSN_P (q)) return; + q = BB_END (b); + /* Don't remove table jumps here. */ + if (tablejump_p (q, NULL, NULL)) + return; + /* Remove what will soon cease being the jump insn from the source block. If block B consisted only of this single jump, turn it into a deleted note. */ - q = BB_END (b); if (JUMP_P (q) && onlyjump_p (q) && (any_uncondjump_p (q) --- gcc/testsuite/gcc.dg/pr64536.c.jj 2015-01-08 17:13:32.218929003 +0100 +++ gcc/testsuite/gcc.dg/pr64536.c 2015-01-08 17:28:56.758428958 +0100 @@ -0,0 +1,67 @@ +/* PR rtl-optimization/64536 */ +/* { dg-do link } */ +/* { dg-options "-O2" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +struct S { long q; } *h; +long a, b, g, j, k, *c, *d, *e, *f, *i; +long *baz (void) +{ + asm volatile ("" : : : "memory"); + return e; +} + +void +bar (int x) +{ + int y; + for (y = 0; y < x; y++) + { + switch (b) + { + case 0: + case 2: + a++; + break; + case 3: + a++; + break; + case 1: + a++; + } + if (d) + { + f = baz (); + g = k++; + if (&h->q) + { + j = *f; + h->q = *f; + } + else + i = (long *) (h->q = *f); + *c++ = (long) f; + e += 6; + } + else + { + f = baz (); + g = k++; + if (&h->q) + { + j = *f; + h->q = *f; + } + else + i = (long *) (h->q = *f); + *c++ = (long) f; + e += 6; + } + } +} + +int +main () +{ + return 0; +} Jakub