https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127011

Uroš Bizjak <ubizjak at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
          Component|target                      |rtl-optimization
                 CC|                            |jakub at redhat dot com

--- Comment #2 from Uroš Bizjak <ubizjak at gmail dot com> ---
The abort site has:

/* If asm goto has a crossing fallthrough edge
   and at least one of the labels to the same bb,
   force_nonfallthru can result in the fallthrough
   edge being redirected and a new edge added for the
   label or more labels to e->dest. ... See PR108596.  */
rtx_insn *j = BB_END (cur_bb);
gcc_checking_assert (JUMP_P (j)
                     && (asm_noperands (PATTERN (j)) > 0));

This fires whenever force_nonfallthru on a crossing fall-through edge causes
EDGE_COUNT (cur_bb->succs) to grow beyond what it was before the call. The
PR108596 fix assumed that can only happen for an asm goto whose label operand
aliases the fallthrough target, hence the asm_noperands (...) > 0 check.

xbegin has the same shape:

--cut here--
(define_expand "xbegin"
  ...
{
  rtx_code_label *label = gen_label_rtx ();
  ...
  emit_jump_insn (gen_xbegin_1 (ax_reg, label));
  emit_label (label);
  ...
})

(define_insn "xbegin_1"
  [(set (pc)
        (if_then_else (ne (unspec [(const_int 0)] UNSPEC_XBEGIN_ABORT)
(const_int 0))
                      (label_ref (match_operand 1))
                      (pc)))
   ...]
  "xbegin\t%l1")
---cut here--

xbegin_1 is a conditional jump_insn whose only label target is the label
emitted immediately after it — i.e. its fallthrough edge and its explicit jump
edge point at the exact same destination block.

force_nonfallthru_and_redirect in cfgrtl.cc is not asm-specific:

if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
    && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
    && any_condjump_p (BB_END (e->src))
    && JUMP_LABEL (BB_END (e->src)) == BB_HEAD (e->dest))
  {
    edge b = unchecked_make_edge (e->src, target, 0);
    redirected = redirect_jump (as_a <rtx_jump_insn *> (BB_END (e->src)),
                                block_label (target), 0);
    ...
  }

any_condjump_p (BB_END (e->src)) && JUMP_LABEL (...) == BB_HEAD (e->dest)
matches xbegin_1 exactly — "conditional jump to the next instruction." This
branch unconditionally adds an extra edge (unchecked_make_edge) whenever that
pattern is hit, with zero connection to asm_noperands.

x86 defaults to -freorder-blocks-and-partition on at -O2, so bbpart runs. The
noreturn function falling off the end synthesizes a trap/unreachable tail that
ends up cold, forcing partition fixups on the preceding blocks. When that fixup
reaches the block ending in xbegin_1, force_nonfallthru takes the generic
condjump-to-fallthrough path above, bumps cur_bb's successor count, and back in
fix_up_fall_thru_edges the EDGE_COUNT (cur_bb->succs) > old_count check assumes
this can only come from asm goto — j is xbegin_1, asm_noperands returns -1,
assert fails, abort.

The asm goto isn't the direct trigger of the abort — it's what produces the
crossing edge that starts the fixup walk; xbegin_1 is what actually violates
the assert.

The assert/comment in fix_up_fall_thru_edges needs to be generalized from "is
this an asm goto" to "is this the same condjump-to-own-fallthrough shape
force_nonfallthru_and_redirect special-cases" — i.e. mirror any_condjump_p (j)
&& JUMP_LABEL (j) == <old fallthrough label> rather than asm_noperands (PATTERN
(j)) > 0.

CC author of the added assert.

Claude Sonnet 5 was used during analysis.

Reply via email to