On 11/28/25 03:00, Richard Biener wrote:
On Thu, Nov 27, 2025 at 7:39 PM Andrew MacLeod <[email protected]> wrote:
I do think this is the correct solution. I dont think there is any point
in enhancing the bitmask class to have a representation of UNDEFINED as
it would be such a transient thing, and serves little purpose in the
class itself.

ok?
OK.

Thanks,
Richard.


Pushed.

From d46828612c6481e3510af54335cab2b4cdab0e91 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <[email protected]>
Date: Wed, 26 Nov 2025 14:21:13 -0500
Subject: [PATCH 1/7] Undefined bitmasks imply undefined ranges.

bitmask have no way of representing UNDEFINED, and as such, bitmask
intersection returns an unknown_p values instead.  This patch has the
function return false in this case, which will indicate UNDEFINED.

	PR tree-optimization/122686
	gcc/
	* range-op.cc (operator_bitwise_and::op1_range): Check for
	undefined bitmask.
	* value-range.cc (prange::intersect): Handle undefined bitmask
	intersection.
	(irange::get_bitmask): Ditto.
	(irange::intersect_bitmask): Ditto.
	* value-range.h (irange_bitmask::intersect): Return false if the
	result is UNDEFINED.
---
 gcc/range-op.cc    |  9 ++++++---
 gcc/value-range.cc | 15 ++++++++++-----
 gcc/value-range.h  | 17 +++++++----------
 3 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 82a994b4ca5..fb7d4742bb6 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -3848,9 +3848,12 @@ operator_bitwise_and::op1_range (irange &r, tree type,
   // extraneous values thats are not convered by the mask.
   wide_int op1_value = lhs_bm.value () & ~op1_mask;
   irange_bitmask op1_bm (op1_value, op1_mask);
-  // INtersect this mask with anything already known about the value.
-  op1_bm.intersect (r.get_bitmask ());
-  r.update_bitmask (op1_bm);
+  // Intersect this mask with anything already known about the value.
+  // A return valueof false indicated the bitmask is an UNDEFINED range.
+  if (op1_bm.intersect (r.get_bitmask ()))
+    r.update_bitmask (op1_bm);
+  else
+    r.set_undefined ();
   return true;
 }
 
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index f93a7e5c53a..605f7081737 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -674,8 +674,10 @@ prange::intersect (const vrange &v)
 
   // Intersect all bitmasks: the old one, the new one, and the other operand's.
   irange_bitmask new_bitmask (m_type, m_min, m_max);
-  m_bitmask.intersect (new_bitmask);
-  m_bitmask.intersect (r.m_bitmask);
+  if (!m_bitmask.intersect (new_bitmask))
+    set_undefined ();
+  else if (!m_bitmask.intersect (r.m_bitmask))
+    set_undefined ();
   if (varying_compatible_p ())
     {
       set_varying (type ());
@@ -2528,10 +2530,9 @@ irange::get_bitmask () const
   irange_bitmask bm (type (), lower_bound (), upper_bound ());
   if (!m_bitmask.unknown_p ())
     {
-      bm.intersect (m_bitmask);
       // If the new intersection is unknown, it means there are inconstent
       // bits, so simply return the original bitmask.
-      if (bm.unknown_p ())
+      if (!bm.intersect (m_bitmask))
 	return m_bitmask;
     }
   return bm;
@@ -2572,7 +2573,11 @@ irange::intersect_bitmask (const irange &r)
 
   irange_bitmask bm = get_bitmask ();
   irange_bitmask save = bm;
-  bm.intersect (r.get_bitmask ());
+  if (!bm.intersect (r.get_bitmask ()))
+    {
+      set_undefined ();
+      return true;
+    }
 
   // If the new mask is the same, there is no change.
   if (m_bitmask == bm)
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 6ae46e17959..11d1ed75744 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -145,7 +145,7 @@ public:
   bool unknown_p () const;
   unsigned get_precision () const;
   void union_ (const irange_bitmask &src);
-  void intersect (const irange_bitmask &src);
+  bool intersect (const irange_bitmask &src);
   bool operator== (const irange_bitmask &src) const;
   bool operator!= (const irange_bitmask &src) const { return !(*this == src); }
   void verify_mask () const;
@@ -247,20 +247,16 @@ irange_bitmask::union_ (const irange_bitmask &src)
     verify_mask ();
 }
 
-inline void
+// Return FALSE if the bitmask intersection is undefined.
+
+inline bool
 irange_bitmask::intersect (const irange_bitmask &src)
 {
   // If we have two known bits that are incompatible, the resulting
-  // bit is undefined.  It is unclear whether we should set the entire
-  // range to UNDEFINED, or just a subset of it.  For now, set the
-  // entire bitmask to unknown (VARYING).
+  // bit and therefore entire range is undefined.  Return FALSE.
   if (wi::bit_and (~(m_mask | src.m_mask),
 		   m_value ^ src.m_value) != 0)
-    {
-      unsigned prec = m_mask.get_precision ();
-      m_mask = wi::minus_one (prec);
-      m_value = wi::zero (prec);
-    }
+    return false;
   else
     {
       m_mask = m_mask & src.m_mask;
@@ -268,6 +264,7 @@ irange_bitmask::intersect (const irange_bitmask &src)
     }
   if (flag_checking)
     verify_mask ();
+  return true;
 }
 
 // An integer range without any storage.
-- 
2.45.0

Reply via email to