On 10/24/25 05:29, Richard Biener wrote:
On Thu, Oct 23, 2025 at 8:49 PM Andrew MacLeod <[email protected]> wrote:
The attached patch fixes PR 118254.

It does 2 things:

1) when performing a cast, we cast sub pairs and union the results.
When this gets to VARYING we immediately short circuit and return.
THe error was if there was a bitmask, it was nebver attached and
applied.    This patch correct that such that the bitmask is now applied
to a VARYING result, which may result in something that is not VARYING
any more.

2) Operator_cast::op1_range makes no attempt to set a bitmask for
truncating casts...  The observation is that given:

     x_2 = (char) b_4

if x_2 is known to have a range of unsigned char [0, 7] MASK 0x7 VALUE
0x0  , then we can also determine that b_4's lower 8 bits must also have
the same mask...


This bootstraps fine, but causes a single regression.  It appears to
make the bug in PR 111003 no longer latent  (
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111003 ).

For the testcase in that PR, we are presented with :

    <bb 2> [local count: 1073741824]:
    c.0_1 = c;
    _2 = (unsigned char) c.0_1;
    goto <bb 4>; [100.00%]

< - snip- >

    <bb 7> [local count: 70290166531]:
    if (_2 != 0)
      goto <bb 8>; [50.00%]
    else
      goto <bb 12>; [50.00%]

The edge from 7->12 knows that _2 == [0,0] and for c.0_1, ranger use to
generate the range [-INF, -256][0, 0][256, +INF].

WIth this patch, the appropriate bitmask is added in
operator_cast::op1_range() , and now c.0_1 ==  [-INF, -256][0, 0][256,
2147483392] MASK 0xffffff00 VALUE 0x0

Note this allows us to carry the knowledge that the lower 8 bits are
zero.  THis then feeds into

<bb 12> [local count: 58340838140]:
    _4 = c.0_1 & 255;
    _12 = (unsigned int) _4;
    if (_4 > 6)
      goto <bb 13>; [50.00%]
    else
      goto <bb 14>; [50.00%]

    Where previously, _4 was  calculated as   [-INF, -256][0, 0][256,
+INF]   & 255  ,  which comes out VARYING.

With this patch,  we produce [-INF, -256][0, 0][256, 2147483392] MASK
0xffffff00 VALUE 0x0 & 255,  and come up with _4 == 0.

That then causing that IF statement to never be true on this path, and
the threader makes a different set of decisions on this new information
in threadfull2.

That in turns seems to reactivate the bug in PR 111003.  I've looked at
it a bit, but its not in my wheelhouse so I havent made much progress

The attached patch fixes 118254, but causes 111003 to regress. Should I
commit it, close 118254, and reopen 111003?   Or should I hold off on
this patch?
I'd say commit it and re-open the bug - it has not been "fixed", but
it was made latent anyway.

Richard.

Thanks

Andrew

Also note this fixes PR 114331 as well.

Bootstraps on 86_64-pc-linux-gnu , with a single regression, the aforementioned 111003 is no longer latent. I will reopen that PR.

Pushed.

Andrew
From 8ace106c80067095f08b36187893dd71b6206f47 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <[email protected]>
Date: Tue, 21 Oct 2025 16:05:22 -0400
Subject: [PATCH 1/2] Create and apply bitmasks for truncating casts.

When folding a cast, we were not applying the bitmask if we reached
a VARYING result.
We were also not creating a bitmask to represent the lower bits of a
truncating cast in op1_range.  So GORI was losing bits.

	PR tree-optimization/118254
	PR tree-optimization/114331
	gcc/
	* range-op.cc (operator_cast::fold_range): When VARYING is
	reached, update the bitmask if we reach VARYING.
	(operator_cast::op1_range): For truncating casts, create a
	bitmask bit in LHS.

	gcc/testsuite/
	* gcc.dg/pr114331.c: New.
	* gcc.dg/pr118254.c: New.
---
 gcc/range-op.cc                 | 22 ++++++++++++++++++++-
 gcc/testsuite/gcc.dg/pr114331.c | 20 +++++++++++++++++++
 gcc/testsuite/gcc.dg/pr118254.c | 34 +++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr114331.c
 create mode 100644 gcc/testsuite/gcc.dg/pr118254.c

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 1f91066a44e..762fd349e5f 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -3103,8 +3103,9 @@ operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
       int_range_max tmp;
       fold_pair (tmp, x, inner, outer);
       r.union_ (tmp);
+      // If we hit varying, go update the bitmask.
       if (r.varying_p ())
-	return true;
+	break;
     }
 
   update_bitmask (r, inner, outer);
@@ -3204,6 +3205,25 @@ operator_cast::op1_range (irange &r, tree type,
 	}
       // And intersect with any known value passed in the extra operand.
       r.intersect (op2);
+      if (r.undefined_p ())
+	return true;
+
+      // Now create a bitmask indicating that the lower bit must match the
+      // bits in the LHS.   Zero-extend LHS bitmask to precision of op1.
+      irange_bitmask bm = lhs.get_bitmask ();
+      wide_int mask = wide_int::from (bm.mask (), TYPE_PRECISION (type),
+				      UNSIGNED);
+      wide_int value = wide_int::from (bm.value (), TYPE_PRECISION (type),
+				       UNSIGNED);
+
+      // Set then additonal unknown bits in mask.
+      wide_int lim = wi::mask (TYPE_PRECISION (lhs_type), true,
+			       TYPE_PRECISION (type));
+      mask = mask | lim;
+
+      // Now set the new bitmask for the range.
+      irange_bitmask new_bm (value, mask);
+      r.update_bitmask (new_bm);
       return true;
     }
 
diff --git a/gcc/testsuite/gcc.dg/pr114331.c b/gcc/testsuite/gcc.dg/pr114331.c
new file mode 100644
index 00000000000..e93289e651b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114331.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int src(int num) {
+    switch((short)num){
+        case 111:
+	  /* Should fold to 110.  */
+          return num & 0xfffe;
+        case 267:
+        case 204:
+        case 263:
+          return 0;
+        default:
+          return 0;
+    }
+}
+
+
+/* { dg-final { scan-tree-dump "110"  "optimized" } } */
+
diff --git a/gcc/testsuite/gcc.dg/pr118254.c b/gcc/testsuite/gcc.dg/pr118254.c
new file mode 100644
index 00000000000..5a0553ba6f9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr118254.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void foo(void);
+int il=1000;
+
+int m1(void)
+{
+  short t = il;
+  unsigned t1 = t;
+  if (t1 == 0) {
+    char b = t1;
+    if (b != 1)
+      return 0;
+    foo();
+  }
+  return 0;
+}
+
+int m2(void)
+{
+  short t = il;
+  unsigned t1 = t;
+  if (t1 == 0) {
+    char b = il;
+    if (b != 1)
+      return 0;
+    foo();
+  }
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "foo"  "evrp" } } */
+
-- 
2.45.0

Reply via email to