On Wed, 11 Feb 2026, Jakub Jelinek wrote:

> Hi!
> 
> force_nonfallthru_and_redirect has some extra code to handle asm gotos
> if we are forcing or redirecting the EDGE_FALLTHRU in case.  This was
> done for PR51767, PR53589, PR54127.
> It is done for the cases where some asm goto label points to the bb
> after the fallthru edge (i.e. there is edge sharing between the fallthru
> and the label, partly or fully degenerate asm goto) and/or if the label
> points to the TARGET bb (before/after).
> In such case it changes the label from e->dest's label to target's label
> and similarly to the case of 2+ successor e->src a new bb is created
> as new fallthru from e->src and in the asm goto case an additional edge
> is added, so there is
>  |
> asm goto -----+    maybe other edges
>  | fallthru    \
>  v              v
>  jumpblock -> target
> and the jumpblock -> target edge isn't EDGE_FALLTHRU.
> This was done that way to fix various ICEs with the degenerate asm gotos,
> see above for list.
> I believe it will still ICE if we decide to force_nonfallthru_and_redirect
> E bb5->bb6 to l2, because in that case there are already two+ edges, one
> pointing from bb5->l2 and we create another edge bb5->l2:
> bb5:
> asm goto ("" : : : : (l2));
> bb6:
> ...
> l2:
> but maybe nothing tries that in that case.  Anyway, the reason why
> the following two (PR116600 and PR123386) testcases are miscompiled is
> that we try to (during shrink-wrapping) emit some insns on the bb3->bb7
> edge, and see bb7 predecessor edge is EDGE_FALLTHRU in:
> bb3:
>   __asm__ goto ("" : : : : d);
>   if (c)
>     bar (a);
> bb6:
>   __asm__ goto ("" : : : : d);
> d: // == bb7
> in rtl_split_edge:
>   /* We are going to place the new block in front of edge destination.
>      Avoid existence of fallthru predecessors.  */
>   if ((edge_in->flags & EDGE_FALLTHRU) == 0)
>     {
>       edge e = find_fallthru_edge (edge_in->dest->preds);
> 
>       if (e)
>         force_nonfallthru (e);
>     }
> Now, the asm goto in bb6 is degenerate, so shrink-wrapping isn't aware
> that there would be multiple edges from it, there is just single one.
> But we still while splitting the bb3->bb7 edge in order to emit there
> pending insns on that edge turn the single successor asm goto bb into
> one with two successors (initially with two different ways to reach
> the same destination).  But unfortunately such change confuses the
> shrink-wrapping logic which isn't aware of such a change and so the
> separate shrink wrapping insns end up just on one of the paths instead
> of being on both, and we then ICE in dwarf2 pass because there is an
> disagreement on the CFI state (of course it is a wrong-code too).
> 
> Note, force_nonfallthru calls force_nonfallthru_and_redirect with
> target set to e->dest.
> 
> The following patch reworks this.
> Instead of creating that
>  |
> asm goto -----+    maybe other edges
>  | fallthru    \
>  v              v
>  jumpblock -> target
> for initially degenerate asm goto we now create
>  |
> asm goto    maybe other edges
>  | fallthru
>  v        
>  jumpblock -> target
> i.e. the asm goto keeps being degenerate, all we've changed is adding
> a new bb on the fallthru edge and making the edge from that new bb
> non-fallthru.  Furthermore, for the case where there would be before
> an asm goto -> target edge before for the e->dest != target case,
> those edges are untouched.
> For the immediate effect after the operation, the asm goto keeps
> the existing behavior, if it falls through, it will reach target
> by hopping through jumpblock, if it jumps to that label, previously
> it jumped directly to target, now it jumps to jumpblock and from there
> to target.  But shrink-wrapping etc. then put the right fixups everywhere
> where it belongs.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Richard.

> 2026-02-10  Jakub Jelinek  <[email protected]>
> 
>       PR rtl-optimization/116600
>       PR middle-end/123386
>       * cfgrtl.cc (force_nonfallthru_and_redirect): Don't do any
>       asm goto adjustments early, only note in asm_goto_edge if
>       any labels point originally to e->dest head.  After jumpblock
>       creation don't add an extra edge for asm_goto_edge, instead
>       adjust those labels pointing to former e->dest head to point
>       to jumpblock instead.
> 
>       * gcc.c-torture/compile/pr116600.c: New test.
>       * gcc.c-torture/compile/pr123386.c: New test.
> 
> --- gcc/cfgrtl.cc.jj  2026-01-09 21:59:08.701543900 +0100
> +++ gcc/cfgrtl.cc     2026-02-10 11:04:06.811401150 +0100
> @@ -1594,54 +1594,20 @@ force_nonfallthru_and_redirect (edge e,
>      }
>  
>    /* If e->src ends with asm goto, see if any of the ASM_OPERANDS_LABELs
> -     don't point to the target or fallthru label.  */
> +     don't point to the fallthru label.  */
>    if (JUMP_P (BB_END (e->src))
>        && target != EXIT_BLOCK_PTR_FOR_FN (cfun)
>        && (e->flags & EDGE_FALLTHRU)
>        && (note = extract_asm_operands (PATTERN (BB_END (e->src)))))
>      {
> -      int i, n = ASM_OPERANDS_LABEL_LENGTH (note);
> -      bool adjust_jump_target = false;
> +      int n = ASM_OPERANDS_LABEL_LENGTH (note);
>  
> -      for (i = 0; i < n; ++i)
> -     {
> -       if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
> -         {
> -           LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))--;
> -           XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target);
> -           LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))++;
> -           adjust_jump_target = true;
> -         }
> -       if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (target))
> +      for (int i = 0; i < n; ++i)
> +     if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
> +       {
>           asm_goto_edge = true;
> -     }
> -      if (adjust_jump_target)
> -     {
> -       rtx_insn *insn = BB_END (e->src);
> -       rtx note;
> -       rtx_insn *old_label = BB_HEAD (e->dest);
> -       rtx_insn *new_label = BB_HEAD (target);
> -
> -       if (JUMP_LABEL (insn) == old_label)
> -         {
> -           JUMP_LABEL (insn) = new_label;
> -           note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
> -           if (note)
> -             remove_note (insn, note);
> -         }
> -       else
> -         {
> -           note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
> -           if (note)
> -             remove_note (insn, note);
> -           if (JUMP_LABEL (insn) != new_label
> -               && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
> -             add_reg_note (insn, REG_LABEL_TARGET, new_label);
> -         }
> -       while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
> -              != NULL_RTX)
> -         XEXP (note, 0) = new_label;
> -     }
> +         break;
> +       }
>      }
>  
>    if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || 
> asm_goto_edge)
> @@ -1680,15 +1646,45 @@ force_nonfallthru_and_redirect (edge e,
>           and the reg crossing note should be removed.  */
>        fixup_partition_crossing (new_edge);
>  
> -      /* If asm goto has any label refs to target's label,
> -      add also edge from asm goto bb to target.  */
> +      /* If asm goto has any label refs to e->dest, change them to point
> +      to jump_block instead.  */
>        if (asm_goto_edge)
>       {
> -       new_edge->probability /= 2;
> -       jump_block->count /= 2;
> -       edge new_edge2 = make_edge (new_edge->src, target,
> -                                   e->flags & ~EDGE_FALLTHRU);
> -       new_edge2->probability = probability - new_edge->probability;
> +       int n = ASM_OPERANDS_LABEL_LENGTH (note);
> +
> +       for (int i = 0; i < n; ++i)
> +         if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
> +           {
> +             LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))--;
> +             XEXP (ASM_OPERANDS_LABEL (note, i), 0)
> +               = block_label (jump_block);
> +             LABEL_NUSES (XEXP (ASM_OPERANDS_LABEL (note, i), 0))++;
> +           }
> +
> +       rtx_insn *insn = BB_END (new_edge->src);
> +       rtx note;
> +       rtx_insn *old_label = BB_HEAD (e->dest);
> +       rtx_insn *new_label = BB_HEAD (jump_block);
> +
> +       if (JUMP_LABEL (insn) == old_label)
> +         {
> +           JUMP_LABEL (insn) = new_label;
> +           note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
> +           if (note)
> +             remove_note (insn, note);
> +         }
> +       else
> +         {
> +           note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
> +           if (note)
> +             remove_note (insn, note);
> +           if (JUMP_LABEL (insn) != new_label
> +               && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
> +             add_reg_note (insn, REG_LABEL_TARGET, new_label);
> +         }
> +       while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
> +              != NULL_RTX)
> +         XEXP (note, 0) = new_label;
>       }
>  
>        new_bb = jump_block;
> --- gcc/testsuite/gcc.c-torture/compile/pr116600.c.jj 2026-02-10 
> 11:24:22.840629711 +0100
> +++ gcc/testsuite/gcc.c-torture/compile/pr116600.c    2026-02-10 
> 11:24:15.386757048 +0100
> @@ -0,0 +1,24 @@
> +/* PR rtl-optimization/116600 */
> +
> +int a, b;
> +int foo ();
> +
> +int
> +bar ()
> +{
> +  int c = ({ int d = 0, e = foo ();
> +          b = __builtin_expect (e, 1); if (b) ; else d = 4; d; });
> +  if (c)
> +    return c;
> +  foo ();
> +  if (a)
> +    __asm__ goto ("" : : : : l);
> +l:
> +  return 0;
> +}
> +
> +void
> +baz ()
> +{
> +  bar ();
> +}
> --- gcc/testsuite/gcc.c-torture/compile/pr123386.c.jj 2026-02-10 
> 11:13:55.634344133 +0100
> +++ gcc/testsuite/gcc.c-torture/compile/pr123386.c    2026-02-10 
> 11:13:34.528704662 +0100
> @@ -0,0 +1,25 @@
> +/* PR middle-end/123386 */
> +
> +char *a;
> +int b;
> +
> +void
> +foo (char *)
> +{
> +  if (b)
> +    __builtin_abort ();
> +}
> +
> +void
> +bar (char *c)
> +{
> +  __asm__ goto ("" : : : : d);
> +  foo (a);
> +  __asm__ goto ("" : : : : d);
> +  if (c)
> +    bar (a);
> +  __asm__ goto ("" : : : : d);
> +d:
> +  if (b)
> +    __builtin_abort ();
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to