aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2022-05-18 09:18:24 +0200
committerRichard Biener <rguenther@suse.de>2022-05-18 09:18:24 +0200
commitef6f1e135618a39ea456416093575b68ea5fc28e (patch)
treeee6a4997d110c3215f0d6b74e1da94a75566a8b8
parent1990086f5791cba8c267c430119e38c5030451d9 (diff)
Avoid ICE when removing a case sharing the edge with the default case
-rw-r--r--gcc/testsuite/gcc.dg/torture/20220518-1.c39
-rw-r--r--gcc/tree-ssa-loop-unswitch.cc15
2 files changed, 51 insertions, 3 deletions
diff --git a/gcc/testsuite/gcc.dg/torture/20220518-1.c b/gcc/testsuite/gcc.dg/torture/20220518-1.c
new file mode 100644
index 00000000000..1822aee6151
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/20220518-1.c
@@ -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;
+ }
+}
diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc
index b245885d91d..0e8baded8b9 100644
--- a/gcc/tree-ssa-loop-unswitch.cc
+++ b/gcc/tree-ssa-loop-unswitch.cc
@@ -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);