[PATCH] Use extremes of underlying type when building VR_ANTI_RANGEs.

Aldy Hernandez aldyh@redhat.com
Tue Nov 10 10:41:48 GMT 2020


[Andrew, this doesn't fix a PR per se.  It's just something I stumbled
upon in my other -fstrict-enums fixes.  It passes tests.  What do you
think?  Should we push it?]

Imagine an enum in an -fstrict-enums world:

	enum foo { zero, one, two, three };

Building the inverse of [0,3] currently yields VARYING (instead of
[4,+INF]).  This is because the setter sees 0 and 3 as the extremes of
the type, and per the current code, calculates the inverse to VARYING.
BTW, it really should be UNDEFINED, but this is legacy code I'm afraid
to touch:

      if (is_min && is_max)
	{
	  /* We cannot deal with empty ranges, drop to varying.
	     ???  This could be VR_UNDEFINED instead.  */
	  set_varying (type);
	  return;
	}

However, the extremes of a VARYING are the extremes of the underlying
type ([0, 0xff..ff]), even in the presence of -fstrict-enums.

This fixes the setter to use the extremes of the underlying type.

gcc/ChangeLog:

	* value-range.cc (irange::set): Use wi::{min,max}_value
	instead of TYPE_{MIN,MAX}_VALUE when building anti-ranges.
	(range_tests_strict_enum): New tests.
---
 gcc/value-range.cc | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index f83a824a982..bbd7d69a766 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -274,11 +274,13 @@ irange::set (tree min, tree max, value_range_kind kind)
   // Anti-ranges that can be represented as ranges should be so.
   if (kind == VR_ANTI_RANGE)
     {
-      /* For -fstrict-enums we may receive out-of-range ranges so consider
-         values < -INF and values > INF as -INF/INF as well.  */
-      bool is_min = vrp_val_is_min (min);
-      bool is_max = vrp_val_is_max (max);
       tree type = TREE_TYPE (min);
+      unsigned prec = TYPE_PRECISION (type);
+      signop sign = TYPE_SIGN (type);
+      wide_int type_max = wi::max_value (prec, sign);
+      wide_int type_min = wi::min_value (prec, sign);
+      bool is_min = wi::to_wide (min) == type_min;
+      bool is_max = wi::to_wide (max) == type_max;
 
       if (is_min && is_max)
 	{
@@ -302,14 +304,14 @@ irange::set (tree min, tree max, value_range_kind kind)
         {
 	  tree one = build_int_cst (TREE_TYPE (max), 1);
 	  min = int_const_binop (PLUS_EXPR, max, one);
-	  max = vrp_val_max (TREE_TYPE (max));
+	  max = wide_int_to_tree (type, type_max);
 	  kind = VR_RANGE;
         }
       else if (is_max)
         {
 	  tree one = build_int_cst (TREE_TYPE (min), 1);
 	  max = int_const_binop (MINUS_EXPR, min, one);
-	  min = vrp_val_min (TREE_TYPE (min));
+	  min = wide_int_to_tree (type, type_min);
 	  kind = VR_RANGE;
         }
     }
@@ -2276,6 +2278,19 @@ range_tests_strict_enum ()
   ir1 = vr1;
   ASSERT_TRUE (ir1 == vr1);
   ASSERT_FALSE (ir1.varying_p ());
+
+  // Legacy inversion of [0, 3] should be [4, MAX].
+  vr1 = int_range<1> (build_int_cstu (rtype, 0), build_int_cstu (rtype, 3));
+  vr1.invert ();
+  tree type_max = wide_int_to_tree (rtype,
+				    wi::max_value (TYPE_PRECISION (rtype),
+						   TYPE_SIGN (rtype)));
+  ASSERT_TRUE (vr1 == int_range<1> (build_int_cstu (rtype, 4), type_max));
+
+  // Multi-range inversion of [0, 3] should be [4, MAX].
+  ir1 = int_range<2> (build_int_cstu (rtype, 0), build_int_cstu (rtype, 3));
+  ir1.invert ();
+  ASSERT_TRUE (vr1 == int_range<2> (build_int_cstu (rtype, 4), type_max));
 }
 
 static void
-- 
2.26.2



More information about the Gcc-patches mailing list