]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Split signed bitwise AND operations.
authorAndrew MacLeod <amacleod@redhat.com>
Thu, 23 Oct 2025 21:19:02 +0000 (17:19 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Fri, 24 Oct 2025 16:04:20 +0000 (12:04 -0400)
The algorithm for bitwise AND struggles with complex signed operations
which cross the signed/unsigned barrier.  When this happens, process it
as 2 seperate ranges [LB, -1] and [0, UB], and combine the results.

PR tree-optimization/114725.c
gcc/
* range-op.cc (operator_bitwise_and::wi_fold): Split signed
operations crossing zero into 2 operations.

gcc/testsuite/
* gcc.dg/pr114725.c: New.

gcc/range-op.cc
gcc/testsuite/gcc.dg/pr114725.c [new file with mode: 0644]

index 762fd349e5f78f2f18648ff691c960c777422cea..6b6bf78cb2f18fb765acd8b37ee3061bd165f229 100644 (file)
@@ -3522,6 +3522,22 @@ operator_bitwise_and::wi_fold (irange &r, tree type,
                               const wide_int &rh_lb,
                               const wide_int &rh_ub) const
 {
+  // The AND algorithm does not handle complex signed operations well.
+  // If a signed range crosses the boundry between signed and unsigned
+  // proces sit as 2 ranges and union the results.
+  if (TYPE_SIGN (type) == SIGNED
+      && wi::neg_p (lh_lb, SIGNED) != wi::neg_p (lh_ub, SIGNED))
+    {
+      int prec = TYPE_PRECISION (type);
+      int_range_max tmp;
+      // Process [lh_lb, -1]
+      wi_fold (tmp, type, lh_lb, wi::minus_one (prec), rh_lb, rh_ub);
+      // Now Process [0, rh_ub]
+      wi_fold (r, type, wi::zero (prec), lh_ub, rh_lb, rh_ub);
+      r.union_ (tmp);
+      return;
+    }
+
   if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
     return;
 
diff --git a/gcc/testsuite/gcc.dg/pr114725.c b/gcc/testsuite/gcc.dg/pr114725.c
new file mode 100644 (file)
index 0000000..01c3139
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+//* This should fold to return 0
+bool
+src(int offset)
+{
+  if (offset > 128)
+    return 0;
+  else
+    return (offset & -9) == 258;
+}
+
+/* { dg-final { scan-tree-dump "return 0"  "optimized" } } */
+/* { dg-final { scan-tree-dump-not "PHI"  "optimized" } } */