Enforce canonicalization in value_range.

From-SVN: r274525
This commit is contained in:
Aldy Hernandez 2019-08-15 10:45:41 +00:00 committed by Aldy Hernandez
parent eb2211e357
commit c7cf3a9bb0
4 changed files with 247 additions and 99 deletions

View File

@ -1,3 +1,37 @@
2019-08-15 Aldy Hernandez <aldyh@redhat.com>
* tree-vrp.c (value_range_base::set): Merge in code from
value_range_base::set_and_canonicalize.
Enforce canonicalization at set time.
Normalize [MIN, MAX] into VARYING and ~[MIN, MAX] into UNDEFINED.
(value_range_base::set_undefined): Inline call to set().
(value_range_base::set_varying): Same.
(value_range_base::singleton_p): Handle VR_ANTI_RANGEs.
(vrp_val_max): New argument handle_pointers.
(vrp_val_min): Same.
(ranges_from_anti_range): Same.
(extract_range_into_wide_ints): Use tree argument instead of sign
and precision.
(extract_range_from_multiplicative_op): Take in tree type instead
of precision and sign. Adapt function for canonicalized ranges.
(extract_range_from_binary_expr): Pass type to
extract_range_from_multiplicative_op.
Adapt for canonicalized ranges.
(extract_range_from_unary_expr): Same.
(value_range_base::intersect_helper): Adjust for canonicalized
ranges.
(value_range_base::union_helper): Same.
(value_range_base::normalize_symbolics): New.
* tree-vrp.h (class value_range_base): Remove
set_and_canonicalize.
New prototype for normalize_symbolics.
(class value_range): Remove set_and_canonicalize.
(vrp_val_min): Adjust prototype.
(vrp_val_max): Same.
* vr-values.c
(vr_values::extract_range_for_var_from_comparison_expr): Call set
instead of set_and_canonicalize.
2019-08-15 Richard Sandiford <richard.sandiford@arm.com> 2019-08-15 Richard Sandiford <richard.sandiford@arm.com>
PR middle-end/91444 PR middle-end/91444

View File

@ -69,23 +69,20 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h" #include "builtins.h"
#include "wide-int-range.h" #include "wide-int-range.h"
static bool
ranges_from_anti_range (const value_range_base *ar,
value_range_base *vr0, value_range_base *vr1,
bool handle_pointers = false);
/* Set of SSA names found live during the RPO traversal of the function /* Set of SSA names found live during the RPO traversal of the function
for still active basic-blocks. */ for still active basic-blocks. */
static sbitmap *live; static sbitmap *live;
void
value_range_base::set (enum value_range_kind kind, tree min, tree max)
{
m_kind = kind;
m_min = min;
m_max = max;
if (flag_checking)
check ();
}
void void
value_range::set_equiv (bitmap equiv) value_range::set_equiv (bitmap equiv)
{ {
if (undefined_p () || varying_p ())
equiv = NULL;
/* Since updating the equivalence set involves deep copying the /* Since updating the equivalence set involves deep copying the
bitmaps, only do it if absolutely necessary. bitmaps, only do it if absolutely necessary.
@ -261,7 +258,8 @@ value_range_base::constant_p () const
void void
value_range_base::set_undefined () value_range_base::set_undefined ()
{ {
set (VR_UNDEFINED, NULL, NULL); m_kind = VR_UNDEFINED;
m_min = m_max = NULL;
} }
void void
@ -273,7 +271,8 @@ value_range::set_undefined ()
void void
value_range_base::set_varying () value_range_base::set_varying ()
{ {
set (VR_VARYING, NULL, NULL); m_kind = VR_VARYING;
m_min = m_max = NULL;
} }
void void
@ -324,6 +323,24 @@ value_range::equiv_add (const_tree var,
bool bool
value_range_base::singleton_p (tree *result) const value_range_base::singleton_p (tree *result) const
{ {
if (m_kind == VR_ANTI_RANGE)
{
if (nonzero_p ())
{
if (TYPE_PRECISION (type ()) == 1)
{
if (result)
*result = m_max;
return true;
}
return false;
}
value_range_base vr0, vr1;
return (ranges_from_anti_range (this, &vr0, &vr1, true)
&& vr1.undefined_p ()
&& vr0.singleton_p (result));
}
if (m_kind == VR_RANGE if (m_kind == VR_RANGE
&& vrp_operand_equal_p (min (), max ()) && vrp_operand_equal_p (min (), max ())
&& is_gimple_min_invariant (min ())) && is_gimple_min_invariant (min ()))
@ -499,23 +516,28 @@ static assert_locus **asserts_for;
/* Return the maximum value for TYPE. */ /* Return the maximum value for TYPE. */
tree tree
vrp_val_max (const_tree type) vrp_val_max (const_tree type, bool handle_pointers)
{ {
if (!INTEGRAL_TYPE_P (type)) if (INTEGRAL_TYPE_P (type))
return NULL_TREE; return TYPE_MAX_VALUE (type);
if (POINTER_TYPE_P (type) && handle_pointers)
return TYPE_MAX_VALUE (type); {
wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
return wide_int_to_tree (const_cast<tree> (type), max);
}
return NULL_TREE;
} }
/* Return the minimum value for TYPE. */ /* Return the minimum value for TYPE. */
tree tree
vrp_val_min (const_tree type) vrp_val_min (const_tree type, bool handle_pointers)
{ {
if (!INTEGRAL_TYPE_P (type)) if (INTEGRAL_TYPE_P (type))
return NULL_TREE; return TYPE_MIN_VALUE (type);
if (POINTER_TYPE_P (type) && handle_pointers)
return TYPE_MIN_VALUE (type); return build_zero_cst (const_cast<tree> (type));
return NULL_TREE;
} }
/* Return whether VAL is equal to the maximum value of its type. /* Return whether VAL is equal to the maximum value of its type.
@ -626,8 +648,7 @@ intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
extract ranges from var + CST op limit. */ extract ranges from var + CST op limit. */
void void
value_range_base::set_and_canonicalize (enum value_range_kind kind, value_range_base::set (enum value_range_kind kind, tree min, tree max)
tree min, tree max)
{ {
/* Use the canonical setters for VR_UNDEFINED and VR_VARYING. */ /* Use the canonical setters for VR_UNDEFINED and VR_VARYING. */
if (kind == VR_UNDEFINED) if (kind == VR_UNDEFINED)
@ -645,7 +666,9 @@ value_range_base::set_and_canonicalize (enum value_range_kind kind,
if (TREE_CODE (min) != INTEGER_CST if (TREE_CODE (min) != INTEGER_CST
|| TREE_CODE (max) != INTEGER_CST) || TREE_CODE (max) != INTEGER_CST)
{ {
set (kind, min, max); m_kind = kind;
m_min = min;
m_max = max;
return; return;
} }
@ -681,12 +704,13 @@ value_range_base::set_and_canonicalize (enum value_range_kind kind,
kind = kind == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE; kind = kind == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
} }
tree type = TREE_TYPE (min);
/* Anti-ranges that can be represented as ranges should be so. */ /* Anti-ranges that can be represented as ranges should be so. */
if (kind == VR_ANTI_RANGE) if (kind == VR_ANTI_RANGE)
{ {
/* For -fstrict-enums we may receive out-of-range ranges so consider /* For -fstrict-enums we may receive out-of-range ranges so consider
values < -INF and values > INF as -INF/INF as well. */ values < -INF and values > INF as -INF/INF as well. */
tree type = TREE_TYPE (min);
bool is_min = (INTEGRAL_TYPE_P (type) bool is_min = (INTEGRAL_TYPE_P (type)
&& tree_int_cst_compare (min, TYPE_MIN_VALUE (type)) <= 0); && tree_int_cst_compare (min, TYPE_MIN_VALUE (type)) <= 0);
bool is_max = (INTEGRAL_TYPE_P (type) bool is_max = (INTEGRAL_TYPE_P (type)
@ -729,22 +753,37 @@ value_range_base::set_and_canonicalize (enum value_range_kind kind,
} }
} }
/* Normalize [MIN, MAX] into VARYING and ~[MIN, MAX] into UNDEFINED.
Avoid using TYPE_{MIN,MAX}_VALUE because -fstrict-enums can
restrict those to a subset of what actually fits in the type.
Instead use the extremes of the type precision which will allow
compare_range_with_value() to check if a value is inside a range,
whereas if we used TYPE_*_VAL, said function would just punt
upon seeing a VARYING. */
unsigned prec = TYPE_PRECISION (type);
signop sign = TYPE_SIGN (type);
if (wi::eq_p (wi::to_wide (min), wi::min_value (prec, sign))
&& wi::eq_p (wi::to_wide (max), wi::max_value (prec, sign)))
{
if (kind == VR_RANGE)
set_varying ();
else if (kind == VR_ANTI_RANGE)
set_undefined ();
else
gcc_unreachable ();
return;
}
/* Do not drop [-INF(OVF), +INF(OVF)] to varying. (OVF) has to be sticky /* Do not drop [-INF(OVF), +INF(OVF)] to varying. (OVF) has to be sticky
to make sure VRP iteration terminates, otherwise we can get into to make sure VRP iteration terminates, otherwise we can get into
oscillations. */ oscillations. */
set (kind, min, max); m_kind = kind;
} m_min = min;
m_max = max;
void if (flag_checking)
value_range::set_and_canonicalize (enum value_range_kind kind, check ();
tree min, tree max, bitmap equiv)
{
value_range_base::set_and_canonicalize (kind, min, max);
if (this->kind () == VR_RANGE || this->kind () == VR_ANTI_RANGE)
set_equiv (equiv);
else
equiv_clear ();
} }
void void
@ -1180,7 +1219,8 @@ vrp_set_zero_nonzero_bits (const tree expr_type,
static bool static bool
ranges_from_anti_range (const value_range_base *ar, ranges_from_anti_range (const value_range_base *ar,
value_range_base *vr0, value_range_base *vr1) value_range_base *vr0, value_range_base *vr1,
bool handle_pointers)
{ {
tree type = ar->type (); tree type = ar->type ();
@ -1193,18 +1233,18 @@ ranges_from_anti_range (const value_range_base *ar,
if (ar->kind () != VR_ANTI_RANGE if (ar->kind () != VR_ANTI_RANGE
|| TREE_CODE (ar->min ()) != INTEGER_CST || TREE_CODE (ar->min ()) != INTEGER_CST
|| TREE_CODE (ar->max ()) != INTEGER_CST || TREE_CODE (ar->max ()) != INTEGER_CST
|| !vrp_val_min (type) || !vrp_val_min (type, handle_pointers)
|| !vrp_val_max (type)) || !vrp_val_max (type, handle_pointers))
return false; return false;
if (tree_int_cst_lt (vrp_val_min (type), ar->min ())) if (tree_int_cst_lt (vrp_val_min (type, handle_pointers), ar->min ()))
vr0->set (VR_RANGE, vr0->set (VR_RANGE,
vrp_val_min (type), vrp_val_min (type, handle_pointers),
wide_int_to_tree (type, wi::to_wide (ar->min ()) - 1)); wide_int_to_tree (type, wi::to_wide (ar->min ()) - 1));
if (tree_int_cst_lt (ar->max (), vrp_val_max (type))) if (tree_int_cst_lt (ar->max (), vrp_val_max (type, handle_pointers)))
vr1->set (VR_RANGE, vr1->set (VR_RANGE,
wide_int_to_tree (type, wi::to_wide (ar->max ()) + 1), wide_int_to_tree (type, wi::to_wide (ar->max ()) + 1),
vrp_val_max (type)); vrp_val_max (type, handle_pointers));
if (vr0->undefined_p ()) if (vr0->undefined_p ())
{ {
*vr0 = *vr1; *vr0 = *vr1;
@ -1215,21 +1255,20 @@ ranges_from_anti_range (const value_range_base *ar,
} }
/* Extract the components of a value range into a pair of wide ints in /* Extract the components of a value range into a pair of wide ints in
[WMIN, WMAX]. [WMIN, WMAX], after having normalized any symbolics from the input. */
If the value range is anything but a VR_*RANGE of constants, the
resulting wide ints are set to [-MIN, +MAX] for the type. */
static void inline static void inline
extract_range_into_wide_ints (const value_range_base *vr, extract_range_into_wide_ints (const value_range_base *vr_,
signop sign, unsigned prec, tree type, wide_int &wmin, wide_int &wmax)
wide_int &wmin, wide_int &wmax)
{ {
gcc_assert (vr->kind () != VR_ANTI_RANGE || vr->symbolic_p ()); signop sign = TYPE_SIGN (type);
if (range_int_cst_p (vr)) unsigned int prec = TYPE_PRECISION (type);
gcc_assert (vr_->kind () != VR_ANTI_RANGE || vr_->symbolic_p ());
value_range vr = vr_->normalize_symbolics ();
if (range_int_cst_p (&vr))
{ {
wmin = wi::to_wide (vr->min ()); wmin = wi::to_wide (vr.min ());
wmax = wi::to_wide (vr->max ()); wmax = wi::to_wide (vr.max ());
} }
else else
{ {
@ -1256,12 +1295,31 @@ extract_range_from_multiplicative_op (value_range_base *vr,
|| code == ROUND_DIV_EXPR || code == ROUND_DIV_EXPR
|| code == RSHIFT_EXPR || code == RSHIFT_EXPR
|| code == LSHIFT_EXPR); || code == LSHIFT_EXPR);
gcc_assert (vr0->kind () == VR_RANGE if (!range_int_cst_p (vr1))
&& vr0->kind () == vr1->kind ()); {
vr->set_varying ();
return;
}
/* Even if vr0 is VARYING or otherwise not usable, we can derive
useful ranges just from the shift count. E.g.
x >> 63 for signed 64-bit x is always [-1, 0]. */
value_range_base tem = vr0->normalize_symbolics ();
tree vr0_min, vr0_max;
if (tem.kind () == VR_RANGE)
{
vr0_min = tem.min ();
vr0_max = tem.max ();
}
else
{
vr0_min = vrp_val_min (type);
vr0_max = vrp_val_max (type);
}
wide_int res_lb, res_ub; wide_int res_lb, res_ub;
wide_int vr0_lb = wi::to_wide (vr0->min ()); wide_int vr0_lb = wi::to_wide (vr0_min);
wide_int vr0_ub = wi::to_wide (vr0->max ()); wide_int vr0_ub = wi::to_wide (vr0_max);
wide_int vr1_lb = wi::to_wide (vr1->min ()); wide_int vr1_lb = wi::to_wide (vr1->min ());
wide_int vr1_ub = wi::to_wide (vr1->max ()); wide_int vr1_ub = wi::to_wide (vr1->max ());
bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type); bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
@ -1271,9 +1329,8 @@ extract_range_from_multiplicative_op (value_range_base *vr,
code, TYPE_SIGN (type), prec, code, TYPE_SIGN (type), prec,
vr0_lb, vr0_ub, vr1_lb, vr1_ub, vr0_lb, vr0_ub, vr1_lb, vr1_ub,
overflow_undefined)) overflow_undefined))
vr->set_and_canonicalize (VR_RANGE, vr->set (VR_RANGE, wide_int_to_tree (type, res_lb),
wide_int_to_tree (type, res_lb), wide_int_to_tree (type, res_ub));
wide_int_to_tree (type, res_ub));
else else
vr->set_varying (); vr->set_varying ();
} }
@ -1667,19 +1724,30 @@ extract_range_from_binary_expr (value_range_base *vr,
range and see what we end up with. */ range and see what we end up with. */
if (code == PLUS_EXPR || code == MINUS_EXPR) if (code == PLUS_EXPR || code == MINUS_EXPR)
{ {
value_range_kind vr0_kind = vr0.kind (), vr1_kind = vr1.kind ();
tree vr0_min = vr0.min (), vr0_max = vr0.max ();
tree vr1_min = vr1.min (), vr1_max = vr1.max ();
/* This will normalize things such that calculating /* This will normalize things such that calculating
[0,0] - VR_VARYING is not dropped to varying, but is [0,0] - VR_VARYING is not dropped to varying, but is
calculated as [MIN+1, MAX]. */ calculated as [MIN+1, MAX]. */
if (vr0.varying_p ()) if (vr0.varying_p ())
vr0.set (VR_RANGE, vrp_val_min (expr_type), vrp_val_max (expr_type)); {
vr0_kind = VR_RANGE;
vr0_min = vrp_val_min (expr_type);
vr0_max = vrp_val_max (expr_type);
}
if (vr1.varying_p ()) if (vr1.varying_p ())
vr1.set (VR_RANGE, vrp_val_min (expr_type), vrp_val_max (expr_type)); {
vr1_kind = VR_RANGE;
vr1_min = vrp_val_min (expr_type);
vr1_max = vrp_val_max (expr_type);
}
const bool minus_p = (code == MINUS_EXPR); const bool minus_p = (code == MINUS_EXPR);
tree min_op0 = vr0.min (); tree min_op0 = vr0_min;
tree min_op1 = minus_p ? vr1.max () : vr1.min (); tree min_op1 = minus_p ? vr1_max : vr1_min;
tree max_op0 = vr0.max (); tree max_op0 = vr0_max;
tree max_op1 = minus_p ? vr1.min () : vr1.max (); tree max_op1 = minus_p ? vr1_min : vr1_max;
tree sym_min_op0 = NULL_TREE; tree sym_min_op0 = NULL_TREE;
tree sym_min_op1 = NULL_TREE; tree sym_min_op1 = NULL_TREE;
tree sym_max_op0 = NULL_TREE; tree sym_max_op0 = NULL_TREE;
@ -1692,7 +1760,7 @@ extract_range_from_binary_expr (value_range_base *vr,
single-symbolic ranges, try to compute the precise resulting range, single-symbolic ranges, try to compute the precise resulting range,
but only if we know that this resulting range will also be constant but only if we know that this resulting range will also be constant
or single-symbolic. */ or single-symbolic. */
if (vr0.kind () == VR_RANGE && vr1.kind () == VR_RANGE if (vr0_kind == VR_RANGE && vr1_kind == VR_RANGE
&& (TREE_CODE (min_op0) == INTEGER_CST && (TREE_CODE (min_op0) == INTEGER_CST
|| (sym_min_op0 || (sym_min_op0
= get_single_symbol (min_op0, &neg_min_op0, &min_op0))) = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
@ -1772,8 +1840,8 @@ extract_range_from_binary_expr (value_range_base *vr,
wide_int wmin, wmax; wide_int wmin, wmax;
wide_int vr0_min, vr0_max; wide_int vr0_min, vr0_max;
wide_int vr1_min, vr1_max; wide_int vr1_min, vr1_max;
extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max); extract_range_into_wide_ints (&vr0, expr_type, vr0_min, vr0_max);
extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max); extract_range_into_wide_ints (&vr1, expr_type, vr1_min, vr1_max);
if (wide_int_range_min_max (wmin, wmax, code, sign, prec, if (wide_int_range_min_max (wmin, wmax, code, sign, prec,
vr0_min, vr0_max, vr1_min, vr1_max)) vr0_min, vr0_max, vr1_min, vr1_max))
vr->set (VR_RANGE, wide_int_to_tree (expr_type, wmin), vr->set (VR_RANGE, wide_int_to_tree (expr_type, wmin),
@ -1805,12 +1873,6 @@ extract_range_from_binary_expr (value_range_base *vr,
{ {
if (code == RSHIFT_EXPR) if (code == RSHIFT_EXPR)
{ {
/* Even if vr0 is VARYING or otherwise not usable, we can derive
useful ranges just from the shift count. E.g.
x >> 63 for signed 64-bit x is always [-1, 0]. */
if (vr0.kind () != VR_RANGE || vr0.symbolic_p ())
vr0.set (VR_RANGE, vrp_val_min (expr_type),
vrp_val_max (expr_type));
extract_range_from_multiplicative_op (vr, code, expr_type, extract_range_from_multiplicative_op (vr, code, expr_type,
&vr0, &vr1); &vr0, &vr1);
return; return;
@ -1828,7 +1890,7 @@ extract_range_from_binary_expr (value_range_base *vr,
{ {
min = wide_int_to_tree (expr_type, res_lb); min = wide_int_to_tree (expr_type, res_lb);
max = wide_int_to_tree (expr_type, res_ub); max = wide_int_to_tree (expr_type, res_ub);
vr->set_and_canonicalize (VR_RANGE, min, max); vr->set (VR_RANGE, min, max);
return; return;
} }
} }
@ -1860,9 +1922,9 @@ extract_range_from_binary_expr (value_range_base *vr,
NOTE: As a future improvement, we may be able to do better NOTE: As a future improvement, we may be able to do better
with mixed symbolic (anti-)ranges like [0, A]. See note in with mixed symbolic (anti-)ranges like [0, A]. See note in
ranges_from_anti_range. */ ranges_from_anti_range. */
extract_range_into_wide_ints (&vr0, sign, prec, extract_range_into_wide_ints (&vr0, expr_type,
dividend_min, dividend_max); dividend_min, dividend_max);
extract_range_into_wide_ints (&vr1, sign, prec, extract_range_into_wide_ints (&vr1, expr_type,
divisor_min, divisor_max); divisor_min, divisor_max);
if (!wide_int_range_div (wmin, wmax, code, sign, prec, if (!wide_int_range_div (wmin, wmax, code, sign, prec,
dividend_min, dividend_max, dividend_min, dividend_max,
@ -1893,8 +1955,8 @@ extract_range_from_binary_expr (value_range_base *vr,
} }
wide_int wmin, wmax, tmp; wide_int wmin, wmax, tmp;
wide_int vr0_min, vr0_max, vr1_min, vr1_max; wide_int vr0_min, vr0_max, vr1_min, vr1_max;
extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max); extract_range_into_wide_ints (&vr0, expr_type, vr0_min, vr0_max);
extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max); extract_range_into_wide_ints (&vr1, expr_type, vr1_min, vr1_max);
wide_int_range_trunc_mod (wmin, wmax, sign, prec, wide_int_range_trunc_mod (wmin, wmax, sign, prec,
vr0_min, vr0_max, vr1_min, vr1_max); vr0_min, vr0_max, vr1_min, vr1_max);
min = wide_int_to_tree (expr_type, wmin); min = wide_int_to_tree (expr_type, wmin);
@ -1912,8 +1974,8 @@ extract_range_from_binary_expr (value_range_base *vr,
&may_be_nonzero0, &must_be_nonzero0); &may_be_nonzero0, &must_be_nonzero0);
vrp_set_zero_nonzero_bits (expr_type, &vr1, vrp_set_zero_nonzero_bits (expr_type, &vr1,
&may_be_nonzero1, &must_be_nonzero1); &may_be_nonzero1, &must_be_nonzero1);
extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max); extract_range_into_wide_ints (&vr0, expr_type, vr0_min, vr0_max);
extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max); extract_range_into_wide_ints (&vr1, expr_type, vr1_min, vr1_max);
if (code == BIT_AND_EXPR) if (code == BIT_AND_EXPR)
{ {
if (wide_int_range_bit_and (wmin, wmax, sign, prec, if (wide_int_range_bit_and (wmin, wmax, sign, prec,
@ -2117,8 +2179,7 @@ extract_range_from_unary_expr (value_range_base *vr,
signop outer_sign = TYPE_SIGN (outer_type); signop outer_sign = TYPE_SIGN (outer_type);
unsigned inner_prec = TYPE_PRECISION (inner_type); unsigned inner_prec = TYPE_PRECISION (inner_type);
unsigned outer_prec = TYPE_PRECISION (outer_type); unsigned outer_prec = TYPE_PRECISION (outer_type);
extract_range_into_wide_ints (&vr0, inner_sign, inner_prec, extract_range_into_wide_ints (&vr0, inner_type, vr0_min, vr0_max);
vr0_min, vr0_max);
if (wide_int_range_convert (wmin, wmax, if (wide_int_range_convert (wmin, wmax,
inner_sign, inner_prec, inner_sign, inner_prec,
outer_sign, outer_prec, outer_sign, outer_prec,
@ -2126,7 +2187,7 @@ extract_range_from_unary_expr (value_range_base *vr,
{ {
tree min = wide_int_to_tree (outer_type, wmin); tree min = wide_int_to_tree (outer_type, wmin);
tree max = wide_int_to_tree (outer_type, wmax); tree max = wide_int_to_tree (outer_type, wmax);
vr->set_and_canonicalize (VR_RANGE, min, max); vr->set (VR_RANGE, min, max);
} }
else else
vr->set_varying (); vr->set_varying ();
@ -2136,7 +2197,7 @@ extract_range_from_unary_expr (value_range_base *vr,
{ {
wide_int wmin, wmax; wide_int wmin, wmax;
wide_int vr0_min, vr0_max; wide_int vr0_min, vr0_max;
extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max); extract_range_into_wide_ints (&vr0, type, vr0_min, vr0_max);
if (wide_int_range_abs (wmin, wmax, sign, prec, vr0_min, vr0_max, if (wide_int_range_abs (wmin, wmax, sign, prec, vr0_min, vr0_max,
TYPE_OVERFLOW_UNDEFINED (type))) TYPE_OVERFLOW_UNDEFINED (type)))
vr->set (VR_RANGE, wide_int_to_tree (type, wmin), vr->set (VR_RANGE, wide_int_to_tree (type, wmin),
@ -2149,7 +2210,8 @@ extract_range_from_unary_expr (value_range_base *vr,
{ {
wide_int wmin, wmax; wide_int wmin, wmax;
wide_int vr0_min, vr0_max; wide_int vr0_min, vr0_max;
extract_range_into_wide_ints (&vr0, SIGNED, prec, vr0_min, vr0_max); tree signed_type = make_signed_type (TYPE_PRECISION (type));
extract_range_into_wide_ints (&vr0, signed_type, vr0_min, vr0_max);
wide_int_range_absu (wmin, wmax, prec, vr0_min, vr0_max); wide_int_range_absu (wmin, wmax, prec, vr0_min, vr0_max);
vr->set (VR_RANGE, wide_int_to_tree (type, wmin), vr->set (VR_RANGE, wide_int_to_tree (type, wmin),
wide_int_to_tree (type, wmax)); wide_int_to_tree (type, wmax));
@ -6038,7 +6100,7 @@ value_range_base::intersect_helper (const value_range_base *vr0,
VR_RANGE can still be a VR_RANGE. Work on a temporary so we can VR_RANGE can still be a VR_RANGE. Work on a temporary so we can
fall back to vr0 when this turns things to varying. */ fall back to vr0 when this turns things to varying. */
value_range_base tem; value_range_base tem;
tem.set_and_canonicalize (vr0type, vr0min, vr0max); tem.set (vr0type, vr0min, vr0max);
/* If that failed, use the saved original VR0. */ /* If that failed, use the saved original VR0. */
if (tem.varying_p ()) if (tem.varying_p ())
return *vr0; return *vr0;
@ -6143,7 +6205,7 @@ value_range_base::union_helper (const value_range_base *vr0,
/* Work on a temporary so we can still use vr0 when union returns varying. */ /* Work on a temporary so we can still use vr0 when union returns varying. */
value_range_base tem; value_range_base tem;
tem.set_and_canonicalize (vr0type, vr0min, vr0max); tem.set (vr0type, vr0min, vr0max);
/* Failed to find an efficient meet. Before giving up and setting /* Failed to find an efficient meet. Before giving up and setting
the result to VARYING, see if we can at least derive a useful the result to VARYING, see if we can at least derive a useful
@ -6223,6 +6285,58 @@ value_range::union_ (const value_range *other)
} }
} }
/* Normalize symbolics into constants. */
value_range_base
value_range_base::normalize_symbolics () const
{
if (varying_p () || undefined_p ())
return *this;
tree ttype = type ();
bool min_symbolic = !is_gimple_min_invariant (min ());
bool max_symbolic = !is_gimple_min_invariant (max ());
if (!min_symbolic && !max_symbolic)
return *this;
// [SYM, SYM] -> VARYING
if (min_symbolic && max_symbolic)
{
value_range_base var;
var.set_varying ();
return var;
}
if (kind () == VR_RANGE)
{
// [SYM, NUM] -> [-MIN, NUM]
if (min_symbolic)
return value_range_base (VR_RANGE, vrp_val_min (ttype), max ());
// [NUM, SYM] -> [NUM, +MAX]
return value_range_base (VR_RANGE, min (), vrp_val_max (ttype));
}
gcc_assert (kind () == VR_ANTI_RANGE);
// ~[SYM, NUM] -> [NUM + 1, +MAX]
if (min_symbolic)
{
if (!vrp_val_is_max (max ()))
{
tree n = wide_int_to_tree (ttype, wi::to_wide (max ()) + 1);
return value_range_base (VR_RANGE, n, vrp_val_max (ttype));
}
value_range_base var;
var.set_varying ();
return var;
}
// ~[NUM, SYM] -> [-MIN, NUM - 1]
if (!vrp_val_is_min (min ()))
{
tree n = wide_int_to_tree (ttype, wi::to_wide (min ()) - 1);
return value_range_base (VR_RANGE, vrp_val_min (ttype), n);
}
value_range_base var;
var.set_varying ();
return var;
}
/* Visit all arguments for PHI node PHI that flow through executable /* Visit all arguments for PHI node PHI that flow through executable
edges. If a valid value range can be derived from all the incoming edges. If a valid value range can be derived from all the incoming
value ranges, set a new range for the LHS of PHI. */ value ranges, set a new range for the LHS of PHI. */

View File

@ -71,12 +71,13 @@ public:
/* Misc methods. */ /* Misc methods. */
tree type () const; tree type () const;
bool may_contain_p (tree) const; bool may_contain_p (tree) const;
void set_and_canonicalize (enum value_range_kind, tree, tree);
bool zero_p () const; bool zero_p () const;
bool nonzero_p () const; bool nonzero_p () const;
bool singleton_p (tree *result = NULL) const; bool singleton_p (tree *result = NULL) const;
void dump (FILE *) const; void dump (FILE *) const;
value_range_base normalize_symbolics () const;
protected: protected:
void check (); void check ();
static value_range_base union_helper (const value_range_base *, static value_range_base union_helper (const value_range_base *,
@ -143,7 +144,6 @@ class GTY((user)) value_range : public value_range_base
/* Misc methods. */ /* Misc methods. */
void deep_copy (const value_range *); void deep_copy (const value_range *);
void set_and_canonicalize (enum value_range_kind, tree, tree, bitmap = NULL);
void dump (FILE *) const; void dump (FILE *) const;
private: private:
@ -270,8 +270,8 @@ extern int operand_less_p (tree, tree);
extern bool vrp_val_is_min (const_tree); extern bool vrp_val_is_min (const_tree);
extern bool vrp_val_is_max (const_tree); extern bool vrp_val_is_max (const_tree);
extern tree vrp_val_min (const_tree); extern tree vrp_val_min (const_tree, bool handle_pointers = false);
extern tree vrp_val_max (const_tree); extern tree vrp_val_max (const_tree, bool handle_pointers = false);
extern void extract_range_from_unary_expr (value_range_base *vr, extern void extract_range_from_unary_expr (value_range_base *vr,
enum tree_code code, enum tree_code code,

View File

@ -522,9 +522,9 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
vice-versa. Use set_and_canonicalize which does this for vice-versa. Use set_and_canonicalize which does this for
us. */ us. */
if (cond_code == LE_EXPR) if (cond_code == LE_EXPR)
vr_p->set_and_canonicalize (VR_RANGE, min, max, vr_p->equiv ()); vr_p->set (VR_RANGE, min, max, vr_p->equiv ());
else if (cond_code == GT_EXPR) else if (cond_code == GT_EXPR)
vr_p->set_and_canonicalize (VR_ANTI_RANGE, min, max, vr_p->equiv ()); vr_p->set (VR_ANTI_RANGE, min, max, vr_p->equiv ());
else else
gcc_unreachable (); gcc_unreachable ();
} }
@ -596,7 +596,7 @@ vr_values::extract_range_for_var_from_comparison_expr (tree var,
&& vrp_val_is_max (max)) && vrp_val_is_max (max))
min = max = limit; min = max = limit;
vr_p->set_and_canonicalize (VR_ANTI_RANGE, min, max, vr_p->equiv ()); vr_p->set (VR_ANTI_RANGE, min, max, vr_p->equiv ());
} }
else if (cond_code == LE_EXPR || cond_code == LT_EXPR) else if (cond_code == LE_EXPR || cond_code == LT_EXPR)
{ {