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.

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