> My slight preference would be to just do the math and simply check at
> the end..      Fold will work fine on all those values  (in fact
> UNDEFINED gets translated to VARYING I believe).  so I don't see the
> point in multiple checks. .. yeah, slightly more work I suppose.. But it
> eliminates any possibility that operator_minus does something unexpected.

Understood, here's the version I'm going to test.  For the record, the special 
casing of a zero low bound is necessary, because if you do just:

        && query->range_of_expr (vr_idx, index)
        && query->range_of_expr (vr_lb, low_bound)
        && minus_op.fold_range (vr, TREE_TYPE (index),                  
                          vr_idx, vr_lb)
        && !vr.varying_p ()
        && !vr.undefined_p ())

you get a checking failure about type consistency in the ranger for almost all 
C tests involving arrays.  But that's expected: you get an equivalent checking 
failure if you do the same operation on trees:

              index = fold_build2 (MINUS_EXPR, TREE_TYPE (index),
                             index, low_bound);

because the C FE does not guarantee type consistency of its fixed zero low 
bound with the index expression (unlike FEs for languages supporting arbitrary 
low bounds like Ada, which otherwise would break the middle-end).

-- 
Eric Botcazou
diff --git a/gcc/tree-dfa.cc b/gcc/tree-dfa.cc
index 5ba5f10ecb6..4b518e6860f 100644
--- a/gcc/tree-dfa.cc
+++ b/gcc/tree-dfa.cc
@@ -530,30 +530,41 @@ get_ref_base_and_extent (tree exp, poly_int64 *poffset,
 		   index.  */
 		seen_variable_array_ref = true;
 
-		int_range_max vr;
-		range_query *query;
-		query = get_range_query (cfun);
+		/* Try to constrain the access range by using the range of the
+		   index expression when it is known. Extra care must be taken
+		   when the low bound of the array is not zero, because it may
+		   be very large and the index expression may be unsigned and
+		   wrap around; in this case, the correct range is that of the
+		   difference between the index expression and the low bound,
+		   see get_inner_reference for the model computation.  */
+		range_query *query = get_range_query (cfun);
+		range_op_handler minus_op (MINUS_EXPR);
+		int_range_max vr_idx, vr_lb, vr;
 
 		if (TREE_CODE (index) == SSA_NAME
 		    && (low_bound = array_ref_low_bound (exp),
-			poly_int_tree_p (low_bound))
+			TREE_CODE (low_bound) == INTEGER_CST)
 		    && (unit_size = array_ref_element_size (exp),
 			TREE_CODE (unit_size) == INTEGER_CST)
 		    && query->range_of_expr (vr, index)
+		    && (integer_zerop (low_bound)
+			|| ((vr_idx = vr,
+			     query->range_of_expr (vr_lb, low_bound))
+			    && minus_op.fold_range (vr, TREE_TYPE (index),
+						    vr_idx, vr_lb)))
 		    && !vr.varying_p ()
 		    && !vr.undefined_p ())
 		  {
 		    wide_int min = vr.lower_bound ();
 		    wide_int max = vr.upper_bound ();
-		    poly_offset_int lbound = wi::to_poly_offset (low_bound);
 		    /* Try to constrain maxsize with range information.  */
 		    offset_int omax
 		      = offset_int::from (max, TYPE_SIGN (TREE_TYPE (index)));
 		    if (wi::get_precision (max) <= ADDR_MAX_BITSIZE
-			&& known_lt (lbound, omax))
+			&& omax >= 0)
 		      {
-			poly_offset_int rmaxsize;
-			rmaxsize = (omax - lbound + 1)
+			offset_int rmaxsize
+			  = (omax + 1)
 			    * wi::to_offset (unit_size) << LOG2_BITS_PER_UNIT;
 			if (!known_size_p (maxsize)
 			    || known_lt (rmaxsize, maxsize))
@@ -569,11 +580,10 @@ get_ref_base_and_extent (tree exp, poly_int64 *poffset,
 		    offset_int omin
 		      = offset_int::from (min, TYPE_SIGN (TREE_TYPE (index)));
 		    if (wi::get_precision (min) <= ADDR_MAX_BITSIZE
-			&& known_le (lbound, omin))
+			&& omin > 0)
 		      {
-			poly_offset_int woffset
-			  = wi::sext (omin - lbound,
-				      TYPE_PRECISION (sizetype));
+			offset_int woffset
+			  = wi::sext (omin, TYPE_PRECISION (sizetype));
 			woffset *= wi::to_offset (unit_size);
 			woffset <<= LOG2_BITS_PER_UNIT;
 			bit_offset += woffset;

Reply via email to