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.

Reply via email to