As discussed in the PR, the type of a switch operand may be different
than the type of the individual cases. This is causing us to attempt to
intersect incompatible ranges.
This inconsistent IL seems wrong to me, but it also seems pervasive
throughout GCC. Jason, as one of the original gimple designers, do you
remember if this was an oversight, or was there a reason for this?
Richard, you mention in the PR that normalizing the IL would cause
propagation of widening cast sources into switches harder. Couldn't we
just cast all labels to the switch operand type upon creation? What
would be the problem with that? Would we generate sub-optimal code?
In either case, I'd hate to leave trunk in a broken case while this is
being discussed. The attached patch fixes the PRs.
OK?
Aldy
>From 3c2db553c22ffbf014564d374d3d2c9210b5b83b Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <al...@redhat.com>
Date: Fri, 28 Aug 2020 18:44:58 +0200
Subject: [PATCH] PR tree-optimization/96818 - cast label range to type of
switch operand
PR tree-optimization/96818
* tree-vrp.c (find_case_label_range): Cast label range to
type of switch operand.
---
gcc/testsuite/g++.dg/pr96818.C | 28 ++++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/pr96818.c | 14 ++++++++++++++
gcc/tree-vrp.c | 2 ++
3 files changed, 44 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/pr96818.C
create mode 100644 gcc/testsuite/gcc.dg/pr96818.c
diff --git a/gcc/testsuite/g++.dg/pr96818.C b/gcc/testsuite/g++.dg/pr96818.C
new file mode 100644
index 00000000000..134bf8b6980
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr96818.C
@@ -0,0 +1,28 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+bool operatorY ();
+
+struct l
+{
+ int m;
+ int k;
+ void n ();
+ l ()
+ {
+ while (operatorY ())
+ switch ((unsigned char) k)
+ case 0:
+ {
+ n ();
+ case 1:if (m)
+ ;
+ }
+ }
+};
+
+void
+p ()
+{
+ l ();
+}
diff --git a/gcc/testsuite/gcc.dg/pr96818.c b/gcc/testsuite/gcc.dg/pr96818.c
new file mode 100644
index 00000000000..ea2ac540d39
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr96818.c
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+int a, b, c;
+void d() {
+ unsigned short e;
+ while (b)
+ ;
+ e = (e + 5) / a;
+ switch (e)
+ case 0:
+ case 3:
+ c = a;
+}
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 8c1a1854daa..a165164bb40 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -3850,6 +3850,8 @@ find_case_label_range (gswitch *switch_stmt, const irange *range_of_op)
if (!case_high)
case_high = CASE_LOW (max_label);
widest_irange label_range (CASE_LOW (min_label), case_high);
+ if (!types_compatible_p (label_range.type (), range_of_op->type ()))
+ range_cast (label_range, range_of_op->type ());
label_range.intersect (range_of_op);
if (label_range.undefined_p ())
return gimple_switch_label (switch_stmt, 0);
--
2.26.2