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