Recent changes to get_range_from_bitmask can sometimes turn a small
range into an undefined one if the bitmask indicates the bits make all
values impossible.
range_cast () was not expecting this and checks for UNDEFINED before
peforming the cast. It also needs to check for it after the cast now.
in this testcase, the pattern is
y = x * 4 <- we know y will have the bottom 2 bits cleared
z = Y + 7 <- we know z will have the bottom 2 bit set.
then a switch checks for z == 128 | z== 129 and performs a store into
*(int *)y
eventually the store is eliminated as unreachable, but range analysis
recognizes that the value is UNDEFINED when [121, 122] with the last 2
bits having to be 11 is calculated :-P
Do the default for casts, and if the result is UNDEFINED, turn it into
VARYING.
Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.
Andrew
From f332f23d6b6b45dce3ab19440eecffa26bf3fc15 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Thu, 15 May 2025 11:06:05 -0400
Subject: [PATCH 1/5] Check for casts becoming UNDEFINED.
In various situations a cast that is ultimately unreahcable may produce
an UNDEFINED result, and we can't check the bounds in this case.
PR tree-optimization/120277
gcc/
* range-op-ptr.cc (operator_cast::fold_range): Check if the cast
if UNDEFINED before setting bounds.
gcc/testsuite/
* gcc.dg/pr120277.c: New.
---
gcc/range-op-ptr.cc | 10 ++++++++--
gcc/testsuite/gcc.dg/pr120277.c | 21 +++++++++++++++++++++
2 files changed, 29 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/pr120277.c
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 36e9dfc20ba..6aadc9cf2c9 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -602,8 +602,14 @@ operator_cast::fold_range (prange &r, tree type,
int_range<2> tmp = inner;
tree pointer_uint_type = make_unsigned_type (TYPE_PRECISION (type));
range_cast (tmp, pointer_uint_type);
- r.set (type, tmp.lower_bound (), tmp.upper_bound ());
- r.update_bitmask (tmp.get_bitmask ());
+ // Casts may cause ranges to become UNDEFINED based on bitmasks.
+ if (tmp.undefined_p ())
+ r.set_varying (type);
+ else
+ {
+ r.set (type, tmp.lower_bound (), tmp.upper_bound ());
+ r.update_bitmask (tmp.get_bitmask ());
+ }
return true;
}
diff --git a/gcc/testsuite/gcc.dg/pr120277.c b/gcc/testsuite/gcc.dg/pr120277.c
new file mode 100644
index 00000000000..f291e920db1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr120277.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int a, b;
+int c(int d, long e) {
+ switch (d) {
+ case 129:
+ a = 1;
+ case 128:
+ break;
+ default:
+ return 1;
+ }
+ *(int *)e = 0;
+}
+void f(int d, long e) { c(d, e); }
+void g() {
+ int h = b * sizeof(int);
+ f(h + 7, h);
+}
+void main() {}
--
2.45.0