https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108656
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |hubicka at gcc dot gnu.org, | |rguenth at gcc dot gnu.org --- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> --- I think the problem is in the bogus combination of attributes, pure (or const) and returns_twice. For returns_twice we force the call to be the first statement in a bb (stmt_starts_bb_p returns true for it) with an AB edge to it and expect it to be the last one as well with an AB edge out of it. For normal returns_twice calls that is the case, the fact that there is returns_twice results in cfun->calls_setjmp and in that case call_can_make_abnormal_goto will be true (so among others the call is marked as ctrl altering and eventually stmt_ends_bb_p). But if returns_twice is mixed with const, pure or leaf attributes, this all falls apart. The exact reason for the -fcompare-debug failure is that we have the weird ;; basic block 4, loop depth 0, maybe hot ;; prev block 3, next block 5, flags: (NEW) ;; pred: 3 (FALLTHRU) ;; 5 (ABNORMAL,DFS_BACK) # _5(ab) = PHI <_12(3), _6(ab)(5)> _2 = bar (); _14 = corge (_2, _5(ab)); goto <bb 6>; [INV] ;; succ: 6 (FALLTHRU) ;; 5 (ABNORMAL) pre-einline (note, corge isn't pure/const/leaf and so unlike bar is assumed to maybe doing abnormal goto), einline turns it into: ;; basic block 3, loop depth 0, maybe hot ;; prev block 2, next block 4, flags: (NEW, REACHABLE) ;; pred: 2 (FALLTHRU) ;; 4 (ABNORMAL,DFS_BACK) # _5(ab) = PHI <_12(2), _6(ab)(4)> # DEBUG BEGIN_STMT baz (); # DEBUG BEGIN_STMT _19 = 0; _2 = _19; _14 = corge (_2, _5(ab)); goto <bb 5>; [INV] ;; succ: 5 (FALLTHRU) ;; 4 (ABNORMAL) (with the debug stmts missing for -g0), no returns_twice nor anything else actually needing abnormal stuff in the cfg, but bar wasn't the last stmt in bb, so no purging was done. Later on, expand_calL_inline is called on the bb which has just ;; basic block 3, loop depth 0, maybe hot ;; prev block 2, next block 4, flags: (NEW, REACHABLE) ;; pred: 2 (FALLTHRU) ;; 4 (ABNORMAL,DFS_BACK) # _5(ab) = PHI <_12(2), _6(ab)(4)> # DEBUG BEGIN_STMT baz (); # DEBUG BEGIN_STMT goto <bb 5>; [INV] ;; succ: 5 (FALLTHRU) ;; 4 (ABNORMAL) and return_block is after splitting in one case just baz (); call and in another case baz () call + debug stmt. /* If the GIMPLE_CALL was in the last statement of BB, it may have been the source of abnormal edges. In this case, schedule the removal of dead abnormal edges. */ gsi = gsi_start_bb (return_block); gsi_next (&gsi); purge_dead_abnormal_edges = gsi_end_p (gsi); So, purge_dead_abnormal_edges is set for -g0 but not -g and as after inlining baz there is nothing that would need an abnormal edge, we drop .ABNORMAL_DISPATCHER in the former case and not the latter. I wonder if we shouldn't reject mixing const/pure/leaf attributes with returns_twice, like we already warn and ignore returns_twice attribute when mixed with noreturn. Or, I think we'd need to make sure returns_twice results in call_can_make_abnormal_goto true, and perhaps stmt_can_terminate_bb_p true too. Though, still I wonder what will happen if we DCE the returns_twice calls, wonder if we at least drop the abnormal successor edges then.