Hi! In the following testcase, we have initially during RTL expansion a call which can throw, followed by fallthrough into an empty block with two similar predecessors (both calling the same function) and with a fallthrough into an empty block with no successors (__builtin_unreachable). That last block is optimized away soon and in the cfglayout mode we have a bb with no successors that has a BARRIER in BB_FOOTER. During cfg cleanup during combine we actually optimize away even that other empty bb with no successors, but end up not putting a BARRIER into BB_FOOTER of the bb with a call. There is in the following hunk in try_optimize_cfg code to handle that, but a) it assumes a BARRIER has to be the first in BB_FOOTER, which as all other spots I've found don't assume, even for the non-cfglayout mode a few lines below we call get_last_bb_insn which walks the following insn chain (note, this isn't a problem on this exact testcase though) and b) punt if e->src bb already has non-NULL BB_FOOTER (that is what breaks this testcase - the testcase has a NOTE_INSN_DELETED_LABEL in BB_FOOTER, but of course no BARRIER, we don't add one here and later on when outof_cfglayout we ICE because there is no BARRIER after a bb that doesn't fall thru). Apparently there is a function which can handle adding a barrier, both into an empty BB_FOOTER as well as when there is a BB_FOOTER, but doesn't contain a BARRIER in there.
So, this patch fixes both issues. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2019-04-12 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/90026 * cfgcleanup.c (try_optimize_cfg): When removing empty bb with no successors, look for BARRIERs inside of the whole BB_FOOTER chain rather than just at the start of it. If e->src BB_FOOTER is not NULL in cfglayout mode, use emit_barrier_after_bb. * g++.dg/opt/pr90026.C: New test. --- gcc/cfgcleanup.c.jj 2019-03-09 09:25:11.743785011 +0100 +++ gcc/cfgcleanup.c 2019-04-11 11:30:52.967173100 +0200 @@ -2712,23 +2712,23 @@ try_optimize_cfg (int mode) if (current_ir_type () == IR_RTL_CFGLAYOUT) { - if (BB_FOOTER (b) - && BARRIER_P (BB_FOOTER (b))) + rtx_insn *insn; + for (insn = BB_FOOTER (b); + insn; insn = NEXT_INSN (insn)) + if (BARRIER_P (insn)) + break; + if (insn) FOR_EACH_EDGE (e, ei, b->preds) - if ((e->flags & EDGE_FALLTHRU) - && BB_FOOTER (e->src) == NULL) + if ((e->flags & EDGE_FALLTHRU)) { - if (BB_FOOTER (b)) + if (BB_FOOTER (b) + && BB_FOOTER (e->src) == NULL) { BB_FOOTER (e->src) = BB_FOOTER (b); BB_FOOTER (b) = NULL; } else - { - start_sequence (); - BB_FOOTER (e->src) = emit_barrier (); - end_sequence (); - } + emit_barrier_after_bb (e->src); } } else --- gcc/testsuite/g++.dg/opt/pr90026.C.jj 2019-04-11 12:40:14.508840308 +0200 +++ gcc/testsuite/g++.dg/opt/pr90026.C 2019-04-11 12:39:43.431352423 +0200 @@ -0,0 +1,24 @@ +// PR rtl-optimization/90026 +// { dg-do compile } +// { dg-options "-fnon-call-exceptions -ftracer -O2 -w" } + +typedef __SIZE_TYPE__ size_t; +struct S { int *b; ~S () { delete b; } }; +void bar (); +char c[sizeof (int)]; + +void * +operator new (size_t, void *) +{ + __builtin_unreachable (); +} + +void +foo () +{ + S a; + if (a.b) + a.b = new int (); + bar (); + new (c) int (); +} Jakub