> 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;