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

Reply via email to