Creation of inverse ranges in the irange code was not dealing with signed 1-bit quantities correctly.

The legacy code had special cased this case, so I adapted and pulled out some code to do it in one place.

Could someone double check the logic here, please?

Thanks.
Aldy
commit 43c72ceb5dc11cdf8f919aeb774e3aa7a32039e7
Author: Aldy Hernandez <al...@redhat.com>
Date:   Thu Mar 18 16:05:27 2021 +0100

    Handle setting of 1-bit anti-ranges uniformly.
    
            PR tree-optimization/99296
            * value-range.cc (irange::irange_set_1bit_anti_range): New.
            (irange::irange_set_anti_range): Call irange_set_1bit_anti_range
            (irange::set): Same.
            * value-range.h (irange::irange_set_1bit_anti_range): New.

diff --git a/gcc/testsuite/gcc.dg/pr99296.c b/gcc/testsuite/gcc.dg/pr99296.c
new file mode 100644
index 00000000000..4a0b3f0c366
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr99296.c
@@ -0,0 +1,7 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-tree-bit-ccp" }
+
+struct {
+  signed a : 1;
+} b, c;
+void d() { b.a |= c.a |= 0 != 2; }
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 9c42f82a105..132bb0b838b 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -184,12 +184,46 @@ irange::irange_set (tree min, tree max)
     verify_range ();
 }
 
+void
+irange::irange_set_1bit_anti_range (tree min, tree max)
+{
+  tree type = TREE_TYPE (min);
+  gcc_checking_assert (TYPE_PRECISION (type) == 1);
+
+  if (operand_equal_p (min, max))
+    {
+      // Since these are 1-bit quantities, they can only be [MIN,MIN]
+      // or [MAX,MAX].
+      if (vrp_val_is_min (min))
+	min = max = vrp_val_max (type);
+      else
+	min = max = vrp_val_min (type);
+      set (min, max);
+    }
+  else
+    {
+      // The only alternative is [MIN,MAX], which is the empty range,
+      // but legacy code treats this as varying.
+      gcc_checking_assert (vrp_val_is_min (min));
+      gcc_checking_assert (vrp_val_is_max (max));
+      set_varying (type);
+    }
+  if (flag_checking)
+    verify_range ();
+}
+
 void
 irange::irange_set_anti_range (tree min, tree max)
 {
   gcc_checking_assert (!POLY_INT_CST_P (min));
   gcc_checking_assert (!POLY_INT_CST_P (max));
 
+  if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
+    {
+      irange_set_1bit_anti_range (min, max);
+      return;
+    }
+
   // set an anti-range
   tree type = TREE_TYPE (min);
   signop sign = TYPE_SIGN (type);
@@ -291,16 +325,10 @@ irange::set (tree min, tree max, value_range_kind kind)
 	  set_varying (type);
 	  return;
 	}
-      else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
-	       && (is_min || is_max))
+      else if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
 	{
-	  /* Non-empty boolean ranges can always be represented
-	     as a singleton range.  */
-	  if (is_min)
-	    min = max = vrp_val_max (TREE_TYPE (min));
-	  else
-	    min = max = vrp_val_min (TREE_TYPE (min));
-	  kind = VR_RANGE;
+	  irange_set_1bit_anti_range (min, max);
+	  return;
 	}
       else if (is_min)
         {
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 8a4d8ec4207..bfc54a2473f 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -127,6 +127,8 @@ protected:
   void copy_legacy_to_multi_range (const irange &);
 
 private:
+  void irange_set_1bit_anti_range (tree, tree);
+
   unsigned char m_num_ranges;
   unsigned char m_max_ranges;
   ENUM_BITFIELD(value_range_kind) m_kind : 8;

Reply via email to