The invert() range operation is not supported on values of either VARYING or UNDEFINED.  Primarily this is because UNDEFINED has no type, which makes it impossible to perform invert() twice on a value, and produce that same value.  There were also times when it wasn't precisely clear what the client expects when UNDEFINED or VARYING is inverted.. so it is handled at the caller point.

When processing switches, whenever we find the ranges for a particular label, we invert that range, and intersect that inversion with the current "default:" ranges to determine the default case.   In this testcase, one label has all possible values, so the label was producing VARYING.  inverting that value was causing a trap.

This patch simple checks for VARYING and sets the default ranges to UNDEFINED in this case.

Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Backports to GCC12 - 14 forthcoming.

Andrew


From 766075c47db5cc9d04463bfb2219b593bb4263ee Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Sat, 2 Nov 2024 10:26:24 -0400
Subject: [PATCH] Don't call invert on VARYING.

When all cases go to one label and resul in a VARYING value, we can't
invert that value to remove all values from the default case. Simply
check for this case and set the default to UNDEFINED.

	PR tree-optimization/117398
	gcc/
	* gimple-range-edge.cc (gimple_outgoing_range::calc_switch_ranges):
	Check for VARYING and don't call invert () on it.

	gcc/testsuite/
	* gcc.dg/pr117398.c: New.
---
 gcc/gimple-range-edge.cc        | 10 ++++++++--
 gcc/testsuite/gcc.dg/pr117398.c | 17 +++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr117398.c

diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index e3a197a2293..d2387289ad2 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -159,8 +159,14 @@ gimple_outgoing_range::calc_switch_ranges (gswitch *sw)
       // Remove the case range from the default case.
       int_range_max def_range (type, low, high);
       range_cast (def_range, type);
-      def_range.invert ();
-      default_range.intersect (def_range);
+      // If all possible values are taken, set default_range to UNDEFINED.
+      if (def_range.varying_p ())
+	default_range.set_undefined ();
+      else
+	{
+	  def_range.invert ();
+	  default_range.intersect (def_range);
+	}
 
       // Create/union this case with anything on else on the edge.
       int_range_max case_range (type, low, high);
diff --git a/gcc/testsuite/gcc.dg/pr117398.c b/gcc/testsuite/gcc.dg/pr117398.c
new file mode 100644
index 00000000000..c43f2a3ed6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr117398.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int a;
+void c(void);
+int d(_Bool b) {
+  switch (b+0) {
+  case 0:
+    break;
+  case 1:
+    break;
+  default:
+    c();
+  }
+  if (b)
+    return a;
+}
-- 
2.45.0

Reply via email to