X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-vrp.c;h=7ea026272b859f8a404e271a225987fad597ff04;hb=984bd63790d0bce0e9b8d700f95e6c784a7cd746;hp=b165418b36765f97c1489972f72968a0e9fbe081;hpb=fbcece5e7df36c19d0712bd881f74d637c43b0cd;p=pf3gnuchains%2Fgcc-fork.git
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index b165418b367..7ea026272b8 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -6,7 +6,7 @@ This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
@@ -15,9 +15,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+. */
#include "config.h"
#include "system.h"
@@ -48,6 +47,8 @@ static int compare_values (tree val1, tree val2);
static int compare_values_warnv (tree val1, tree val2, bool *);
static void vrp_meet (value_range_t *, value_range_t *);
static tree vrp_evaluate_conditional_warnv (tree, bool, bool *);
+static tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
+ tree, tree, bool, bool *);
/* Location information for ASSERT_EXPRs. Each instance of this
structure describes an ASSERT_EXPR for an SSA name. Since a single
@@ -72,6 +73,9 @@ struct assert_locus_d
/* Value being compared against. */
tree val;
+ /* Expression to compare. */
+ tree expr;
+
/* Next node in the linked list. */
struct assert_locus_d *next;
};
@@ -100,6 +104,74 @@ static value_range_t **vr_value;
node. */
static int *vr_phi_edge_counts;
+typedef struct {
+ tree stmt;
+ tree vec;
+} switch_update;
+
+static VEC (edge, heap) *to_remove_edges;
+DEF_VEC_O(switch_update);
+DEF_VEC_ALLOC_O(switch_update, heap);
+static VEC (switch_update, heap) *to_update_switch_stmts;
+
+
+/* Return the maximum value for TYPEs base type. */
+
+static inline tree
+vrp_val_max (const_tree type)
+{
+ if (!INTEGRAL_TYPE_P (type))
+ return NULL_TREE;
+
+ /* For integer sub-types the values for the base type are relevant. */
+ if (TREE_TYPE (type))
+ type = TREE_TYPE (type);
+
+ return TYPE_MAX_VALUE (type);
+}
+
+/* Return the minimum value for TYPEs base type. */
+
+static inline tree
+vrp_val_min (const_tree type)
+{
+ if (!INTEGRAL_TYPE_P (type))
+ return NULL_TREE;
+
+ /* For integer sub-types the values for the base type are relevant. */
+ if (TREE_TYPE (type))
+ type = TREE_TYPE (type);
+
+ return TYPE_MIN_VALUE (type);
+}
+
+/* Return whether VAL is equal to the maximum value of its type. This
+ will be true for a positive overflow infinity. We can't do a
+ simple equality comparison with TYPE_MAX_VALUE because C typedefs
+ and Ada subtypes can produce types whose TYPE_MAX_VALUE is not ==
+ to the integer constant with the same value in the type. */
+
+static inline bool
+vrp_val_is_max (const_tree val)
+{
+ tree type_max = vrp_val_max (TREE_TYPE (val));
+ return (val == type_max
+ || (type_max != NULL_TREE
+ && operand_equal_p (val, type_max, 0)));
+}
+
+/* Return whether VAL is equal to the minimum value of its type. This
+ will be true for a negative overflow infinity. */
+
+static inline bool
+vrp_val_is_min (const_tree val)
+{
+ tree type_min = vrp_val_min (TREE_TYPE (val));
+ return (val == type_min
+ || (type_min != NULL_TREE
+ && operand_equal_p (val, type_min, 0)));
+}
+
/* Return whether TYPE should use an overflow infinity distinct from
TYPE_{MIN,MAX}_VALUE. We use an overflow infinity value to
@@ -108,9 +180,13 @@ static int *vr_phi_edge_counts;
TYPE_{MIN,MAX}_VALUE. */
static inline bool
-needs_overflow_infinity (tree type)
+needs_overflow_infinity (const_tree type)
{
- return INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type);
+ return (INTEGRAL_TYPE_P (type)
+ && !TYPE_OVERFLOW_WRAPS (type)
+ /* Integer sub-types never overflow as they are never
+ operands of arithmetic operators. */
+ && !(TREE_TYPE (type) && TREE_TYPE (type) != type));
}
/* Return whether TYPE can support our overflow infinity
@@ -120,15 +196,16 @@ needs_overflow_infinity (tree type)
VARYING. */
static inline bool
-supports_overflow_infinity (tree type)
+supports_overflow_infinity (const_tree type)
{
+ tree min = vrp_val_min (type), max = vrp_val_max (type);
#ifdef ENABLE_CHECKING
gcc_assert (needs_overflow_infinity (type));
#endif
- return (TYPE_MIN_VALUE (type) != NULL_TREE
- && CONSTANT_CLASS_P (TYPE_MIN_VALUE (type))
- && TYPE_MAX_VALUE (type) != NULL_TREE
- && CONSTANT_CLASS_P (TYPE_MAX_VALUE (type)));
+ return (min != NULL_TREE
+ && CONSTANT_CLASS_P (min)
+ && max != NULL_TREE
+ && CONSTANT_CLASS_P (max));
}
/* VAL is the maximum or minimum value of a type. Return a
@@ -153,7 +230,7 @@ negative_overflow_infinity (tree type)
#ifdef ENABLE_CHECKING
gcc_assert (supports_overflow_infinity (type));
#endif
- return make_overflow_infinity (TYPE_MIN_VALUE (type));
+ return make_overflow_infinity (vrp_val_min (type));
}
/* Return a positive overflow infinity for TYPE. */
@@ -164,41 +241,61 @@ positive_overflow_infinity (tree type)
#ifdef ENABLE_CHECKING
gcc_assert (supports_overflow_infinity (type));
#endif
- return make_overflow_infinity (TYPE_MAX_VALUE (type));
+ return make_overflow_infinity (vrp_val_max (type));
}
/* Return whether VAL is a negative overflow infinity. */
static inline bool
-is_negative_overflow_infinity (tree val)
+is_negative_overflow_infinity (const_tree val)
{
return (needs_overflow_infinity (TREE_TYPE (val))
&& CONSTANT_CLASS_P (val)
&& TREE_OVERFLOW (val)
- && operand_equal_p (val, TYPE_MIN_VALUE (TREE_TYPE (val)), 0));
+ && vrp_val_is_min (val));
}
/* Return whether VAL is a positive overflow infinity. */
static inline bool
-is_positive_overflow_infinity (tree val)
+is_positive_overflow_infinity (const_tree val)
{
return (needs_overflow_infinity (TREE_TYPE (val))
&& CONSTANT_CLASS_P (val)
&& TREE_OVERFLOW (val)
- && operand_equal_p (val, TYPE_MAX_VALUE (TREE_TYPE (val)), 0));
+ && vrp_val_is_max (val));
}
/* Return whether VAL is a positive or negative overflow infinity. */
static inline bool
-is_overflow_infinity (tree val)
+is_overflow_infinity (const_tree val)
{
return (needs_overflow_infinity (TREE_TYPE (val))
&& CONSTANT_CLASS_P (val)
&& TREE_OVERFLOW (val)
- && (operand_equal_p (val, TYPE_MAX_VALUE (TREE_TYPE (val)), 0)
- || operand_equal_p (val, TYPE_MIN_VALUE (TREE_TYPE (val)), 0)));
+ && (vrp_val_is_min (val) || vrp_val_is_max (val)));
+}
+
+/* If VAL is now an overflow infinity, return VAL. Otherwise, return
+ the same value with TREE_OVERFLOW clear. This can be used to avoid
+ confusing a regular value with an overflow value. */
+
+static inline tree
+avoid_overflow_infinity (tree val)
+{
+ if (!is_overflow_infinity (val))
+ return val;
+
+ if (vrp_val_is_max (val))
+ return vrp_val_max (TREE_TYPE (val));
+ else
+ {
+#ifdef ENABLE_CHECKING
+ gcc_assert (vrp_val_is_min (val));
+#endif
+ return vrp_val_min (TREE_TYPE (val));
+ }
}
@@ -206,7 +303,7 @@ is_overflow_infinity (tree val)
current function signature. */
static bool
-nonnull_arg_p (tree arg)
+nonnull_arg_p (const_tree arg)
{
tree t, attrs, fntype;
unsigned HOST_WIDE_INT arg_num;
@@ -250,6 +347,18 @@ nonnull_arg_p (tree arg)
}
+/* Set value range VR to VR_VARYING. */
+
+static inline void
+set_value_range_to_varying (value_range_t *vr)
+{
+ vr->type = VR_VARYING;
+ vr->min = vr->max = NULL_TREE;
+ if (vr->equiv)
+ bitmap_clear (vr->equiv);
+}
+
+
/* Set value range VR to {T, MIN, MAX, EQUIV}. */
static void
@@ -265,10 +374,7 @@ set_value_range (value_range_t *vr, enum value_range_type t, tree min,
gcc_assert (min && max);
if (INTEGRAL_TYPE_P (TREE_TYPE (min)) && t == VR_ANTI_RANGE)
- gcc_assert ((min != TYPE_MIN_VALUE (TREE_TYPE (min))
- && !is_negative_overflow_infinity (min))
- || (max != TYPE_MAX_VALUE (TREE_TYPE (max))
- && !is_positive_overflow_infinity (max)));
+ gcc_assert (!vrp_val_is_min (min) || !vrp_val_is_max (max));
cmp = compare_values (min, max);
gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
@@ -305,24 +411,90 @@ set_value_range (value_range_t *vr, enum value_range_type t, tree min,
}
-/* Copy value range FROM into value range TO. */
+/* Set value range VR to the canonical form of {T, MIN, MAX, EQUIV}.
+ This means adjusting T, MIN and MAX representing the case of a
+ wrapping range with MAX < MIN covering [MIN, type_max] U [type_min, MAX]
+ as anti-rage ~[MAX+1, MIN-1]. Likewise for wrapping anti-ranges.
+ In corner cases where MAX+1 or MIN-1 wraps this will fall back
+ to varying.
+ This routine exists to ease canonicalization in the case where we
+ extract ranges from var + CST op limit. */
-static inline void
-copy_value_range (value_range_t *to, value_range_t *from)
+static void
+set_and_canonicalize_value_range (value_range_t *vr, enum value_range_type t,
+ tree min, tree max, bitmap equiv)
{
- set_value_range (to, from->type, from->min, from->max, from->equiv);
-}
+ /* Nothing to canonicalize for symbolic or unknown or varying ranges. */
+ if ((t != VR_RANGE
+ && t != VR_ANTI_RANGE)
+ || TREE_CODE (min) != INTEGER_CST
+ || TREE_CODE (max) != INTEGER_CST)
+ {
+ set_value_range (vr, t, min, max, equiv);
+ return;
+ }
+ /* Wrong order for min and max, to swap them and the VR type we need
+ to adjust them. */
+ if (tree_int_cst_lt (max, min))
+ {
+ tree one = build_int_cst (TREE_TYPE (min), 1);
+ tree tmp = int_const_binop (PLUS_EXPR, max, one, 0);
+ max = int_const_binop (MINUS_EXPR, min, one, 0);
+ min = tmp;
-/* Set value range VR to VR_VARYING. */
+ /* There's one corner case, if we had [C+1, C] before we now have
+ that again. But this represents an empty value range, so drop
+ to varying in this case. */
+ if (tree_int_cst_lt (max, min))
+ {
+ set_value_range_to_varying (vr);
+ return;
+ }
+
+ t = t == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
+ }
+
+ /* Anti-ranges that can be represented as ranges should be so. */
+ if (t == VR_ANTI_RANGE)
+ {
+ bool is_min = vrp_val_is_min (min);
+ bool is_max = vrp_val_is_max (max);
+
+ if (is_min && is_max)
+ {
+ /* We cannot deal with empty ranges, drop to varying. */
+ set_value_range_to_varying (vr);
+ return;
+ }
+ else if (is_min
+ /* As a special exception preserve non-null ranges. */
+ && !(TYPE_UNSIGNED (TREE_TYPE (min))
+ && integer_zerop (max)))
+ {
+ tree one = build_int_cst (TREE_TYPE (max), 1);
+ min = int_const_binop (PLUS_EXPR, max, one, 0);
+ max = vrp_val_max (TREE_TYPE (max));
+ t = VR_RANGE;
+ }
+ else if (is_max)
+ {
+ tree one = build_int_cst (TREE_TYPE (min), 1);
+ max = int_const_binop (MINUS_EXPR, min, one, 0);
+ min = vrp_val_min (TREE_TYPE (min));
+ t = VR_RANGE;
+ }
+ }
+
+ set_value_range (vr, t, min, max, equiv);
+}
+
+/* Copy value range FROM into value range TO. */
static inline void
-set_value_range_to_varying (value_range_t *vr)
+copy_value_range (value_range_t *to, value_range_t *from)
{
- vr->type = VR_VARYING;
- vr->min = vr->max = NULL_TREE;
- if (vr->equiv)
- bitmap_clear (vr->equiv);
+ set_value_range (to, from->type, from->min, from->max, from->equiv);
}
/* Set value range VR to a single value. This function is only called
@@ -331,19 +503,15 @@ set_value_range_to_varying (value_range_t *vr)
infinity when we shouldn't. */
static inline void
-set_value_range_to_value (value_range_t *vr, tree val)
+set_value_range_to_value (value_range_t *vr, tree val, bitmap equiv)
{
gcc_assert (is_gimple_min_invariant (val));
- if (is_overflow_infinity (val))
- {
- val = copy_node (val);
- TREE_OVERFLOW (val) = 0;
- }
- set_value_range (vr, VR_RANGE, val, val, NULL);
+ val = avoid_overflow_infinity (val);
+ set_value_range (vr, VR_RANGE, val, val, equiv);
}
/* Set value range VR to a non-negative range of type TYPE.
- OVERFLOW_INFINITY indicates whether to use a overflow infinity
+ OVERFLOW_INFINITY indicates whether to use an overflow infinity
rather than TYPE_MAX_VALUE; this should be true if we determine
that the range is nonnegative based on the assumption that signed
overflow does not occur. */
@@ -383,8 +551,7 @@ set_value_range_to_nonnull (value_range_t *vr, tree type)
static inline void
set_value_range_to_null (value_range_t *vr, tree type)
{
- tree zero = build_int_cst (type, 0);
- set_value_range (vr, VR_RANGE, zero, zero, vr->equiv);
+ set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv);
}
@@ -420,7 +587,7 @@ set_value_range_to_undefined (value_range_t *vr)
return NULL. Otherwise create an empty range if none existed for VAR. */
static value_range_t *
-get_value_range (tree var)
+get_value_range (const_tree var)
{
value_range_t *vr;
tree sym;
@@ -462,7 +629,7 @@ get_value_range (tree var)
/* Return true, if VAL1 and VAL2 are equal values for VRP purposes. */
static inline bool
-vrp_operand_equal_p (tree val1, tree val2)
+vrp_operand_equal_p (const_tree val1, const_tree val2)
{
if (val1 == val2)
return true;
@@ -476,7 +643,7 @@ vrp_operand_equal_p (tree val1, tree val2)
/* Return true, if the bitmaps B1 and B2 are equal. */
static inline bool
-vrp_bitmap_equal_p (bitmap b1, bitmap b2)
+vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
{
return (b1 == b2
|| (b1 && b2
@@ -494,7 +661,7 @@ vrp_bitmap_equal_p (bitmap b1, bitmap b2)
is the range object associated with another SSA name. */
static inline bool
-update_value_range (tree var, value_range_t *new_vr)
+update_value_range (const_tree var, value_range_t *new_vr)
{
value_range_t *old_vr;
bool is_new;
@@ -520,7 +687,7 @@ update_value_range (tree var, value_range_t *new_vr)
point where equivalence processing can be turned on/off. */
static void
-add_equivalence (bitmap *equiv, tree var)
+add_equivalence (bitmap *equiv, const_tree var)
{
unsigned ver = SSA_NAME_VERSION (var);
value_range_t *vr = vr_value[ver];
@@ -564,7 +731,7 @@ symbolic_range_p (value_range_t *vr)
|| !is_gimple_min_invariant (vr->max));
}
-/* Return true if value range VR uses a overflow infinity. */
+/* Return true if value range VR uses an overflow infinity. */
static inline bool
overflow_infinity_range_p (value_range_t *vr)
@@ -682,7 +849,8 @@ operand_less_p (tree val, tree val2)
fold_undefer_and_ignore_overflow_warnings ();
- if (!tcmp)
+ if (!tcmp
+ || TREE_CODE (tcmp) != INTEGER_CST)
return -2;
if (!integer_zerop (tcmp))
@@ -723,6 +891,10 @@ compare_values_warnv (tree val1, tree val2, bool *strict_overflow_p)
both integers. */
gcc_assert (POINTER_TYPE_P (TREE_TYPE (val1))
== POINTER_TYPE_P (TREE_TYPE (val2)));
+ /* Convert the two values into the same type. This is needed because
+ sizetype causes sign extension even for unsigned types. */
+ val2 = fold_convert (TREE_TYPE (val1), val2);
+ STRIP_USELESS_TYPE_CONVERSION (val2);
if ((TREE_CODE (val1) == SSA_NAME
|| TREE_CODE (val1) == PLUS_EXPR
@@ -794,7 +966,9 @@ compare_values_warnv (tree val1, tree val2, bool *strict_overflow_p)
if (!TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (val1)))
return -2;
- if (strict_overflow_p != NULL)
+ if (strict_overflow_p != NULL
+ && (code1 == SSA_NAME || !TREE_NO_WARNING (val1))
+ && (code2 == SSA_NAME || !TREE_NO_WARNING (val2)))
*strict_overflow_p = true;
if (code1 == SSA_NAME)
@@ -884,7 +1058,7 @@ compare_values_warnv (tree val1, tree val2, bool *strict_overflow_p)
|| TREE_CODE (val2) != INTEGER_CST)
{
t = fold_binary_to_constant (NE_EXPR, boolean_type_node, val1, val2);
- if (t && tree_expr_nonzero_p (t))
+ if (t && integer_onep (t))
return 2;
}
@@ -996,7 +1170,7 @@ range_includes_zero_p (value_range_t *vr)
false otherwise or if no value range information is available. */
bool
-ssa_name_nonnegative_p (tree t)
+ssa_name_nonnegative_p (const_tree t)
{
value_range_t *vr = get_value_range (t);
@@ -1018,7 +1192,7 @@ ssa_name_nonnegative_p (tree t)
false otherwise or if no value range information is available. */
bool
-ssa_name_nonzero_p (tree t)
+ssa_name_nonzero_p (const_tree t)
{
value_range_t *vr = get_value_range (t);
@@ -1053,22 +1227,28 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
gcc_assert (COMPARISON_CLASS_P (cond));
/* Find VAR in the ASSERT_EXPR conditional. */
- if (var == TREE_OPERAND (cond, 0))
+ if (var == TREE_OPERAND (cond, 0)
+ || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
+ || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
{
/* If the predicate is of the form VAR COMP LIMIT, then we just
take LIMIT from the RHS and use the same comparison code. */
- limit = TREE_OPERAND (cond, 1);
cond_code = TREE_CODE (cond);
+ limit = TREE_OPERAND (cond, 1);
+ cond = TREE_OPERAND (cond, 0);
}
else
{
/* If the predicate is of the form LIMIT COMP VAR, then we need
to flip around the comparison code to create the proper range
for VAR. */
- limit = TREE_OPERAND (cond, 0);
cond_code = swap_tree_comparison (TREE_CODE (cond));
+ limit = TREE_OPERAND (cond, 0);
+ cond = TREE_OPERAND (cond, 1);
}
+ limit = avoid_overflow_infinity (limit);
+
type = TREE_TYPE (limit);
gcc_assert (limit != var);
@@ -1108,8 +1288,46 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
instance, ASSERT_EXPR . If b_4 is ~[2, 10],
then b_4 takes on the ranges [-INF, 1] and [11, +INF]. There is
no single range for x_2 that could describe LE_EXPR, so we might
- as well build the range [b_4, +INF] for it. */
- if (cond_code == EQ_EXPR)
+ as well build the range [b_4, +INF] for it.
+ One special case we handle is extracting a range from a
+ range test encoded as (unsigned)var + CST <= limit. */
+ if (TREE_CODE (cond) == NOP_EXPR
+ || TREE_CODE (cond) == PLUS_EXPR)
+ {
+ if (TREE_CODE (cond) == PLUS_EXPR)
+ {
+ min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
+ TREE_OPERAND (cond, 1));
+ max = int_const_binop (PLUS_EXPR, limit, min, 0);
+ cond = TREE_OPERAND (cond, 0);
+ }
+ else
+ {
+ min = build_int_cst (TREE_TYPE (var), 0);
+ max = limit;
+ }
+
+ /* Make sure to not set TREE_OVERFLOW on the final type
+ conversion. We are willingly interpreting large positive
+ unsigned values as negative singed values here. */
+ min = force_fit_type_double (TREE_TYPE (var), TREE_INT_CST_LOW (min),
+ TREE_INT_CST_HIGH (min), 0, false);
+ max = force_fit_type_double (TREE_TYPE (var), TREE_INT_CST_LOW (max),
+ TREE_INT_CST_HIGH (max), 0, false);
+
+ /* We can transform a max, min range to an anti-range or
+ vice-versa. Use set_and_canonicalize_value_range which does
+ this for us. */
+ if (cond_code == LE_EXPR)
+ set_and_canonicalize_value_range (vr_p, VR_RANGE,
+ min, max, vr_p->equiv);
+ else if (cond_code == GT_EXPR)
+ set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
+ min, max, vr_p->equiv);
+ else
+ gcc_unreachable ();
+ }
+ else if (cond_code == EQ_EXPR)
{
enum value_range_type range_type;
@@ -1173,10 +1391,8 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
/* If MIN and MAX cover the whole range for their type, then
just use the original LIMIT. */
if (INTEGRAL_TYPE_P (type)
- && (min == TYPE_MIN_VALUE (type)
- || is_negative_overflow_infinity (min))
- && (max == TYPE_MAX_VALUE (type)
- || is_positive_overflow_infinity (max)))
+ && vrp_val_is_min (min)
+ && vrp_val_is_max (max))
min = max = limit;
set_value_range (vr_p, VR_ANTI_RANGE, min, max, vr_p->equiv);
@@ -1209,6 +1425,8 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
{
tree one = build_int_cst (type, 1);
max = fold_build2 (MINUS_EXPR, type, max, one);
+ if (EXPR_P (max))
+ TREE_NO_WARNING (max) = 1;
}
set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
@@ -1242,6 +1460,8 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
{
tree one = build_int_cst (type, 1);
min = fold_build2 (PLUS_EXPR, type, min, one);
+ if (EXPR_P (min))
+ TREE_NO_WARNING (min) = 1;
}
set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
@@ -1391,8 +1611,12 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
if (compare_values (anti_max, real_max) == -1
&& compare_values (anti_min, real_min) == 1)
{
- set_value_range (vr_p, VR_RANGE, real_min,
- real_max, vr_p->equiv);
+ /* If the range is covering the whole valid range of
+ the type keep the anti-range. */
+ if (!vrp_val_is_min (real_min)
+ || !vrp_val_is_max (real_max))
+ set_value_range (vr_p, VR_RANGE, real_min,
+ real_max, vr_p->equiv);
}
/* Case 2, VR_ANTI_RANGE completely disjoint from
VR_RANGE. */
@@ -1411,7 +1635,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
{
gcc_assert (!is_positive_overflow_infinity (anti_max));
if (needs_overflow_infinity (TREE_TYPE (anti_max))
- && anti_max == TYPE_MAX_VALUE (TREE_TYPE (anti_max)))
+ && vrp_val_is_max (anti_max))
{
if (!supports_overflow_infinity (TREE_TYPE (var_vr->min)))
{
@@ -1420,10 +1644,13 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
}
min = positive_overflow_infinity (TREE_TYPE (var_vr->min));
}
- else
+ else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
anti_max,
build_int_cst (TREE_TYPE (var_vr->min), 1));
+ else
+ min = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (var_vr->min),
+ anti_max, size_int (1));
max = real_max;
set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
}
@@ -1436,7 +1663,7 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
{
gcc_assert (!is_negative_overflow_infinity (anti_min));
if (needs_overflow_infinity (TREE_TYPE (anti_min))
- && anti_min == TYPE_MIN_VALUE (TREE_TYPE (anti_min)))
+ && vrp_val_is_min (anti_min))
{
if (!supports_overflow_infinity (TREE_TYPE (var_vr->min)))
{
@@ -1445,10 +1672,14 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
}
max = negative_overflow_infinity (TREE_TYPE (var_vr->min));
}
- else
+ else if (!POINTER_TYPE_P (TREE_TYPE (var_vr->min)))
max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
anti_min,
build_int_cst (TREE_TYPE (var_vr->min), 1));
+ else
+ max = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (var_vr->min),
+ anti_min,
+ size_int (-1));
min = real_min;
set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
}
@@ -1631,11 +1862,12 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
the ranges of each of its operands and the expression code. */
static void
-extract_range_from_binary_expr (value_range_t *vr, tree expr)
+extract_range_from_binary_expr (value_range_t *vr,
+ enum tree_code code,
+ tree expr_type, tree op0, tree op1)
{
- enum tree_code code = TREE_CODE (expr);
enum value_range_type type;
- tree op0, op1, min, max;
+ tree min, max;
int cmp;
value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
value_range_t vr1 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
@@ -1644,6 +1876,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
meaningful way. Handle only arithmetic operations. */
if (code != PLUS_EXPR
&& code != MINUS_EXPR
+ && code != POINTER_PLUS_EXPR
&& code != MULT_EXPR
&& code != TRUNC_DIV_EXPR
&& code != FLOOR_DIV_EXPR
@@ -1654,8 +1887,6 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
&& code != MIN_EXPR
&& code != MAX_EXPR
&& code != BIT_AND_EXPR
- && code != TRUTH_ANDIF_EXPR
- && code != TRUTH_ORIF_EXPR
&& code != TRUTH_AND_EXPR
&& code != TRUTH_OR_EXPR)
{
@@ -1665,19 +1896,17 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
/* Get value ranges for each operand. For constant operands, create
a new value range with the operand to simplify processing. */
- op0 = TREE_OPERAND (expr, 0);
if (TREE_CODE (op0) == SSA_NAME)
vr0 = *(get_value_range (op0));
else if (is_gimple_min_invariant (op0))
- set_value_range_to_value (&vr0, op0);
+ set_value_range_to_value (&vr0, op0, NULL);
else
set_value_range_to_varying (&vr0);
- op1 = TREE_OPERAND (expr, 1);
if (TREE_CODE (op1) == SSA_NAME)
vr1 = *(get_value_range (op1));
else if (is_gimple_min_invariant (op1))
- set_value_range_to_value (&vr1, op1);
+ set_value_range_to_value (&vr1, op1, NULL);
else
set_value_range_to_varying (&vr1);
@@ -1710,39 +1939,41 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
}
/* Now evaluate the expression to determine the new range. */
- if (POINTER_TYPE_P (TREE_TYPE (expr))
+ if (POINTER_TYPE_P (expr_type)
|| POINTER_TYPE_P (TREE_TYPE (op0))
|| POINTER_TYPE_P (TREE_TYPE (op1)))
{
- /* For pointer types, we are really only interested in asserting
- whether the expression evaluates to non-NULL. FIXME, we used
- to gcc_assert (code == PLUS_EXPR || code == MINUS_EXPR), but
- ivopts is generating expressions with pointer multiplication
- in them. */
- if (code == PLUS_EXPR)
+ if (code == MIN_EXPR || code == MAX_EXPR)
{
- if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
- set_value_range_to_nonnull (vr, TREE_TYPE (expr));
+ /* For MIN/MAX expressions with pointers, we only care about
+ nullness, if both are non null, then the result is nonnull.
+ If both are null, then the result is null. Otherwise they
+ are varying. */
+ if (range_is_nonnull (&vr0) && range_is_nonnull (&vr1))
+ set_value_range_to_nonnull (vr, expr_type);
else if (range_is_null (&vr0) && range_is_null (&vr1))
- set_value_range_to_null (vr, TREE_TYPE (expr));
+ set_value_range_to_null (vr, expr_type);
else
set_value_range_to_varying (vr);
+
+ return;
}
+ gcc_assert (code == POINTER_PLUS_EXPR);
+ /* For pointer types, we are really only interested in asserting
+ whether the expression evaluates to non-NULL. */
+ if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
+ set_value_range_to_nonnull (vr, expr_type);
+ else if (range_is_null (&vr0) && range_is_null (&vr1))
+ set_value_range_to_null (vr, expr_type);
else
- {
- /* Subtracting from a pointer, may yield 0, so just drop the
- resulting range to varying. */
- set_value_range_to_varying (vr);
- }
+ set_value_range_to_varying (vr);
return;
}
/* For integer ranges, apply the operation to each end of the
range and see what we end up with. */
- if (code == TRUTH_ANDIF_EXPR
- || code == TRUTH_ORIF_EXPR
- || code == TRUTH_AND_EXPR
+ if (code == TRUTH_AND_EXPR
|| code == TRUTH_OR_EXPR)
{
/* If one of the operands is zero, we know that the whole
@@ -1756,7 +1987,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
&& integer_zerop (vr1.max))))
{
type = VR_RANGE;
- min = max = build_int_cst (TREE_TYPE (expr), 0);
+ min = max = build_int_cst (expr_type, 0);
}
/* If one of the operands is one, we know that the whole
expression evaluates one. */
@@ -1769,7 +2000,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
&& integer_onep (vr1.max))))
{
type = VR_RANGE;
- min = max = build_int_cst (TREE_TYPE (expr), 1);
+ min = max = build_int_cst (expr_type, 1);
}
else if (vr0.type != VR_VARYING
&& vr1.type != VR_VARYING
@@ -1780,13 +2011,13 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
&& !overflow_infinity_range_p (&vr1))
{
/* Boolean expressions cannot be folded with int_const_binop. */
- min = fold_binary (code, TREE_TYPE (expr), vr0.min, vr1.min);
- max = fold_binary (code, TREE_TYPE (expr), vr0.max, vr1.max);
+ min = fold_binary (code, expr_type, vr0.min, vr1.min);
+ max = fold_binary (code, expr_type, vr0.max, vr1.max);
}
else
{
/* The result of a TRUTH_*_EXPR is always true or false. */
- set_value_range_to_truthvalue (vr, TREE_TYPE (expr));
+ set_value_range_to_truthvalue (vr, expr_type);
return;
}
}
@@ -1852,7 +2083,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
|| !vrp_expr_computes_nonnegative (op1, &sop)
|| (operand_less_p
(build_int_cst (TREE_TYPE (vr1.max),
- TYPE_PRECISION (TREE_TYPE (expr)) - 1),
+ TYPE_PRECISION (expr_type) - 1),
vr1.max) != 0))
{
set_value_range_to_varying (vr);
@@ -1981,7 +2212,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
&& !TREE_OVERFLOW (vr0.max)
&& tree_int_cst_sgn (vr0.max) >= 0)
{
- min = build_int_cst (TREE_TYPE (expr), 0);
+ min = build_int_cst (expr_type, 0);
max = vr0.max;
}
else if (vr1.type == VR_RANGE
@@ -1991,7 +2222,7 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
&& tree_int_cst_sgn (vr1.max) >= 0)
{
type = VR_RANGE;
- min = build_int_cst (TREE_TYPE (expr), 0);
+ min = build_int_cst (expr_type, 0);
max = vr1.max;
}
else
@@ -2025,10 +2256,8 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
We learn nothing when we have INF and INF(OVF) on both sides.
Note that we do accept [-INF, -INF] and [+INF, +INF] without
overflow. */
- if ((min == TYPE_MIN_VALUE (TREE_TYPE (min))
- || is_overflow_infinity (min))
- && (max == TYPE_MAX_VALUE (TREE_TYPE (max))
- || is_overflow_infinity (max)))
+ if ((vrp_val_is_min (min) || is_overflow_infinity (min))
+ && (vrp_val_is_max (max) || is_overflow_infinity (max)))
{
set_value_range_to_varying (vr);
return;
@@ -2051,10 +2280,10 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr)
the range of its operand and the expression code. */
static void
-extract_range_from_unary_expr (value_range_t *vr, tree expr)
+extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
+ tree type, tree op0)
{
- enum tree_code code = TREE_CODE (expr);
- tree min, max, op0;
+ tree min, max;
int cmp;
value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
@@ -2072,11 +2301,10 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
/* Get value ranges for the operand. For constant operands, create
a new value range with the operand to simplify processing. */
- op0 = TREE_OPERAND (expr, 0);
if (TREE_CODE (op0) == SSA_NAME)
vr0 = *(get_value_range (op0));
else if (is_gimple_min_invariant (op0))
- set_value_range_to_value (&vr0, op0);
+ set_value_range_to_value (&vr0, op0, NULL);
else
set_value_range_to_varying (&vr0);
@@ -2100,17 +2328,17 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
/* If the expression involves pointers, we are only interested in
determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). */
- if (POINTER_TYPE_P (TREE_TYPE (expr)) || POINTER_TYPE_P (TREE_TYPE (op0)))
+ if (POINTER_TYPE_P (type) || POINTER_TYPE_P (TREE_TYPE (op0)))
{
bool sop;
sop = false;
if (range_is_nonnull (&vr0)
- || (tree_expr_nonzero_warnv_p (expr, &sop)
+ || (tree_unary_nonzero_warnv_p (code, type, op0, &sop)
&& !sop))
- set_value_range_to_nonnull (vr, TREE_TYPE (expr));
+ set_value_range_to_nonnull (vr, type);
else if (range_is_null (&vr0))
- set_value_range_to_null (vr, TREE_TYPE (expr));
+ set_value_range_to_null (vr, type);
else
set_value_range_to_varying (vr);
@@ -2118,69 +2346,63 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
}
/* Handle unary expressions on integer ranges. */
- if (code == NOP_EXPR || code == CONVERT_EXPR)
+ if ((code == NOP_EXPR
+ || code == CONVERT_EXPR)
+ && INTEGRAL_TYPE_P (type)
+ && INTEGRAL_TYPE_P (TREE_TYPE (op0)))
{
tree inner_type = TREE_TYPE (op0);
- tree outer_type = TREE_TYPE (expr);
-
- /* If VR0 represents a simple range, then try to convert
- the min and max values for the range to the same type
- as OUTER_TYPE. If the results compare equal to VR0's
- min and max values and the new min is still less than
- or equal to the new max, then we can safely use the newly
- computed range for EXPR. This allows us to compute
- accurate ranges through many casts. */
- if ((vr0.type == VR_RANGE
- && !overflow_infinity_range_p (&vr0))
- || (vr0.type == VR_VARYING
- && TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type)))
+ tree outer_type = type;
+
+ /* Always use base-types here. This is important for the
+ correct signedness. */
+ if (TREE_TYPE (inner_type))
+ inner_type = TREE_TYPE (inner_type);
+ if (TREE_TYPE (outer_type))
+ outer_type = TREE_TYPE (outer_type);
+
+ /* If VR0 is varying and we increase the type precision, assume
+ a full range for the following transformation. */
+ if (vr0.type == VR_VARYING
+ && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
{
- tree new_min, new_max, orig_min, orig_max;
-
- /* Convert the input operand min/max to OUTER_TYPE. If
- the input has no range information, then use the min/max
- for the input's type. */
- if (vr0.type == VR_RANGE)
- {
- orig_min = vr0.min;
- orig_max = vr0.max;
- }
- else
- {
- orig_min = TYPE_MIN_VALUE (inner_type);
- orig_max = TYPE_MAX_VALUE (inner_type);
- }
-
- new_min = fold_convert (outer_type, orig_min);
- new_max = fold_convert (outer_type, orig_max);
-
- /* Verify the new min/max values are gimple values and
- that they compare equal to the original input's
- min/max values. */
- if (is_gimple_val (new_min)
- && is_gimple_val (new_max)
- && tree_int_cst_equal (new_min, orig_min)
- && tree_int_cst_equal (new_max, orig_max)
- && (cmp = compare_values (new_min, new_max)) <= 0
- && cmp >= -1)
- {
- set_value_range (vr, VR_RANGE, new_min, new_max, vr->equiv);
- return;
- }
+ vr0.type = VR_RANGE;
+ vr0.min = TYPE_MIN_VALUE (inner_type);
+ vr0.max = TYPE_MAX_VALUE (inner_type);
}
- /* When converting types of different sizes, set the result to
- VARYING. Things like sign extensions and precision loss may
- change the range. For instance, if x_3 is of type 'long long
- int' and 'y_5 = (unsigned short) x_3', if x_3 is ~[0, 0], it
- is impossible to know at compile time whether y_5 will be
- ~[0, 0]. */
- if (TYPE_SIZE (inner_type) != TYPE_SIZE (outer_type)
- || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
+ /* If VR0 is a constant range or anti-range and the conversion is
+ not truncating we can convert the min and max values and
+ canonicalize the resulting range. Otherwise we can do the
+ conversion if the size of the range is less than what the
+ precision of the target type can represent and the range is
+ not an anti-range. */
+ if ((vr0.type == VR_RANGE
+ || vr0.type == VR_ANTI_RANGE)
+ && TREE_CODE (vr0.min) == INTEGER_CST
+ && TREE_CODE (vr0.max) == INTEGER_CST
+ && !is_overflow_infinity (vr0.min)
+ && !is_overflow_infinity (vr0.max)
+ && (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type)
+ || (vr0.type == VR_RANGE
+ && integer_zerop (int_const_binop (RSHIFT_EXPR,
+ int_const_binop (MINUS_EXPR, vr0.max, vr0.min, 0),
+ size_int (TYPE_PRECISION (outer_type)), 0)))))
{
- set_value_range_to_varying (vr);
+ tree new_min, new_max;
+ new_min = force_fit_type_double (outer_type,
+ TREE_INT_CST_LOW (vr0.min),
+ TREE_INT_CST_HIGH (vr0.min), 0, 0);
+ new_max = force_fit_type_double (outer_type,
+ TREE_INT_CST_LOW (vr0.max),
+ TREE_INT_CST_HIGH (vr0.max), 0, 0);
+ set_and_canonicalize_value_range (vr, vr0.type,
+ new_min, new_max, NULL);
return;
}
+
+ set_value_range_to_varying (vr);
+ return;
}
/* Conversion of a VR_VARYING value to a wider type can result
@@ -2196,22 +2418,22 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
/* Apply the operation to each end of the range and see what we end
up with. */
if (code == NEGATE_EXPR
- && !TYPE_UNSIGNED (TREE_TYPE (expr)))
+ && !TYPE_UNSIGNED (type))
{
/* NEGATE_EXPR flips the range around. We need to treat
TYPE_MIN_VALUE specially. */
if (is_positive_overflow_infinity (vr0.max))
- min = negative_overflow_infinity (TREE_TYPE (expr));
+ min = negative_overflow_infinity (type);
else if (is_negative_overflow_infinity (vr0.max))
- min = positive_overflow_infinity (TREE_TYPE (expr));
- else if (vr0.max != TYPE_MIN_VALUE (TREE_TYPE (expr)))
- min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
- else if (needs_overflow_infinity (TREE_TYPE (expr)))
+ min = positive_overflow_infinity (type);
+ else if (!vrp_val_is_min (vr0.max))
+ min = fold_unary_to_constant (code, type, vr0.max);
+ else if (needs_overflow_infinity (type))
{
- if (supports_overflow_infinity (TREE_TYPE (expr))
+ if (supports_overflow_infinity (type)
&& !is_overflow_infinity (vr0.min)
- && vr0.min != TYPE_MIN_VALUE (TREE_TYPE (expr)))
- min = positive_overflow_infinity (TREE_TYPE (expr));
+ && !vrp_val_is_min (vr0.min))
+ min = positive_overflow_infinity (type);
else
{
set_value_range_to_varying (vr);
@@ -2219,18 +2441,18 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
}
}
else
- min = TYPE_MIN_VALUE (TREE_TYPE (expr));
+ min = TYPE_MIN_VALUE (type);
if (is_positive_overflow_infinity (vr0.min))
- max = negative_overflow_infinity (TREE_TYPE (expr));
+ max = negative_overflow_infinity (type);
else if (is_negative_overflow_infinity (vr0.min))
- max = positive_overflow_infinity (TREE_TYPE (expr));
- else if (vr0.min != TYPE_MIN_VALUE (TREE_TYPE (expr)))
- max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
- else if (needs_overflow_infinity (TREE_TYPE (expr)))
+ max = positive_overflow_infinity (type);
+ else if (!vrp_val_is_min (vr0.min))
+ max = fold_unary_to_constant (code, type, vr0.min);
+ else if (needs_overflow_infinity (type))
{
- if (supports_overflow_infinity (TREE_TYPE (expr)))
- max = positive_overflow_infinity (TREE_TYPE (expr));
+ if (supports_overflow_infinity (type))
+ max = positive_overflow_infinity (type);
else
{
set_value_range_to_varying (vr);
@@ -2238,35 +2460,35 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
}
}
else
- max = TYPE_MIN_VALUE (TREE_TYPE (expr));
+ max = TYPE_MIN_VALUE (type);
}
else if (code == NEGATE_EXPR
- && TYPE_UNSIGNED (TREE_TYPE (expr)))
+ && TYPE_UNSIGNED (type))
{
if (!range_includes_zero_p (&vr0))
{
- max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
- min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
+ max = fold_unary_to_constant (code, type, vr0.min);
+ min = fold_unary_to_constant (code, type, vr0.max);
}
else
{
if (range_is_null (&vr0))
- set_value_range_to_null (vr, TREE_TYPE (expr));
+ set_value_range_to_null (vr, type);
else
set_value_range_to_varying (vr);
return;
}
}
else if (code == ABS_EXPR
- && !TYPE_UNSIGNED (TREE_TYPE (expr)))
+ && !TYPE_UNSIGNED (type))
{
/* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
useful range. */
- if (!TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (expr))
+ if (!TYPE_OVERFLOW_UNDEFINED (type)
&& ((vr0.type == VR_RANGE
- && vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr)))
+ && vrp_val_is_min (vr0.min))
|| (vr0.type == VR_ANTI_RANGE
- && vr0.min != TYPE_MIN_VALUE (TREE_TYPE (expr))
+ && !vrp_val_is_min (vr0.min)
&& !range_includes_zero_p (&vr0))))
{
set_value_range_to_varying (vr);
@@ -2276,13 +2498,13 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
/* ABS_EXPR may flip the range around, if the original range
included negative values. */
if (is_overflow_infinity (vr0.min))
- min = positive_overflow_infinity (TREE_TYPE (expr));
- else if (vr0.min != TYPE_MIN_VALUE (TREE_TYPE (expr)))
- min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
- else if (!needs_overflow_infinity (TREE_TYPE (expr)))
- min = TYPE_MAX_VALUE (TREE_TYPE (expr));
- else if (supports_overflow_infinity (TREE_TYPE (expr)))
- min = positive_overflow_infinity (TREE_TYPE (expr));
+ min = positive_overflow_infinity (type);
+ else if (!vrp_val_is_min (vr0.min))
+ min = fold_unary_to_constant (code, type, vr0.min);
+ else if (!needs_overflow_infinity (type))
+ min = TYPE_MAX_VALUE (type);
+ else if (supports_overflow_infinity (type))
+ min = positive_overflow_infinity (type);
else
{
set_value_range_to_varying (vr);
@@ -2290,13 +2512,13 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
}
if (is_overflow_infinity (vr0.max))
- max = positive_overflow_infinity (TREE_TYPE (expr));
- else if (vr0.max != TYPE_MIN_VALUE (TREE_TYPE (expr)))
- max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
- else if (!needs_overflow_infinity (TREE_TYPE (expr)))
- max = TYPE_MAX_VALUE (TREE_TYPE (expr));
- else if (supports_overflow_infinity (TREE_TYPE (expr)))
- max = positive_overflow_infinity (TREE_TYPE (expr));
+ max = positive_overflow_infinity (type);
+ else if (!vrp_val_is_min (vr0.max))
+ max = fold_unary_to_constant (code, type, vr0.max);
+ else if (!needs_overflow_infinity (type))
+ max = TYPE_MAX_VALUE (type);
+ else if (supports_overflow_infinity (type))
+ max = positive_overflow_infinity (type);
else
{
set_value_range_to_varying (vr);
@@ -2319,9 +2541,9 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
or ~[-INF + 1, min (abs(MIN), abs(MAX))] when
flag_wrapv is set and the original anti-range doesn't include
TYPE_MIN_VALUE, remember -TYPE_MIN_VALUE = TYPE_MIN_VALUE. */
- if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)))
+ if (TYPE_OVERFLOW_WRAPS (type))
{
- tree type_min_value = TYPE_MIN_VALUE (TREE_TYPE (expr));
+ tree type_min_value = TYPE_MIN_VALUE (type);
min = (vr0.min != type_min_value
? int_const_binop (PLUS_EXPR, type_min_value,
@@ -2331,9 +2553,9 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
else
{
if (overflow_infinity_range_p (&vr0))
- min = negative_overflow_infinity (TREE_TYPE (expr));
+ min = negative_overflow_infinity (type);
else
- min = TYPE_MIN_VALUE (TREE_TYPE (expr));
+ min = TYPE_MIN_VALUE (type);
}
}
else
@@ -2342,11 +2564,11 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
flag_wrapv since TYPE_MIN_VALUE is in the original
anti-range. */
vr0.type = VR_RANGE;
- min = build_int_cst (TREE_TYPE (expr), 0);
- if (needs_overflow_infinity (TREE_TYPE (expr)))
+ min = build_int_cst (type, 0);
+ if (needs_overflow_infinity (type))
{
- if (supports_overflow_infinity (TREE_TYPE (expr)))
- max = positive_overflow_infinity (TREE_TYPE (expr));
+ if (supports_overflow_infinity (type))
+ max = positive_overflow_infinity (type);
else
{
set_value_range_to_varying (vr);
@@ -2354,7 +2576,7 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
}
}
else
- max = TYPE_MAX_VALUE (TREE_TYPE (expr));
+ max = TYPE_MAX_VALUE (type);
}
}
@@ -2364,7 +2586,7 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
{
if (cmp == 1)
max = min;
- min = build_int_cst (TREE_TYPE (expr), 0);
+ min = build_int_cst (type, 0);
}
else
{
@@ -2380,10 +2602,10 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
else
{
/* Otherwise, operate on each end of the range. */
- min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
- max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
+ min = fold_unary_to_constant (code, type, vr0.min);
+ max = fold_unary_to_constant (code, type, vr0.max);
- if (needs_overflow_infinity (TREE_TYPE (expr)))
+ if (needs_overflow_infinity (type))
{
gcc_assert (code != NEGATE_EXPR && code != ABS_EXPR);
@@ -2402,7 +2624,7 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
min = vr0.min;
else if (TREE_OVERFLOW (min))
{
- if (supports_overflow_infinity (TREE_TYPE (expr)))
+ if (supports_overflow_infinity (type))
min = (tree_int_cst_sgn (min) >= 0
? positive_overflow_infinity (TREE_TYPE (min))
: negative_overflow_infinity (TREE_TYPE (min)));
@@ -2417,7 +2639,7 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
max = vr0.max;
else if (TREE_OVERFLOW (max))
{
- if (supports_overflow_infinity (TREE_TYPE (expr)))
+ if (supports_overflow_infinity (type))
max = (tree_int_cst_sgn (max) >= 0
? positive_overflow_infinity (TREE_TYPE (max))
: negative_overflow_infinity (TREE_TYPE (max)));
@@ -2459,7 +2681,7 @@ extract_range_from_cond_expr (value_range_t *vr, tree expr)
if (TREE_CODE (op0) == SSA_NAME)
vr0 = *(get_value_range (op0));
else if (is_gimple_min_invariant (op0))
- set_value_range_to_value (&vr0, op0);
+ set_value_range_to_value (&vr0, op0, NULL);
else
set_value_range_to_varying (&vr0);
@@ -2467,7 +2689,7 @@ extract_range_from_cond_expr (value_range_t *vr, tree expr)
if (TREE_CODE (op1) == SSA_NAME)
vr1 = *(get_value_range (op1));
else if (is_gimple_min_invariant (op1))
- set_value_range_to_value (&vr1, op1);
+ set_value_range_to_value (&vr1, op1, NULL);
else
set_value_range_to_varying (&vr1);
@@ -2481,10 +2703,14 @@ extract_range_from_cond_expr (value_range_t *vr, tree expr)
on the range of its operand and the expression code. */
static void
-extract_range_from_comparison (value_range_t *vr, tree expr)
+extract_range_from_comparison (value_range_t *vr, enum tree_code code,
+ tree type, tree op0, tree op1)
{
bool sop = false;
- tree val = vrp_evaluate_conditional_warnv (expr, false, &sop);
+ tree val = vrp_evaluate_conditional_warnv_with_ops (code,
+ op0,
+ op1,
+ false, &sop);
/* A disadvantage of using a special infinity as an overflow
representation is that we lose the ability to record overflow
@@ -2496,12 +2722,15 @@ extract_range_from_comparison (value_range_t *vr, tree expr)
/* Since this expression was found on the RHS of an assignment,
its type may be different from _Bool. Convert VAL to EXPR's
type. */
- val = fold_convert (TREE_TYPE (expr), val);
- set_value_range (vr, VR_RANGE, val, val, vr->equiv);
+ val = fold_convert (type, val);
+ if (is_gimple_min_invariant (val))
+ set_value_range_to_value (vr, val, vr->equiv);
+ else
+ set_value_range (vr, VR_RANGE, val, val, vr->equiv);
}
else
/* The result of a comparison is always true or false. */
- set_value_range_to_truthvalue (vr, TREE_TYPE (expr));
+ set_value_range_to_truthvalue (vr, type);
}
@@ -2518,20 +2747,23 @@ extract_range_from_expr (value_range_t *vr, tree expr)
else if (code == SSA_NAME)
extract_range_from_ssa_name (vr, expr);
else if (TREE_CODE_CLASS (code) == tcc_binary
- || code == TRUTH_ANDIF_EXPR
- || code == TRUTH_ORIF_EXPR
|| code == TRUTH_AND_EXPR
|| code == TRUTH_OR_EXPR
|| code == TRUTH_XOR_EXPR)
- extract_range_from_binary_expr (vr, expr);
+ extract_range_from_binary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr),
+ TREE_OPERAND (expr, 0),
+ TREE_OPERAND (expr, 1));
else if (TREE_CODE_CLASS (code) == tcc_unary)
- extract_range_from_unary_expr (vr, expr);
+ extract_range_from_unary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr),
+ TREE_OPERAND (expr, 0));
else if (code == COND_EXPR)
extract_range_from_cond_expr (vr, expr);
else if (TREE_CODE_CLASS (code) == tcc_comparison)
- extract_range_from_comparison (vr, expr);
+ extract_range_from_comparison (vr, TREE_CODE (expr), TREE_TYPE (expr),
+ TREE_OPERAND (expr, 0),
+ TREE_OPERAND (expr, 1));
else if (is_gimple_min_invariant (expr))
- set_value_range_to_value (vr, expr);
+ set_value_range_to_value (vr, expr, NULL);
else
set_value_range_to_varying (vr);
@@ -2569,7 +2801,22 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
if (vr->type == VR_ANTI_RANGE)
return;
+ /* Ensure that there are not values in the scev cache based on assumptions
+ on ranges of ssa names that were changed
+ (in set_value_range/set_value_range_to_varying). Preserve cached numbers
+ of iterations, that were computed before the start of VRP (we do not
+ recompute these each time to save the compile time). */
+ scev_reset_except_niters ();
+
chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
+
+ /* Like in PR19590, scev can return a constant function. */
+ if (is_gimple_min_invariant (chrec))
+ {
+ set_value_range_to_value (vr, chrec, vr->equiv);
+ return;
+ }
+
if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
return;
@@ -2651,6 +2898,13 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
if (compare_values (min, max) == 1)
return;
}
+
+ /* According to the loop information, the variable does not
+ overflow. If we think it does, probably because of an
+ overflow due to arithmetic on a different INF value,
+ reset now. */
+ if (is_negative_overflow_infinity (min))
+ min = tmin;
}
else
{
@@ -2663,12 +2917,60 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
if (compare_values (min, max) == 1)
return;
}
+
+ if (is_positive_overflow_infinity (max))
+ max = tmax;
}
set_value_range (vr, VR_RANGE, min, max, vr->equiv);
}
}
+/* Return true if VAR may overflow at STMT. This checks any available
+ loop information to see if we can determine that VAR does not
+ overflow. */
+
+static bool
+vrp_var_may_overflow (tree var, tree stmt)
+{
+ struct loop *l;
+ tree chrec, init, step;
+
+ if (current_loops == NULL)
+ return true;
+
+ l = loop_containing_stmt (stmt);
+ if (l == NULL)
+ return true;
+
+ chrec = instantiate_parameters (l, analyze_scalar_evolution (l, var));
+ if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
+ return true;
+
+ init = initial_condition_in_loop_num (chrec, l->num);
+ step = evolution_part_in_loop_num (chrec, l->num);
+
+ if (step == NULL_TREE
+ || !is_gimple_min_invariant (step)
+ || !valid_value_p (init))
+ return true;
+
+ /* If we get here, we know something useful about VAR based on the
+ loop information. If it wraps, it may overflow. */
+
+ if (scev_probably_wraps_p (init, step, stmt, get_chrec_loop (chrec),
+ true))
+ return true;
+
+ if (dump_file && (dump_flags & TDF_DETAILS) != 0)
+ {
+ print_generic_expr (dump_file, var, 0);
+ fprintf (dump_file, ": loop information indicates does not overflow\n");
+ }
+
+ return false;
+}
+
/* Given two numeric value ranges VR0, VR1 and a comparison code COMP:
@@ -2987,24 +3289,22 @@ dump_value_range (FILE *file, value_range_t *vr)
fprintf (file, "%s[", (vr->type == VR_ANTI_RANGE) ? "~" : "");
- if (INTEGRAL_TYPE_P (type)
- && !TYPE_UNSIGNED (type)
- && vr->min == TYPE_MIN_VALUE (type))
- fprintf (file, "-INF");
- else if (needs_overflow_infinity (type)
- && is_negative_overflow_infinity (vr->min))
+ if (is_negative_overflow_infinity (vr->min))
fprintf (file, "-INF(OVF)");
+ else if (INTEGRAL_TYPE_P (type)
+ && !TYPE_UNSIGNED (type)
+ && vrp_val_is_min (vr->min))
+ fprintf (file, "-INF");
else
print_generic_expr (file, vr->min, 0);
fprintf (file, ", ");
- if (INTEGRAL_TYPE_P (type)
- && vr->max == TYPE_MAX_VALUE (type))
- fprintf (file, "+INF");
- else if (needs_overflow_infinity (type)
- && is_positive_overflow_infinity (vr->max))
+ if (is_positive_overflow_infinity (vr->max))
fprintf (file, "+INF(OVF)");
+ else if (INTEGRAL_TYPE_P (type)
+ && vrp_val_is_max (vr->max))
+ fprintf (file, "+INF");
else
print_generic_expr (file, vr->max, 0);
@@ -3124,7 +3424,7 @@ build_assert_expr_for (tree cond, tree v)
point values. */
static inline bool
-fp_predicate (tree expr)
+fp_predicate (const_tree expr)
{
return (COMPARISON_CLASS_P (expr)
&& FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0))));
@@ -3252,9 +3552,9 @@ debug_all_asserts (void)
/* If NAME doesn't have an ASSERT_EXPR registered for asserting
- 'NAME COMP_CODE VAL' at a location that dominates block BB or
+ 'EXPR COMP_CODE VAL' at a location that dominates block BB or
E->DEST, then register this location as a possible insertion point
- for ASSERT_EXPR .
+ for ASSERT_EXPR .
BB, E and SI provide the exact insertion point for the new
ASSERT_EXPR. If BB is NULL, then the ASSERT_EXPR is to be inserted
@@ -3263,7 +3563,7 @@ debug_all_asserts (void)
must not be NULL. */
static void
-register_new_assert_for (tree name,
+register_new_assert_for (tree name, tree expr,
enum tree_code comp_code,
tree val,
basic_block bb,
@@ -3317,7 +3617,9 @@ register_new_assert_for (tree name,
{
if (loc->comp_code == comp_code
&& (loc->val == val
- || operand_equal_p (loc->val, val, 0)))
+ || operand_equal_p (loc->val, val, 0))
+ && (loc->expr == expr
+ || operand_equal_p (loc->expr, expr, 0)))
{
/* If the assertion NAME COMP_CODE VAL has already been
registered at a basic block that dominates DEST_BB, then
@@ -3364,6 +3666,7 @@ register_new_assert_for (tree name,
n->si = si;
n->comp_code = comp_code;
n->val = val;
+ n->expr = expr;
n->next = NULL;
if (last_loc)
@@ -3374,82 +3677,203 @@ register_new_assert_for (tree name,
bitmap_set_bit (need_assert_for, SSA_NAME_VERSION (name));
}
-/* COND is a predicate which uses NAME. Extract a suitable test code
- and value and store them into *CODE_P and *VAL_P so the predicate
- is normalized to NAME *CODE_P *VAL_P.
+/* (COND_OP0 COND_CODE COND_OP1) is a predicate which uses NAME.
+ Extract a suitable test code and value and store them into *CODE_P and
+ *VAL_P so the predicate is normalized to NAME *CODE_P *VAL_P.
If no extraction was possible, return FALSE, otherwise return TRUE.
If INVERT is true, then we invert the result stored into *CODE_P. */
static bool
-extract_code_and_val_from_cond (tree name, tree cond, bool invert,
- enum tree_code *code_p, tree *val_p)
+extract_code_and_val_from_cond_with_ops (tree name, enum tree_code cond_code,
+ tree cond_op0, tree cond_op1,
+ bool invert, enum tree_code *code_p,
+ tree *val_p)
{
enum tree_code comp_code;
tree val;
- /* Predicates may be a single SSA name or NAME OP VAL. */
- if (cond == name)
+ /* Otherwise, we have a comparison of the form NAME COMP VAL
+ or VAL COMP NAME. */
+ if (name == cond_op1)
{
- /* If the predicate is a name, it must be NAME, in which
- case we create the predicate NAME == true or
- NAME == false accordingly. */
- comp_code = EQ_EXPR;
- val = invert ? boolean_false_node : boolean_true_node;
+ /* If the predicate is of the form VAL COMP NAME, flip
+ COMP around because we need to register NAME as the
+ first operand in the predicate. */
+ comp_code = swap_tree_comparison (cond_code);
+ val = cond_op0;
}
else
{
- /* Otherwise, we have a comparison of the form NAME COMP VAL
- or VAL COMP NAME. */
- if (name == TREE_OPERAND (cond, 1))
- {
- /* If the predicate is of the form VAL COMP NAME, flip
- COMP around because we need to register NAME as the
- first operand in the predicate. */
- comp_code = swap_tree_comparison (TREE_CODE (cond));
- val = TREE_OPERAND (cond, 0);
+ /* The comparison is of the form NAME COMP VAL, so the
+ comparison code remains unchanged. */
+ comp_code = cond_code;
+ val = cond_op1;
+ }
+
+ /* Invert the comparison code as necessary. */
+ if (invert)
+ comp_code = invert_tree_comparison (comp_code, 0);
+
+ /* VRP does not handle float types. */
+ if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)))
+ return false;
+
+ /* Do not register always-false predicates.
+ FIXME: this works around a limitation in fold() when dealing with
+ enumerations. Given 'enum { N1, N2 } x;', fold will not
+ fold 'if (x > N2)' to 'if (0)'. */
+ if ((comp_code == GT_EXPR || comp_code == LT_EXPR)
+ && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ {
+ tree min = TYPE_MIN_VALUE (TREE_TYPE (val));
+ tree max = TYPE_MAX_VALUE (TREE_TYPE (val));
+
+ if (comp_code == GT_EXPR
+ && (!max
+ || compare_values (val, max) == 0))
+ return false;
+
+ if (comp_code == LT_EXPR
+ && (!min
+ || compare_values (val, min) == 0))
+ return false;
+ }
+ *code_p = comp_code;
+ *val_p = val;
+ return true;
+}
+
+/* Try to register an edge assertion for SSA name NAME on edge E for
+ the condition COND contributing to the conditional jump pointed to by BSI.
+ Invert the condition COND if INVERT is true.
+ Return true if an assertion for NAME could be registered. */
+
+static bool
+register_edge_assert_for_2 (tree name, edge e, block_stmt_iterator bsi,
+ enum tree_code cond_code,
+ tree cond_op0, tree cond_op1, bool invert)
+{
+ tree val;
+ enum tree_code comp_code;
+ bool retval = false;
+
+ if (!extract_code_and_val_from_cond_with_ops (name, cond_code,
+ cond_op0,
+ cond_op1,
+ invert, &comp_code, &val))
+ return false;
+
+ /* Only register an ASSERT_EXPR if NAME was found in the sub-graph
+ reachable from E. */
+ if (TEST_BIT (found_in_subgraph, SSA_NAME_VERSION (name))
+ && !has_single_use (name))
+ {
+ register_new_assert_for (name, name, comp_code, val, NULL, e, bsi);
+ retval = true;
+ }
+
+ /* In the case of NAME <= CST and NAME being defined as
+ NAME = (unsigned) NAME2 + CST2 we can assert NAME2 >= -CST2
+ and NAME2 <= CST - CST2. We can do the same for NAME > CST.
+ This catches range and anti-range tests. */
+ if ((comp_code == LE_EXPR
+ || comp_code == GT_EXPR)
+ && TREE_CODE (val) == INTEGER_CST
+ && TYPE_UNSIGNED (TREE_TYPE (val)))
+ {
+ tree def_stmt = SSA_NAME_DEF_STMT (name);
+ tree cst2 = NULL_TREE, name2 = NULL_TREE, name3 = NULL_TREE;
+
+ /* Extract CST2 from the (optional) addition. */
+ if (TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
+ && TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1)) == PLUS_EXPR)
+ {
+ name2 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 0);
+ cst2 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 1);
+ if (TREE_CODE (name2) == SSA_NAME
+ && TREE_CODE (cst2) == INTEGER_CST)
+ def_stmt = SSA_NAME_DEF_STMT (name2);
}
- else
+
+ /* Extract NAME2 from the (optional) sign-changing cast. */
+ if (TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
+ && (TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1)) == NOP_EXPR
+ || TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1)) == CONVERT_EXPR))
{
- /* The comparison is of the form NAME COMP VAL, so the
- comparison code remains unchanged. */
- comp_code = TREE_CODE (cond);
- val = TREE_OPERAND (cond, 1);
+ tree rhs = GIMPLE_STMT_OPERAND (def_stmt, 1);
+ if ((TREE_CODE (rhs) == NOP_EXPR
+ || TREE_CODE (rhs) == CONVERT_EXPR)
+ && ! TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (rhs, 0)))
+ && (TYPE_PRECISION (TREE_TYPE (rhs))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (rhs, 0)))))
+ name3 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 0);
}
- /* Invert the comparison code as necessary. */
- if (invert)
- comp_code = invert_tree_comparison (comp_code, 0);
+ /* If name3 is used later, create an ASSERT_EXPR for it. */
+ if (name3 != NULL_TREE
+ && TREE_CODE (name3) == SSA_NAME
+ && (cst2 == NULL_TREE
+ || TREE_CODE (cst2) == INTEGER_CST)
+ && INTEGRAL_TYPE_P (TREE_TYPE (name3))
+ && TEST_BIT (found_in_subgraph, SSA_NAME_VERSION (name3))
+ && !has_single_use (name3))
+ {
+ tree tmp;
- /* VRP does not handle float types. */
- if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)))
- return false;
+ /* Build an expression for the range test. */
+ tmp = build1 (NOP_EXPR, TREE_TYPE (name), name3);
+ if (cst2 != NULL_TREE)
+ tmp = build2 (PLUS_EXPR, TREE_TYPE (name), tmp, cst2);
- /* Do not register always-false predicates.
- FIXME: this works around a limitation in fold() when dealing with
- enumerations. Given 'enum { N1, N2 } x;', fold will not
- fold 'if (x > N2)' to 'if (0)'. */
- if ((comp_code == GT_EXPR || comp_code == LT_EXPR)
- && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ if (dump_file)
+ {
+ fprintf (dump_file, "Adding assert for ");
+ print_generic_expr (dump_file, name3, 0);
+ fprintf (dump_file, " from ");
+ print_generic_expr (dump_file, tmp, 0);
+ fprintf (dump_file, "\n");
+ }
+
+ register_new_assert_for (name3, tmp, comp_code, val, NULL, e, bsi);
+
+ retval = true;
+ }
+
+ /* If name2 is used later, create an ASSERT_EXPR for it. */
+ if (name2 != NULL_TREE
+ && TREE_CODE (name2) == SSA_NAME
+ && TREE_CODE (cst2) == INTEGER_CST
+ && INTEGRAL_TYPE_P (TREE_TYPE (name2))
+ && TEST_BIT (found_in_subgraph, SSA_NAME_VERSION (name2))
+ && !has_single_use (name2))
{
- tree min = TYPE_MIN_VALUE (TREE_TYPE (val));
- tree max = TYPE_MAX_VALUE (TREE_TYPE (val));
-
- if (comp_code == GT_EXPR
- && (!max
- || compare_values (val, max) == 0))
- return false;
-
- if (comp_code == LT_EXPR
- && (!min
- || compare_values (val, min) == 0))
- return false;
+ tree tmp;
+
+ /* Build an expression for the range test. */
+ tmp = name2;
+ if (TREE_TYPE (name) != TREE_TYPE (name2))
+ tmp = build1 (NOP_EXPR, TREE_TYPE (name), tmp);
+ if (cst2 != NULL_TREE)
+ tmp = build2 (PLUS_EXPR, TREE_TYPE (name), tmp, cst2);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "Adding assert for ");
+ print_generic_expr (dump_file, name2, 0);
+ fprintf (dump_file, " from ");
+ print_generic_expr (dump_file, tmp, 0);
+ fprintf (dump_file, "\n");
+ }
+
+ register_new_assert_for (name2, tmp, comp_code, val, NULL, e, bsi);
+
+ retval = true;
}
}
- *code_p = comp_code;
- *val_p = val;
- return true;
+
+ return retval;
}
/* OP is an operand of a truth value expression which is known to have
@@ -3465,6 +3889,7 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
{
bool retval = false;
tree op_def, rhs, val;
+ enum tree_code rhs_code;
/* We only care about SSA_NAMEs. */
if (TREE_CODE (op) != SSA_NAME)
@@ -3479,7 +3904,7 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
if (!has_single_use (op))
{
val = build_int_cst (TREE_TYPE (op), 0);
- register_new_assert_for (op, code, val, NULL, e, bsi);
+ register_new_assert_for (op, op, code, val, NULL, e, bsi);
retval = true;
}
@@ -3491,6 +3916,7 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
return retval;
rhs = GIMPLE_STMT_OPERAND (op_def, 1);
+ rhs_code = TREE_CODE (rhs);
if (COMPARISON_CLASS_P (rhs))
{
@@ -3498,26 +3924,12 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
tree op0 = TREE_OPERAND (rhs, 0);
tree op1 = TREE_OPERAND (rhs, 1);
- /* Conditionally register an assert for each SSA_NAME in the
- comparison. */
- if (TREE_CODE (op0) == SSA_NAME
- && !has_single_use (op0)
- && extract_code_and_val_from_cond (op0, rhs,
- invert, &code, &val))
- {
- register_new_assert_for (op0, code, val, NULL, e, bsi);
- retval = true;
- }
-
- /* Similarly for the second operand of the comparison. */
- if (TREE_CODE (op1) == SSA_NAME
- && !has_single_use (op1)
- && extract_code_and_val_from_cond (op1, rhs,
- invert, &code, &val))
- {
- register_new_assert_for (op1, code, val, NULL, e, bsi);
- retval = true;
- }
+ if (TREE_CODE (op0) == SSA_NAME)
+ retval |= register_edge_assert_for_2 (op0, e, bsi, rhs_code, op0, op1,
+ invert);
+ if (TREE_CODE (op1) == SSA_NAME)
+ retval |= register_edge_assert_for_2 (op1, e, bsi, rhs_code, op0, op1,
+ invert);
}
else if ((code == NE_EXPR
&& (TREE_CODE (rhs) == TRUTH_AND_EXPR
@@ -3561,7 +3973,9 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
Return true if an assertion for NAME could be registered. */
static bool
-register_edge_assert_for (tree name, edge e, block_stmt_iterator si, tree cond)
+register_edge_assert_for (tree name, edge e, block_stmt_iterator si,
+ enum tree_code cond_code, tree cond_op0,
+ tree cond_op1)
{
tree val;
enum tree_code comp_code;
@@ -3573,17 +3987,16 @@ register_edge_assert_for (tree name, edge e, block_stmt_iterator si, tree cond)
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
return false;
- if (!extract_code_and_val_from_cond (name, cond, is_else_edge,
- &comp_code, &val))
+ if (!extract_code_and_val_from_cond_with_ops (name, cond_code,
+ cond_op0, cond_op1,
+ is_else_edge,
+ &comp_code, &val))
return false;
- /* Only register an ASSERT_EXPR if NAME was found in the sub-graph
- reachable from E. */
- if (TEST_BIT (found_in_subgraph, SSA_NAME_VERSION (name)))
- {
- register_new_assert_for (name, comp_code, val, NULL, e, si);
- retval = true;
- }
+ /* Register ASSERT_EXPRs for name. */
+ retval |= register_edge_assert_for_2 (name, e, si, cond_code, cond_op0,
+ cond_op1, is_else_edge);
+
/* If COND is effectively an equality test of an SSA_NAME against
the value zero or one, then we may be able to assert values
@@ -3618,7 +4031,11 @@ register_edge_assert_for (tree name, edge e, block_stmt_iterator si, tree cond)
if (TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT
&& (TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1)) == TRUTH_OR_EXPR
- || TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1)) == BIT_IOR_EXPR))
+ /* For BIT_IOR_EXPR only if NAME == 0 both operands have
+ necessarily zero value. */
+ || (comp_code == EQ_EXPR
+ && (TREE_CODE (GIMPLE_STMT_OPERAND (def_stmt, 1))
+ == BIT_IOR_EXPR))))
{
tree op0 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 0);
tree op1 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 1);
@@ -3690,14 +4107,22 @@ find_conditional_asserts (basic_block bb, tree last)
/* Traverse the strictly dominated sub-graph rooted at E->DEST
to determine if any of the operands in the conditional
predicate are used. */
- if (e->dest != bb)
- need_assert |= find_assert_locations (e->dest);
+ need_assert |= find_assert_locations (e->dest);
/* Register the necessary assertions for each operand in the
conditional predicate. */
FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE)
- need_assert |= register_edge_assert_for (op, e, bsi,
- COND_EXPR_COND (last));
+ {
+ tree cond = COND_EXPR_COND (last);
+ if (op != cond)
+ need_assert |= register_edge_assert_for (op, e, bsi,
+ TREE_CODE (cond),
+ TREE_OPERAND (cond, 0),
+ TREE_OPERAND (cond, 1));
+ else
+ need_assert |= register_edge_assert_for (op, e, bsi, EQ_EXPR, op,
+ boolean_true_node);
+ }
}
/* Finally, indicate that we have found the operands in the
@@ -3714,8 +4139,8 @@ find_conditional_asserts (basic_block bb, tree last)
static int
compare_case_labels (const void *p1, const void *p2)
{
- tree case1 = *(tree *)p1;
- tree case2 = *(tree *)p2;
+ const_tree const case1 = *(const_tree const*)p1;
+ const_tree const case2 = *(const_tree const*)p2;
unsigned int uid1 = DECL_UID (CASE_LABEL (case1));
unsigned int uid2 = DECL_UID (CASE_LABEL (case2));
@@ -3748,7 +4173,7 @@ find_switch_asserts (basic_block bb, tree last)
{
bool need_assert;
block_stmt_iterator bsi;
- tree op, cond;
+ tree op;
edge e;
tree vec = SWITCH_LABELS (last), vec2;
size_t n = TREE_VEC_LENGTH (vec);
@@ -3815,14 +4240,17 @@ find_switch_asserts (basic_block bb, tree last)
/* Register the necessary assertions for the operand in the
SWITCH_EXPR. */
- cond = build2 (max ? GE_EXPR : EQ_EXPR, boolean_type_node,
- op, fold_convert (TREE_TYPE (op), min));
- need_assert |= register_edge_assert_for (op, e, bsi, cond);
+ need_assert |= register_edge_assert_for (op, e, bsi,
+ max ? GE_EXPR : EQ_EXPR,
+ op,
+ fold_convert (TREE_TYPE (op),
+ min));
if (max)
{
- cond = build2 (LE_EXPR, boolean_type_node,
- op, fold_convert (TREE_TYPE (op), max));
- need_assert |= register_edge_assert_for (op, e, bsi, cond);
+ need_assert |= register_edge_assert_for (op, e, bsi, LE_EXPR,
+ op,
+ fold_convert (TREE_TYPE (op),
+ max));
}
}
@@ -3987,7 +4415,7 @@ find_assert_locations (basic_block bb)
conversion. */
if (! has_single_use (t))
{
- register_new_assert_for (t, comp_code, value,
+ register_new_assert_for (t, t, comp_code, value,
bb, NULL, si);
need_assert = true;
}
@@ -3999,7 +4427,8 @@ find_assert_locations (basic_block bb)
ASSERT_EXPR would do nothing but increase compile time. */
if (!has_single_use (op))
{
- register_new_assert_for (op, comp_code, value, bb, NULL, si);
+ register_new_assert_for (op, op, comp_code, value,
+ bb, NULL, si);
need_assert = true;
}
}
@@ -4044,7 +4473,7 @@ process_assert_insertions_for (tree name, assert_locus_t loc)
edge_iterator ei;
edge e;
- cond = build2 (loc->comp_code, boolean_type_node, name, loc->val);
+ cond = build2 (loc->comp_code, boolean_type_node, loc->expr, loc->val);
assert_expr = build_assert_expr_for (cond, name);
if (loc->e)
@@ -4211,7 +4640,7 @@ check_array_ref (tree ref, location_t* locus, bool ignore_off_by_one)
low_sub = up_sub = TREE_OPERAND (ref, 1);
- if (!up_bound || !locus || TREE_NO_WARNING (ref)
+ if (!up_bound || TREE_NO_WARNING (ref)
|| TREE_CODE (up_bound) != INTEGER_CST
/* Can not check flexible arrays. */
|| (TYPE_SIZE (TREE_TYPE (ref)) == NULL_TREE
@@ -4313,6 +4742,12 @@ check_array_bounds (tree *tp, int *walk_subtree, void *data)
tree stmt = (tree)data;
location_t *location = EXPR_LOCUS (stmt);
+ if (!EXPR_HAS_LOCATION (stmt))
+ {
+ *walk_subtree = FALSE;
+ return NULL_TREE;
+ }
+
*walk_subtree = TRUE;
if (TREE_CODE (t) == ARRAY_REF)
@@ -4585,7 +5020,7 @@ vrp_visit_assignment (tree stmt, tree *output_p)
}
/* Helper that gets the value range of the SSA_NAME with version I
- or a symbolic range contaning the SSA_NAME only if the value range
+ or a symbolic range containing the SSA_NAME only if the value range
is varying or undefined. */
static inline value_range_t
@@ -4634,8 +5069,8 @@ compare_name_with_value (enum tree_code comp, tree var, tree val,
equiv_vr = get_vr_for_comparison (SSA_NAME_VERSION (var));
sop = false;
retval = compare_range_with_value (comp, &equiv_vr, val, &sop);
- if (sop)
- used_strict_overflow = 1;
+ if (retval)
+ used_strict_overflow = sop ? 1 : 0;
/* If the equiv set is empty we have done all work we need to do. */
if (e == NULL)
@@ -4749,7 +5184,7 @@ compare_names (enum tree_code comp, tree n1, tree n2,
t = retval = NULL_TREE;
EXECUTE_IF_SET_IN_BITMAP (e2, 0, i2, bi2)
{
- bool sop;
+ bool sop = false;
value_range_t vr2 = get_vr_for_comparison (i2);
@@ -4793,6 +5228,51 @@ compare_names (enum tree_code comp, tree n1, tree n2,
return NULL_TREE;
}
+/* Helper function for vrp_evaluate_conditional_warnv. */
+
+static tree
+vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
+ tree op1, bool use_equiv_p,
+ bool *strict_overflow_p)
+{
+ /* We only deal with integral and pointer types. */
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
+ && !POINTER_TYPE_P (TREE_TYPE (op0)))
+ return NULL_TREE;
+
+ if (use_equiv_p)
+ {
+ if (TREE_CODE (op0) == SSA_NAME && TREE_CODE (op1) == SSA_NAME)
+ return compare_names (code, op0, op1,
+ strict_overflow_p);
+ else if (TREE_CODE (op0) == SSA_NAME)
+ return compare_name_with_value (code, op0, op1,
+ strict_overflow_p);
+ else if (TREE_CODE (op1) == SSA_NAME)
+ return (compare_name_with_value
+ (swap_tree_comparison (code), op1, op0,
+ strict_overflow_p));
+ }
+ else
+ {
+ value_range_t *vr0, *vr1;
+
+ vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
+ vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
+
+ if (vr0 && vr1)
+ return compare_ranges (code, vr0, vr1,
+ strict_overflow_p);
+ else if (vr0 && vr1 == NULL)
+ return compare_range_with_value (code, vr0, op1,
+ strict_overflow_p);
+ else if (vr0 == NULL && vr1)
+ return (compare_range_with_value
+ (swap_tree_comparison (code), vr1, op0,
+ strict_overflow_p));
+ }
+ return NULL_TREE;
+}
/* Given a conditional predicate COND, try to determine if COND yields
true or false based on the value ranges of its operands. Return
@@ -4841,47 +5321,11 @@ vrp_evaluate_conditional_warnv (tree cond, bool use_equiv_p,
return vr->min;
}
else
- {
- tree op0 = TREE_OPERAND (cond, 0);
- tree op1 = TREE_OPERAND (cond, 1);
-
- /* We only deal with integral and pointer types. */
- if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
- && !POINTER_TYPE_P (TREE_TYPE (op0)))
- return NULL_TREE;
-
- if (use_equiv_p)
- {
- if (TREE_CODE (op0) == SSA_NAME && TREE_CODE (op1) == SSA_NAME)
- return compare_names (TREE_CODE (cond), op0, op1,
- strict_overflow_p);
- else if (TREE_CODE (op0) == SSA_NAME)
- return compare_name_with_value (TREE_CODE (cond), op0, op1,
- strict_overflow_p);
- else if (TREE_CODE (op1) == SSA_NAME)
- return (compare_name_with_value
- (swap_tree_comparison (TREE_CODE (cond)), op1, op0,
- strict_overflow_p));
- }
- else
- {
- value_range_t *vr0, *vr1;
-
- vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
- vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
-
- if (vr0 && vr1)
- return compare_ranges (TREE_CODE (cond), vr0, vr1,
- strict_overflow_p);
- else if (vr0 && vr1 == NULL)
- return compare_range_with_value (TREE_CODE (cond), vr0, op1,
- strict_overflow_p);
- else if (vr0 == NULL && vr1)
- return (compare_range_with_value
- (swap_tree_comparison (TREE_CODE (cond)), vr1, op0,
- strict_overflow_p));
- }
- }
+ return vrp_evaluate_conditional_warnv_with_ops (TREE_CODE (cond),
+ TREE_OPERAND (cond, 0),
+ TREE_OPERAND (cond, 1),
+ use_equiv_p,
+ strict_overflow_p);
/* Anything else cannot be computed statically. */
return NULL_TREE;
@@ -4933,6 +5377,49 @@ vrp_evaluate_conditional (tree cond, tree stmt)
}
}
+ if (warn_type_limits
+ && ret
+ && TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
+ && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME)
+ {
+ /* If the comparison is being folded and the operand on the LHS
+ is being compared against a constant value that is outside of
+ the natural range of OP0's type, then the predicate will
+ always fold regardless of the value of OP0. If -Wtype-limits
+ was specified, emit a warning. */
+ const char *warnmsg = NULL;
+ tree op0 = TREE_OPERAND (cond, 0);
+ tree op1 = TREE_OPERAND (cond, 1);
+ tree type = TREE_TYPE (op0);
+ value_range_t *vr0 = get_value_range (op0);
+
+ if (vr0->type != VR_VARYING
+ && INTEGRAL_TYPE_P (type)
+ && vrp_val_is_min (vr0->min)
+ && vrp_val_is_max (vr0->max)
+ && is_gimple_min_invariant (op1))
+ {
+ if (integer_zerop (ret))
+ warnmsg = G_("comparison always false due to limited range of "
+ "data type");
+ else
+ warnmsg = G_("comparison always true due to limited range of "
+ "data type");
+ }
+
+ if (warnmsg)
+ {
+ location_t locus;
+
+ if (!EXPR_HAS_LOCATION (stmt))
+ locus = input_location;
+ else
+ locus = EXPR_LOCATION (stmt);
+
+ warning (OPT_Wtype_limits, "%H%s", &locus, warnmsg);
+ }
+ }
+
return ret;
}
@@ -4949,11 +5436,6 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p)
bool sop;
*taken_edge_p = NULL;
-
- /* FIXME. Handle SWITCH_EXPRs. */
- if (TREE_CODE (stmt) == SWITCH_EXPR)
- return SSA_PROP_VARYING;
-
cond = COND_EXPR_COND (stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -5047,6 +5529,147 @@ vrp_visit_cond_stmt (tree stmt, edge *taken_edge_p)
}
+/* Searches the case label vector VEC for the index *IDX the CASE_LABEL
+ includes the value VAL. The search starts at index START_IDX and
+ true is returned if *IDX corresponds to such an index. False is
+ returned in case VAL hits the default case label and *IDX in this
+ case is the next higher or the next lower case label index. */
+
+static bool
+find_case_label_index (tree vec, size_t start_idx, tree val, size_t *idx)
+{
+ size_t n = TREE_VEC_LENGTH (vec);
+ size_t low, high, i = start_idx;
+
+ /* Find case label for minimum of the value range or the next one. */
+ for (low = start_idx - 1, high = n - 1; high - low > 1; )
+ {
+ tree t;
+ int cmp;
+ i = (high + low) / 2;
+ t = TREE_VEC_ELT (vec, i);
+
+ /* Cache the result of comparing CASE_LOW and val. */
+ cmp = tree_int_cst_compare (CASE_LOW (t), val);
+
+ if (cmp > 0)
+ high = i;
+ else
+ low = i;
+
+ if (CASE_HIGH (t) == NULL)
+ {
+ /* A singe-valued case label. */
+ if (cmp == 0)
+ {
+ *idx = i;
+ return true;
+ }
+ }
+ else
+ {
+ /* A case range. We can only handle integer ranges. */
+ if (cmp <= 0 && tree_int_cst_compare (CASE_HIGH (t), val) >= 0)
+ {
+ *idx = i;
+ return true;
+ }
+ }
+ }
+
+ *idx = i;
+ return false;
+}
+
+/* Visit switch statement STMT. If we can determine which edge
+ will be taken out of STMT's basic block, record it in
+ *TAKEN_EDGE_P and return SSA_PROP_INTERESTING. Otherwise, return
+ SSA_PROP_VARYING. */
+
+static enum ssa_prop_result
+vrp_visit_switch_stmt (tree stmt, edge *taken_edge_p)
+{
+ tree op, val;
+ value_range_t *vr;
+ size_t i = 0, j = 0, n;
+ tree vec;
+ bool min_take_default, max_take_default;
+
+ *taken_edge_p = NULL;
+ op = TREE_OPERAND (stmt, 0);
+ if (TREE_CODE (op) != SSA_NAME)
+ return SSA_PROP_VARYING;
+
+ vr = get_value_range (op);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nVisiting switch expression with operand ");
+ print_generic_expr (dump_file, op, 0);
+ fprintf (dump_file, " with known range ");
+ dump_value_range (dump_file, vr);
+ fprintf (dump_file, "\n");
+ }
+
+ if (vr->type != VR_RANGE
+ || symbolic_range_p (vr))
+ return SSA_PROP_VARYING;
+
+ /* Find the single edge that is taken from the switch expression. */
+ vec = SWITCH_LABELS (stmt);
+ n = TREE_VEC_LENGTH (vec);
+
+ /* Find case label for minimum of the value range or the next one. */
+ min_take_default = !find_case_label_index (vec, 0, vr->min, &i);
+
+ /* Find case label for maximum of the value range or the previous one. */
+ max_take_default = !find_case_label_index (vec, i, vr->max, &j);
+
+ /* Check if we reach the default label only. */
+ if (j < i)
+ val = TREE_VEC_ELT (vec, n - 1);
+ /* Check if we reach exactly one label and not the default label. */
+ else if (i == j
+ && !min_take_default
+ && !max_take_default)
+ val = TREE_VEC_ELT (vec, i);
+ else
+ {
+ /* Check if labels with index i to j are all reaching the same label.
+ If we don't hit a single case label only, the default case also has
+ to branch to the same label. */
+ val = TREE_VEC_ELT (vec, i);
+ if (CASE_LABEL (TREE_VEC_ELT (vec, n - 1)) != CASE_LABEL (val))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " not a single destination for this "
+ "range\n");
+ return SSA_PROP_VARYING;
+ }
+ for (++i; i <= j; ++i)
+ {
+ if (CASE_LABEL (TREE_VEC_ELT (vec, i)) != CASE_LABEL (val))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " not a single destination for this "
+ "range\n");
+ return SSA_PROP_VARYING;
+ }
+ }
+ }
+
+ *taken_edge_p = find_edge (bb_for_stmt (stmt),
+ label_to_block (CASE_LABEL (val)));
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " will take edge to ");
+ print_generic_stmt (dump_file, CASE_LABEL (val), 0);
+ }
+
+ return SSA_PROP_INTERESTING;
+}
+
+
/* Evaluate statement STMT. If the statement produces a useful range,
return SSA_PROP_INTERESTING and record the SSA name with the
interesting range into *OUTPUT_P.
@@ -5085,8 +5708,10 @@ vrp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
|| ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
return vrp_visit_assignment (stmt, output_p);
}
- else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
+ else if (TREE_CODE (stmt) == COND_EXPR)
return vrp_visit_cond_stmt (stmt, taken_edge_p);
+ else if (TREE_CODE (stmt) == SWITCH_EXPR)
+ return vrp_visit_switch_stmt (stmt, taken_edge_p);
/* All other statements produce nothing of interest for VRP, so mark
their outputs varying and prevent further simulation. */
@@ -5157,10 +5782,8 @@ vrp_meet (value_range_t *vr0, value_range_t *vr1)
/* Check for useless ranges. */
if (INTEGRAL_TYPE_P (TREE_TYPE (min))
- && ((min == TYPE_MIN_VALUE (TREE_TYPE (min))
- || is_overflow_infinity (min))
- && (max == TYPE_MAX_VALUE (TREE_TYPE (max))
- || is_overflow_infinity (max))))
+ && ((vrp_val_is_min (min) || is_overflow_infinity (min))
+ && (vrp_val_is_max (max) || is_overflow_infinity (max))))
goto give_up;
/* The resulting set of equivalences is the intersection of
@@ -5348,12 +5971,11 @@ vrp_visit_phi_node (tree phi)
{
/* If we will end up with a (-INF, +INF) range, set it
to VARYING. */
- if (is_positive_overflow_infinity (vr_result.max)
- || (vr_result.max
- == TYPE_MAX_VALUE (TREE_TYPE (vr_result.max))))
+ if (vrp_val_is_max (vr_result.max))
goto varying;
- if (!needs_overflow_infinity (TREE_TYPE (vr_result.min)))
+ if (!needs_overflow_infinity (TREE_TYPE (vr_result.min))
+ || !vrp_var_may_overflow (lhs, phi))
vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min));
else if (supports_overflow_infinity (TREE_TYPE (vr_result.min)))
vr_result.min =
@@ -5368,12 +5990,11 @@ vrp_visit_phi_node (tree phi)
{
/* If we will end up with a (-INF, +INF) range, set it
to VARYING. */
- if (is_negative_overflow_infinity (vr_result.min)
- || (vr_result.min
- == TYPE_MIN_VALUE (TREE_TYPE (vr_result.min))))
+ if (vrp_val_is_min (vr_result.min))
goto varying;
- if (!needs_overflow_infinity (TREE_TYPE (vr_result.max)))
+ if (!needs_overflow_infinity (TREE_TYPE (vr_result.max))
+ || !vrp_var_may_overflow (lhs, phi))
vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max));
else if (supports_overflow_infinity (TREE_TYPE (vr_result.max)))
vr_result.max =
@@ -5417,7 +6038,7 @@ simplify_div_or_mod_using_ranges (tree stmt, tree rhs, enum tree_code rhs_code)
{
bool sop = false;
- val = compare_range_with_value (GT_EXPR, vr, integer_zero_node, &sop);
+ val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
if (val
&& sop
@@ -5553,6 +6174,8 @@ test_for_singularity (enum tree_code cond_code, tree op0,
{
tree one = build_int_cst (TREE_TYPE (op0), 1);
max = fold_build2 (MINUS_EXPR, TREE_TYPE (op0), max, one);
+ if (EXPR_P (max))
+ TREE_NO_WARNING (max) = 1;
}
}
else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
@@ -5566,6 +6189,8 @@ test_for_singularity (enum tree_code cond_code, tree op0,
{
tree one = build_int_cst (TREE_TYPE (op0), 1);
min = fold_build2 (PLUS_EXPR, TREE_TYPE (op0), min, one);
+ if (EXPR_P (min))
+ TREE_NO_WARNING (min) = 1;
}
}
@@ -5670,6 +6295,106 @@ simplify_cond_using_ranges (tree stmt)
}
}
+/* Simplify a switch statement using the value range of the switch
+ argument. */
+
+static void
+simplify_switch_using_ranges (tree stmt)
+{
+ tree op = TREE_OPERAND (stmt, 0);
+ value_range_t *vr;
+ bool take_default;
+ edge e;
+ edge_iterator ei;
+ size_t i = 0, j = 0, n, n2;
+ tree vec, vec2;
+ switch_update su;
+
+ if (TREE_CODE (op) != SSA_NAME)
+ return;
+
+ vr = get_value_range (op);
+
+ /* We can only handle integer ranges. */
+ if (vr->type != VR_RANGE
+ || symbolic_range_p (vr))
+ return;
+
+ /* Find case label for min/max of the value range. */
+ vec = SWITCH_LABELS (stmt);
+ n = TREE_VEC_LENGTH (vec);
+ take_default = !find_case_label_index (vec, 0, vr->min, &i);
+ take_default |= !find_case_label_index (vec, i, vr->max, &j);
+
+ /* If the case label range is continuous, we do not need to
+ preserve the default case label. Verify that. */
+ if (!take_default && j > i)
+ {
+ tree low, high;
+ size_t k;
+
+ high = CASE_LOW (TREE_VEC_ELT (vec, i));
+ if (CASE_HIGH (TREE_VEC_ELT (vec, i)))
+ high = CASE_HIGH (TREE_VEC_ELT (vec, i));
+ for (k = i + 1; k <= j; ++k)
+ {
+ low = CASE_LOW (TREE_VEC_ELT (vec, k));
+ if (!integer_onep (int_const_binop (MINUS_EXPR, low, high, 0)))
+ {
+ take_default = true;
+ break;
+ }
+ high = low;
+ if (CASE_HIGH (TREE_VEC_ELT (vec, k)))
+ high = CASE_HIGH (TREE_VEC_ELT (vec, k));
+ }
+ }
+
+ /* Bail out if this is just all edges taken. */
+ if (i == 0
+ && j == n - 2
+ && take_default)
+ return;
+
+ /* Build a new vector of taken case labels. */
+ vec2 = make_tree_vec (j - i + 1 + (int)take_default);
+ for (n2 = 0; i <= j; ++i, ++n2)
+ TREE_VEC_ELT (vec2, n2) = TREE_VEC_ELT (vec, i);
+
+ /* Add the default edge, if necessary. */
+ if (take_default)
+ TREE_VEC_ELT (vec2, n2++) = TREE_VEC_ELT (vec, n - 1);
+
+ /* Mark needed edges. */
+ for (i = 0; i < n2; ++i)
+ {
+ e = find_edge (bb_for_stmt (stmt),
+ label_to_block (CASE_LABEL (TREE_VEC_ELT (vec2, i))));
+ e->aux = (void *)-1;
+ }
+
+ /* Queue not needed edges for later removal. */
+ FOR_EACH_EDGE (e, ei, bb_for_stmt (stmt)->succs)
+ {
+ if (e->aux == (void *)-1)
+ {
+ e->aux = NULL;
+ continue;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "removing unreachable case label\n");
+ }
+ VEC_safe_push (edge, heap, to_remove_edges, e);
+ }
+
+ /* And queue an update for the stmt. */
+ su.stmt = stmt;
+ su.vec = vec2;
+ VEC_safe_push (switch_update, heap, to_update_switch_stmts, &su);
+}
+
/* Simplify STMT using ranges if possible. */
void
@@ -5696,9 +6421,9 @@ simplify_stmt_using_ranges (tree stmt)
}
else if (TREE_CODE (stmt) == COND_EXPR
&& COMPARISON_CLASS_P (COND_EXPR_COND (stmt)))
- {
- simplify_cond_using_ranges (stmt);
- }
+ simplify_cond_using_ranges (stmt);
+ else if (TREE_CODE (stmt) == SWITCH_EXPR)
+ simplify_switch_using_ranges (stmt);
}
/* Stack of dest,src equivalency pairs that need to be restored after
@@ -5750,6 +6475,8 @@ identify_jump_threads (void)
{
basic_block bb;
tree dummy;
+ int i;
+ edge e;
/* Ugh. When substituting values earlier in this pass we can
wipe the dominance information. So rebuild the dominator
@@ -5763,6 +6490,11 @@ identify_jump_threads (void)
recompute it. */
mark_dfs_back_edges ();
+ /* Do not thread across edges we are about to remove. Just marking
+ them as EDGE_DFS_BACK will do. */
+ for (i = 0; VEC_iterate (edge, to_remove_edges, i, e); ++i)
+ e->flags |= EDGE_DFS_BACK;
+
/* Allocate our unwinder stack to unwind any temporary equivalences
that might be recorded. */
stack = VEC_alloc (tree, heap, 20);
@@ -5808,7 +6540,6 @@ identify_jump_threads (void)
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1)))))
{
edge_iterator ei;
- edge e;
/* We've got a block with multiple predecessors and multiple
successors which also ends in a suitable conditional. For
@@ -5842,13 +6573,7 @@ identify_jump_threads (void)
static void
finalize_jump_threads (void)
{
- bool cfg_altered = false;
- cfg_altered = thread_through_all_blocks ();
-
- /* If we threaded jumps, then we need to recompute the dominance
- information. */
- if (cfg_altered)
- free_dominance_info (CDI_DOMINATORS);
+ thread_through_all_blocks (false);
VEC_free (tree, heap, stack);
}
@@ -5919,6 +6644,20 @@ vrp_finalize (void)
vr_phi_edge_counts = NULL;
}
+/* Calculates number of iterations for all loops, to ensure that they are
+ cached. */
+
+static void
+record_numbers_of_iterations (void)
+{
+ loop_iterator li;
+ struct loop *loop;
+
+ FOR_EACH_LOOP (li, loop, 0)
+ {
+ number_of_latch_executions (loop);
+ }
+}
/* Main entry point to VRP (Value Range Propagation). This pass is
loosely based on J. R. C. Patterson, ``Accurate Static Branch
@@ -5967,21 +6706,47 @@ vrp_finalize (void)
static unsigned int
execute_vrp (void)
{
+ int i;
+ edge e;
+ switch_update *su;
+
+ loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
+ rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+ scev_initialize ();
+
insert_range_assertions ();
- loop_optimizer_init (LOOPS_NORMAL);
- if (current_loops)
- scev_initialize ();
+ /* Compute the # of iterations for each loop before we start the VRP
+ analysis. The value ranges determined by VRP are used in expression
+ simplification, that is also used by the # of iterations analysis.
+ However, in the middle of the VRP analysis, the value ranges do not take
+ all the possible paths in CFG into account, so they do not have to be
+ correct, and the # of iterations analysis can obtain wrong results.
+ This is a problem, since the results of the # of iterations analysis
+ are cached, so these mistakes would not be corrected when the value
+ ranges are corrected. */
+ record_numbers_of_iterations ();
+
+ to_remove_edges = VEC_alloc (edge, heap, 10);
+ to_update_switch_stmts = VEC_alloc (switch_update, heap, 5);
vrp_initialize ();
ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
vrp_finalize ();
- if (current_loops)
- {
- scev_finalize ();
- loop_optimizer_finalize ();
- }
+ /* Remove dead edges from SWITCH_EXPR optimization. This leaves the
+ CFG in a broken state and requires a cfg_cleanup run. */
+ for (i = 0; VEC_iterate (edge, to_remove_edges, i, e); ++i)
+ remove_edge (e);
+ /* Update SWITCH_EXPR case label vector. */
+ for (i = 0; VEC_iterate (switch_update, to_update_switch_stmts, i, su); ++i)
+ SWITCH_LABELS (su->stmt) = su->vec;
+
+ if (VEC_length (edge, to_remove_edges) > 0)
+ free_dominance_info (CDI_DOMINATORS);
+
+ VEC_free (edge, heap, to_remove_edges);
+ VEC_free (switch_update, heap, to_update_switch_stmts);
/* ASSERT_EXPRs must be removed before finalizing jump threads
as finalizing jump threads calls the CFG cleanup code which
@@ -5996,6 +6761,9 @@ execute_vrp (void)
update_ssa (TODO_update_ssa);
finalize_jump_threads ();
+ scev_finalize ();
+ loop_optimizer_finalize ();
+
return 0;
}
@@ -6005,8 +6773,10 @@ gate_vrp (void)
return flag_tree_vrp != 0;
}
-struct tree_opt_pass pass_vrp =
+struct gimple_opt_pass pass_vrp =
{
+ {
+ GIMPLE_PASS,
"vrp", /* name */
gate_vrp, /* gate */
execute_vrp, /* execute */
@@ -6022,6 +6792,6 @@ struct tree_opt_pass pass_vrp =
| TODO_ggc_collect
| TODO_verify_ssa
| TODO_dump_func
- | TODO_update_ssa, /* todo_flags_finish */
- 0 /* letter */
+ | TODO_update_ssa /* todo_flags_finish */
+ }
};