]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Avoid ICE when removing a case sharing the edge with the default case
authorRichard Biener <rguenther@suse.de>
Wed, 18 May 2022 07:18:24 +0000 (09:18 +0200)
committerRichard Biener <rguenther@suse.de>
Wed, 18 May 2022 07:18:24 +0000 (09:18 +0200)
gcc/testsuite/gcc.dg/torture/20220518-1.c [new file with mode: 0644]
gcc/tree-ssa-loop-unswitch.cc

diff --git a/gcc/testsuite/gcc.dg/torture/20220518-1.c b/gcc/testsuite/gcc.dg/torture/20220518-1.c
new file mode 100644 (file)
index 0000000..1822aee
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-funswitch-loops" } */
+
+enum {
+  MOD_WVG_MASK_TEX_USE_INT,
+  MOD_WVG_MASK_TEX_USE_RED,
+  MOD_WVG_MASK_TEX_USE_BLUE,
+  MOD_WVG_MASK_TEX_USE_SAT,
+  MOD_WVG_MASK_TEX_USE_VAL,
+  MOD_WVG_MASK_TEX_USE_ALPHA
+} foo_num;
+float *foo_org_w;
+int *foo_new_w;
+float foo_fact;
+int foo_tex_use_channel, foo_i, foo_texres_0;
+void foo()
+{
+  for (; foo_num;)
+    switch (foo_tex_use_channel) {
+    case MOD_WVG_MASK_TEX_USE_INT:
+      foo_org_w[foo_i] = foo_new_w[foo_i] * foo_texres_0;
+      break;
+    case MOD_WVG_MASK_TEX_USE_RED:
+      foo_org_w[foo_i] = 0;
+    case MOD_WVG_MASK_TEX_USE_BLUE:
+      foo_org_w[foo_i] = foo_fact + foo_org_w[foo_i];
+      break;
+    case MOD_WVG_MASK_TEX_USE_SAT:
+      foo_org_w[foo_i] = foo_fact;
+      break;
+    case MOD_WVG_MASK_TEX_USE_VAL:
+      foo_org_w[foo_i] = 0;
+    case MOD_WVG_MASK_TEX_USE_ALPHA:
+      foo_org_w[foo_i] = foo_fact + foo_org_w[foo_i];
+      break;
+    default:
+      foo_org_w[foo_i] = foo_new_w[foo_i] * foo_texres_0;
+    }
+}
index b245885d91dcb711dab8b08abffa690b67ec42fb..0e8baded8b9055b4bcfd45301ddcad1333f05dc4 100644 (file)
@@ -1523,11 +1523,14 @@ clean_up_after_unswitching (int ignored_edge_flag)
 
   FOR_EACH_BB_FN (bb, cfun)
     {
-      gimple *last = last_stmt (bb);
-      if (gswitch *stmt = safe_dyn_cast <gswitch *> (last))
+      gswitch *stmt= safe_dyn_cast <gswitch *> (last_stmt (bb));
+      if (stmt && !CONSTANT_CLASS_P (gimple_switch_index (stmt)))
        {
          unsigned nlabels = gimple_switch_num_labels (stmt);
          unsigned index = 1;
+         tree lab = gimple_switch_default_label (stmt);
+         edge default_e = find_edge (gimple_bb (stmt),
+                                     label_to_block (cfun, CASE_LABEL (lab)));
          for (unsigned i = 1; i < nlabels; ++i)
            {
              tree lab = gimple_switch_label (stmt, i);
@@ -1536,7 +1539,13 @@ clean_up_after_unswitching (int ignored_edge_flag)
              if (e == NULL)
                ; /* The edge is already removed.  */
              else if (e->flags & ignored_edge_flag)
-               remove_edge (e);
+               {
+                 /* We may not remove the default label so we also have
+                    to preserve its edge.  But we can remove the
+                    non-default CASE sharing the edge.  */
+                 if (e != default_e)
+                   remove_edge (e);
+               }
              else
                {
                  gimple_switch_set_label (stmt, index, lab);