> The first version, requiring INTEGER_CST low_bound.  But ...
> 
>                     && query->range_of_expr (vr, index)
>                     && !vr.varying_p ()
> -                   && !vr.undefined_p ())
> +                   && !vr.undefined_p ()
> +                   && (integer_zerop (low_bound)
> +                       || query->range_of_expr
> +                            (vr,
> +                             build2 (MINUS_EXPR, TREE_TYPE (index),
> +                                     index, low_bound))))
> 
> can you try to use
> 
>   range_op_handler op (MINUS_EXPR);
> 
>   || !op.fold_range (vr, TREE_TYPE (index), vr, low_bound_range)
> 
> with building a constant range for low_bound (not exactly sure how to
> best do that)?  I think you'll also need to repeat the
> !vr.varying_p () / !vr.undefined_p () checks -- possibly they
> could be simply delayed and feeding fold_range with those could
> be OK.

The attached version seems to do the job:

(gdb) p debug(&vr_expr)
[irange] sizetype [0, 0][18446744073709551613, +INF]
$1 = void
(gdb) p debug(&vr_lb)
[irange] sizetype [18446744073709551613, 18446744073709551613]
$2 = void
(gdb) p debug(&vr)
[irange] sizetype [0, 3]

> I'll note the existing code tried to account for low_bound != 0, I trust
> you identified where it failed to, I refrained from trying to understand it
> ;)

The problem is that vr_expr is a noncontiguous range (wraparound) so taking 
its global min and global max does not work.  Only a proper computation of the 
range of the difference gives the correct answer in all cases.

-- 
Eric Botcazou
diff --git a/gcc/tree-dfa.cc b/gcc/tree-dfa.cc
index 5ba5f10ecb6..5e374697206 100644
--- a/gcc/tree-dfa.cc
+++ b/gcc/tree-dfa.cc
@@ -530,30 +530,40 @@ 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 op (MINUS_EXPR);
+		int_range_max vr_expr, 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)
-		    && !vr.varying_p ()
-		    && !vr.undefined_p ())
+		    && query->range_of_expr (vr_expr, index)
+		    && !vr_expr.varying_p ()
+		    && !vr_expr.undefined_p ()
+		    && ((vr = vr_expr, integer_zerop (low_bound))
+			|| (query->range_of_expr (vr_lb, low_bound)
+			    && op.fold_range (vr, TREE_TYPE (index),
+					      vr_expr, vr_lb))))
 		  {
 		    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 +579,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