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;