On Wed, May 13, 2026 at 1:46 AM Andrew Pinski
<[email protected]> wrote:
>
> So the problem here is that group_case_labels_stmt can remove all
> cases if they all go directly to a BB just containing
> __builtin_unreachable. So we left with a switch which has one label
> left; the default case. Code in ifcvt (which is the pass right after
> this cleanup happens) is not ready for that case because well it is just
> an fallthrough at this point and it should not have to worry about it.
>
> I have not figured out why this only started to show up recently but
> it is definitely a latent bug since group_case_labels_stmt started removing
> case labels that go to a BB that contains __builtin_unreachable;
> r8-546-gca4d2851687875.

Huh, I didn't expect end_recording_case_labels to affect the CFG.  Which
is why I'm also worried about this patch ...

IMO this belongs to CFG cleanup.  I see we're recording case labels
only from two places, critical edge splitting, CFG cleanup itself and
uninit analysis.  Only CFG cleanup should have exposed the need
for r8-546, right?  So ... can we somehow move this all there?

> What this does is if group_case_labels_stmt returns true and we only
> have a default case left; remove the switch and change the flow into
> a fallthrough.
>
> There is some slight cleanups in end_recording_case_labels done
> with just using continue instead f indention to make it easier
> to read on what is going on.
>
> Bootstrapped and tested on x86_64-linux-gnu.
>
>         PR tree-optimization/125290
>
> gcc/ChangeLog:
>
>         * tree-cfg.cc (end_recording_case_labels): Fixup
>         case for only switch with default case left.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/torture/pr125290-1.c: New test.
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
>  gcc/testsuite/gcc.dg/torture/pr125290-1.c | 40 +++++++++++++++++++++++
>  gcc/tree-cfg.cc                           | 20 +++++++++---
>  2 files changed, 56 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr125290-1.c
>
> diff --git a/gcc/testsuite/gcc.dg/torture/pr125290-1.c 
> b/gcc/testsuite/gcc.dg/torture/pr125290-1.c
> new file mode 100644
> index 00000000000..6183cbd2681
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr125290-1.c
> @@ -0,0 +1,40 @@
> +/* PR tree-optimization/125290 */
> +/* { dg-do compile } */
> +
> +int g21;
> +int g31, f14f16_c12;
> +void f14f16()
> +{
> +    short v7;
> +    long v9;
> +    long v13;
> +    if (g31)
> +    {
> +        g21 = 0;
> +        switch (v7)
> +        {
> +            case 4:
> +            case 66: break;
> +            default: __builtin_unreachable();
> +        }
> +    }
> +    else
> +    {
> +    lbl_bf2:
> +        v9 = g21;
> +    }
> +    v13 = v9;
> +    switch (v13)
> +    {
> +        case 55:
> +        case 2: goto lbl_sw12;
> +        default:
> +            if (f14f16_c12)
> +                goto lbl_bf2;
> +            else
> +                return;
> +    }
> +lbl_sw12:
> +    __builtin_unreachable();
> +}
> +
> diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
> index b2968c412ed..da6d6b34da8 100644
> --- a/gcc/tree-cfg.cc
> +++ b/gcc/tree-cfg.cc
> @@ -1271,10 +1271,22 @@ end_recording_case_labels (void)
>    EXECUTE_IF_SET_IN_BITMAP (touched_switch_bbs, 0, i, bi)
>      {
>        basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
> -      if (bb)
> -       {
> -         if (gswitch *stmt = safe_dyn_cast <gswitch *> (*gsi_last_bb (bb)))
> -           group_case_labels_stmt (stmt);
> +      if (!bb)
> +       continue;
> +      gswitch *stmt = safe_dyn_cast <gswitch *> (*gsi_last_bb (bb));
> +      if (!stmt)
> +       continue;
> +      if (group_case_labels_stmt (stmt)
> +         && gimple_switch_num_labels (stmt) == 1)
> +       {
> +         /* group_case_labels_stmt can remove all
> +            cases except for the default (via __builtin_unreachable())
> +            so fixup that case. */
> +         edge taken_edge = single_succ_edge (bb);
> +         auto gsi = gsi_last_bb (bb);
> +         gsi_remove (&gsi, true);
> +         taken_edge->flags &= ~(EDGE_TRUE_VALUE|EDGE_FALSE_VALUE);
> +         taken_edge->flags |= EDGE_FALLTHRU;
>         }
>      }
>    BITMAP_FREE (touched_switch_bbs);
> --
> 2.43.0
>

Reply via email to