/* Support routines for Value Range Propagation (VRP).
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>.
This file is part of GCC.
sub-graph in find_assert_locations. */
static sbitmap found_in_subgraph;
-/* Loop structure of the program. Used to analyze scalar evolutions
- inside adjust_range_with_scev. */
-static struct loops *cfg_loops;
-
/* Local functions. */
static int compare_values (tree val1, tree val2);
set_value_range (to, from->type, from->min, from->max, from->equiv);
}
+/* Set value range VR to a non-negative range of type TYPE. */
+
+static inline void
+set_value_range_to_nonnegative (value_range_t *vr, tree type)
+{
+ tree zero = build_int_cst (type, 0);
+ set_value_range (vr, VR_RANGE, zero, TYPE_MAX_VALUE (type), vr->equiv);
+}
/* Set value range VR to a non-NULL range of type TYPE. */
}
-/* Return value range information for VAR. Create an empty range
- if none existed. */
+/* Return value range information for VAR.
+
+ If we have no values ranges recorded (ie, VRP is not running), then
+ return NULL. Otherwise create an empty range if none existed for VAR. */
static value_range_t *
get_value_range (tree var)
tree sym;
unsigned ver = SSA_NAME_VERSION (var);
+ /* If we have no recorded ranges, then return NULL. */
+ if (! vr_value)
+ return NULL;
+
vr = vr_value[ver];
if (vr)
return vr;
/* Create a default value range. */
- vr_value[ver] = vr = xmalloc (sizeof (*vr));
- memset (vr, 0, sizeof (*vr));
+ vr_value[ver] = vr = XCNEW (value_range_t);
/* Allocate an equivalence set. */
vr->equiv = BITMAP_ALLOC (NULL);
return vr;
}
+/* Return true, if VAL1 and VAL2 are equal values for VRP purposes. */
+
+static inline bool
+vrp_operand_equal_p (tree val1, tree val2)
+{
+ return (val1 == val2
+ || (val1 && val2
+ && operand_equal_p (val1, val2, 0)));
+}
+
+/* Return true, if the bitmaps B1 and B2 are equal. */
+
+static inline bool
+vrp_bitmap_equal_p (bitmap b1, bitmap b2)
+{
+ return (b1 == b2
+ || (b1 && b2
+ && bitmap_equal_p (b1, b2)));
+}
/* Update the value range and equivalence set for variable VAR to
NEW_VR. Return true if NEW_VR is different from VAR's previous
/* Update the value range, if necessary. */
old_vr = get_value_range (var);
is_new = old_vr->type != new_vr->type
- || old_vr->min != new_vr->min
- || old_vr->max != new_vr->max
- || (old_vr->equiv == NULL && new_vr->equiv)
- || (old_vr->equiv && new_vr->equiv == NULL)
- || (!bitmap_equal_p (old_vr->equiv, new_vr->equiv));
+ || !vrp_operand_equal_p (old_vr->min, new_vr->min)
+ || !vrp_operand_equal_p (old_vr->max, new_vr->max)
+ || !vrp_bitmap_equal_p (old_vr->equiv, new_vr->equiv);
if (is_new)
set_value_range (old_vr, new_vr->type, new_vr->min, new_vr->max,
|| !is_gimple_min_invariant (vr->max));
}
+/* Like tree_expr_nonnegative_p, but this function uses value ranges
+ obtained so far. */
+
+static bool
+vrp_expr_computes_nonnegative (tree expr)
+{
+ return tree_expr_nonnegative_p (expr);
+}
/* Like tree_expr_nonzero_p, but this function uses value ranges
obtained so far. */
return false;
}
+/* Returns true if EXPR is a valid value (as expected by compare_values) --
+ a gimple invariant, or SSA_NAME +- CST. */
+
+static bool
+valid_value_p (tree expr)
+{
+ if (TREE_CODE (expr) == SSA_NAME)
+ return true;
+
+ if (TREE_CODE (expr) == PLUS_EXPR
+ || TREE_CODE (expr) == MINUS_EXPR)
+ return (TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST);
+
+ return is_gimple_min_invariant (expr);
+}
/* Compare two values VAL1 and VAL2. Return
gcc_assert (POINTER_TYPE_P (TREE_TYPE (val1))
== POINTER_TYPE_P (TREE_TYPE (val2)));
- /* Do some limited symbolic comparisons. */
- if (!POINTER_TYPE_P (TREE_TYPE (val1)))
- {
- /* We can determine some comparisons against +INF and -INF even
- if the other value is an expression. */
- if (val1 == TYPE_MAX_VALUE (TREE_TYPE (val1))
- && TREE_CODE (val2) == MINUS_EXPR)
- {
- /* +INF > NAME - CST. */
- return 1;
- }
- else if (val1 == TYPE_MIN_VALUE (TREE_TYPE (val1))
- && TREE_CODE (val2) == PLUS_EXPR)
- {
- /* -INF < NAME + CST. */
- return -1;
- }
- else if (TREE_CODE (val1) == MINUS_EXPR
- && val2 == TYPE_MAX_VALUE (TREE_TYPE (val2)))
- {
- /* NAME - CST < +INF. */
- return -1;
- }
- else if (TREE_CODE (val1) == PLUS_EXPR
- && val2 == TYPE_MIN_VALUE (TREE_TYPE (val2)))
- {
- /* NAME + CST > -INF. */
- return 1;
- }
- }
-
if ((TREE_CODE (val1) == SSA_NAME
|| TREE_CODE (val1) == PLUS_EXPR
|| TREE_CODE (val1) == MINUS_EXPR)
|| TREE_CODE (val2) == MINUS_EXPR))
{
tree n1, c1, n2, c2;
+ enum tree_code code1, code2;
/* If VAL1 and VAL2 are of the form 'NAME [+-] CST' or 'NAME',
return -1 or +1 accordingly. If VAL1 and VAL2 don't use the
same name, return -2. */
if (TREE_CODE (val1) == SSA_NAME)
{
+ code1 = SSA_NAME;
n1 = val1;
c1 = NULL_TREE;
}
else
{
+ code1 = TREE_CODE (val1);
n1 = TREE_OPERAND (val1, 0);
c1 = TREE_OPERAND (val1, 1);
+ if (tree_int_cst_sgn (c1) == -1)
+ {
+ c1 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c1), c1);
+ if (!c1)
+ return -2;
+ code1 = code1 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
+ }
}
if (TREE_CODE (val2) == SSA_NAME)
{
+ code2 = SSA_NAME;
n2 = val2;
c2 = NULL_TREE;
}
else
{
+ code2 = TREE_CODE (val2);
n2 = TREE_OPERAND (val2, 0);
c2 = TREE_OPERAND (val2, 1);
+ if (tree_int_cst_sgn (c2) == -1)
+ {
+ c2 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c2), c2);
+ if (!c2)
+ return -2;
+ code2 = code2 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
+ }
}
/* Both values must use the same name. */
if (n1 != n2)
return -2;
- if (TREE_CODE (val1) == SSA_NAME)
+ if (code1 == SSA_NAME
+ && code2 == SSA_NAME)
+ /* NAME == NAME */
+ return 0;
+
+ /* If overflow is defined we cannot simplify more. */
+ if (TYPE_UNSIGNED (TREE_TYPE (val1))
+ || flag_wrapv)
+ return -2;
+
+ if (code1 == SSA_NAME)
{
- if (TREE_CODE (val2) == SSA_NAME)
- /* NAME == NAME */
- return 0;
- else if (TREE_CODE (val2) == PLUS_EXPR)
+ if (code2 == PLUS_EXPR)
/* NAME < NAME + CST */
return -1;
- else if (TREE_CODE (val2) == MINUS_EXPR)
+ else if (code2 == MINUS_EXPR)
/* NAME > NAME - CST */
return 1;
}
- else if (TREE_CODE (val1) == PLUS_EXPR)
+ else if (code1 == PLUS_EXPR)
{
- if (TREE_CODE (val2) == SSA_NAME)
+ if (code2 == SSA_NAME)
/* NAME + CST > NAME */
return 1;
- else if (TREE_CODE (val2) == PLUS_EXPR)
+ else if (code2 == PLUS_EXPR)
/* NAME + CST1 > NAME + CST2, if CST1 > CST2 */
return compare_values (c1, c2);
- else if (TREE_CODE (val2) == MINUS_EXPR)
+ else if (code2 == MINUS_EXPR)
/* NAME + CST1 > NAME - CST2 */
return 1;
}
- else if (TREE_CODE (val1) == MINUS_EXPR)
+ else if (code1 == MINUS_EXPR)
{
- if (TREE_CODE (val2) == SSA_NAME)
+ if (code2 == SSA_NAME)
/* NAME - CST < NAME */
return -1;
- else if (TREE_CODE (val2) == PLUS_EXPR)
+ else if (code2 == PLUS_EXPR)
/* NAME - CST1 < NAME + CST2 */
return -1;
- else if (TREE_CODE (val2) == MINUS_EXPR)
+ else if (code2 == MINUS_EXPR)
/* NAME - CST1 > NAME - CST2, if CST1 < CST2. Notice that
C1 and C2 are swapped in the call to compare_values. */
return compare_values (c2, c1);
if (!is_gimple_min_invariant (val1) || !is_gimple_min_invariant (val2))
return -2;
- /* We cannot compare overflowed values. */
- if (TREE_OVERFLOW (val1) || TREE_OVERFLOW (val2))
- return -2;
-
if (!POINTER_TYPE_P (TREE_TYPE (val1)))
- return tree_int_cst_compare (val1, val2);
+ {
+ /* We cannot compare overflowed values. */
+ if (TREE_OVERFLOW (val1) || TREE_OVERFLOW (val2))
+ return -2;
+
+ return tree_int_cst_compare (val1, val2);
+ }
else
{
tree t;
/* Return 1 if VAL is inside value range VR (VR->MIN <= VAL <= VR->MAX),
0 if VAL is not inside VR,
- -2 if we cannot tell either way. */
+ -2 if we cannot tell either way.
+
+ FIXME, the current semantics of this functions are a bit quirky
+ when taken in the context of VRP. In here we do not care
+ about VR's type. If VR is the anti-range ~[3, 5] the call
+ value_inside_range (4, VR) will return 1.
+
+ This is counter-intuitive in a strict sense, but the callers
+ currently expect this. They are calling the function
+ merely to determine whether VR->MIN <= VAL <= VR->MAX. The
+ callers are applying the VR_RANGE/VR_ANTI_RANGE semantics
+ themselves.
+
+ This also applies to value_ranges_intersect_p and
+ range_includes_zero_p. The semantics of VR_RANGE and
+ VR_ANTI_RANGE should be encoded here, but that also means
+ adapting the users of these functions to the new semantics. */
static inline int
value_inside_range (tree val, value_range_t *vr)
{
- int cmp1, cmp2;
+ tree cmp1, cmp2;
- cmp1 = compare_values (val, vr->min);
- if (cmp1 == -2 || cmp1 == 2)
+ cmp1 = fold_binary_to_constant (GE_EXPR, boolean_type_node, val, vr->min);
+ if (!cmp1)
return -2;
- cmp2 = compare_values (val, vr->max);
- if (cmp2 == -2 || cmp2 == 2)
+ cmp2 = fold_binary_to_constant (LE_EXPR, boolean_type_node, val, vr->max);
+ if (!cmp2)
return -2;
- return (cmp1 == 0 || cmp1 == 1) && (cmp2 == -1 || cmp2 == 0);
+ return cmp1 == boolean_true_node && cmp2 == boolean_true_node;
}
}
-/* Return true if VR includes the value zero, false otherwise. */
+/* Return true if VR includes the value zero, false otherwise. FIXME,
+ currently this will return false for an anti-range like ~[-4, 3].
+ This will be wrong when the semantics of value_inside_range are
+ modified (currently the users of this function expect these
+ semantics). */
static inline bool
range_includes_zero_p (value_range_t *vr)
return (value_inside_range (zero, vr) == 1);
}
+/* Return true if T, an SSA_NAME, is known to be nonnegative. Return
+ false otherwise or if no value range information is available. */
+
+bool
+ssa_name_nonnegative_p (tree t)
+{
+ value_range_t *vr = get_value_range (t);
+
+ if (!vr)
+ return false;
+
+ /* Testing for VR_ANTI_RANGE is not useful here as any anti-range
+ which would return a useful value should be encoded as a VR_RANGE. */
+ if (vr->type == VR_RANGE)
+ {
+ int result = compare_values (vr->min, integer_zero_node);
+
+ return (result == 0 || result == 1);
+ }
+ return false;
+}
+
+/* Return true if T, an SSA_NAME, is known to be nonzero. Return
+ false otherwise or if no value range information is available. */
+
+bool
+ssa_name_nonzero_p (tree t)
+{
+ value_range_t *vr = get_value_range (t);
+
+ if (!vr)
+ return false;
+
+ /* A VR_RANGE which does not include zero is a nonzero value. */
+ if (vr->type == VR_RANGE && !symbolic_range_p (vr))
+ return ! range_includes_zero_p (vr);
+
+ /* A VR_ANTI_RANGE which does include zero is a nonzero value. */
+ if (vr->type == VR_ANTI_RANGE && !symbolic_range_p (vr))
+ return range_includes_zero_p (vr);
+
+ return false;
+}
+
/* Extract value range information from an ASSERT_EXPR EXPR and store
it in *VR_P. */
|| symbolic_range_p (limit_vr)))
limit_vr = NULL;
- /* Special handling for integral types with super-types. Some FEs
- construct integral types derived from other types and restrict
- the range of values these new types may take.
-
- It may happen that LIMIT is actually smaller than TYPE's minimum
- value. For instance, the Ada FE is generating code like this
- during bootstrap:
-
- D.1480_32 = nam_30 - 300000361;
- if (D.1480_32 <= 1) goto <L112>; else goto <L52>;
- <L112>:;
- D.1480_94 = ASSERT_EXPR <D.1480_32, D.1480_32 <= 1>;
-
- All the names are of type types__name_id___XDLU_300000000__399999999
- which has min == 300000000 and max == 399999999. This means that
- the ASSERT_EXPR would try to create the range [3000000, 1] which
- is invalid.
-
- The fact that the type specifies MIN and MAX values does not
- automatically mean that every variable of that type will always
- be within that range, so the predicate may well be true at run
- time. If we had symbolic -INF and +INF values, we could
- represent this range, but we currently represent -INF and +INF
- using the type's min and max values.
-
- So, the only sensible thing we can do for now is set the
- resulting range to VR_VARYING. TODO, would having symbolic -INF
- and +INF values be worth the trouble? */
- if (TREE_CODE (limit) != SSA_NAME
- && INTEGRAL_TYPE_P (type)
- && TREE_TYPE (type))
- {
- if (cond_code == LE_EXPR || cond_code == LT_EXPR)
- {
- tree type_min = TYPE_MIN_VALUE (type);
- int cmp = compare_values (limit, type_min);
-
- /* For < or <= comparisons, if LIMIT is smaller than
- TYPE_MIN, set the range to VR_VARYING. */
- if (cmp == -1 || cmp == 0)
- {
- set_value_range_to_varying (vr_p);
- return;
- }
- }
- else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
- {
- tree type_max = TYPE_MIN_VALUE (type);
- int cmp = compare_values (limit, type_max);
-
- /* For > or >= comparisons, if LIMIT is bigger than
- TYPE_MAX, set the range to VR_VARYING. */
- if (cmp == 1 || cmp == 0)
- {
- set_value_range_to_varying (vr_p);
- return;
- }
- }
- }
-
- /* The new range has the same set of equivalences of VAR's range. */
+ /* Initially, the new range has the same set of equivalences of
+ VAR's range. This will be revised before returning the final
+ value. Since assertions may be chained via mutually exclusive
+ predicates, we will need to trim the set of equivalences before
+ we are done. */
gcc_assert (vr_p->equiv == NULL);
vr_p->equiv = BITMAP_ALLOC (NULL);
add_equivalence (vr_p->equiv, var);
max = limit_vr->max;
}
- /* For LT_EXPR, we create the range [MIN, MAX - 1]. */
- if (cond_code == LT_EXPR)
+ /* If the maximum value forces us to be out of bounds, simply punt.
+ It would be pointless to try and do anything more since this
+ all should be optimized away above us. */
+ if (cond_code == LT_EXPR && compare_values (max, min) == 0)
+ set_value_range_to_varying (vr_p);
+ else
{
- tree one = build_int_cst (type, 1);
- max = fold_build2 (MINUS_EXPR, type, max, one);
- }
+ /* For LT_EXPR, we create the range [MIN, MAX - 1]. */
+ if (cond_code == LT_EXPR)
+ {
+ tree one = build_int_cst (type, 1);
+ max = fold_build2 (MINUS_EXPR, type, max, one);
+ }
- set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+ set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+ }
}
else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
{
min = limit_vr->min;
}
- /* For GT_EXPR, we create the range [MIN + 1, MAX]. */
- if (cond_code == GT_EXPR)
+ /* If the minimum value forces us to be out of bounds, simply punt.
+ It would be pointless to try and do anything more since this
+ all should be optimized away above us. */
+ if (cond_code == GT_EXPR && compare_values (min, max) == 0)
+ set_value_range_to_varying (vr_p);
+ else
{
- tree one = build_int_cst (type, 1);
- min = fold_build2 (PLUS_EXPR, type, min, one);
- }
+ /* For GT_EXPR, we create the range [MIN + 1, MAX]. */
+ if (cond_code == GT_EXPR)
+ {
+ tree one = build_int_cst (type, 1);
+ min = fold_build2 (PLUS_EXPR, type, min, one);
+ }
- set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+ set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+ }
}
else
gcc_unreachable ();
- /* If VAR already had a known range and the two ranges have a
- non-empty intersection, we can refine the resulting range.
- Since the assert expression creates an equivalency and at the
- same time it asserts a predicate, we can take the intersection of
- the two ranges to get better precision. */
+ /* If VAR already had a known range, it may happen that the new
+ range we have computed and VAR's range are not compatible. For
+ instance,
+
+ if (p_5 == NULL)
+ p_6 = ASSERT_EXPR <p_5, p_5 == NULL>;
+ x_7 = p_6->fld;
+ p_8 = ASSERT_EXPR <p_6, p_6 != NULL>;
+
+ While the above comes from a faulty program, it will cause an ICE
+ later because p_8 and p_6 will have incompatible ranges and at
+ the same time will be considered equivalent. A similar situation
+ would arise from
+
+ if (i_5 > 10)
+ i_6 = ASSERT_EXPR <i_5, i_5 > 10>;
+ if (i_5 < 5)
+ i_7 = ASSERT_EXPR <i_6, i_6 < 5>;
+
+ Again i_6 and i_7 will have incompatible ranges. It would be
+ pointless to try and do anything with i_7's range because
+ anything dominated by 'if (i_5 < 5)' will be optimized away.
+ Note, due to the wa in which simulation proceeds, the statement
+ i_7 = ASSERT_EXPR <...> we would never be visited because the
+ conditional 'if (i_5 < 5)' always evaluates to false. However,
+ this extra check does not hurt and may protect against future
+ changes to VRP that may get into a situation similar to the
+ NULL pointer dereference example.
+
+ Note that these compatibility tests are only needed when dealing
+ with ranges or a mix of range and anti-range. If VAR_VR and VR_P
+ are both anti-ranges, they will always be compatible, because two
+ anti-ranges will always have a non-empty intersection. */
+
var_vr = get_value_range (var);
- if (var_vr->type == VR_RANGE
- && vr_p->type == VR_RANGE
- && value_ranges_intersect_p (var_vr, vr_p))
+
+ /* We may need to make adjustments when VR_P and VAR_VR are numeric
+ ranges or anti-ranges. */
+ if (vr_p->type == VR_VARYING
+ || vr_p->type == VR_UNDEFINED
+ || var_vr->type == VR_VARYING
+ || var_vr->type == VR_UNDEFINED
+ || symbolic_range_p (vr_p)
+ || symbolic_range_p (var_vr))
+ return;
+
+ if (var_vr->type == VR_RANGE && vr_p->type == VR_RANGE)
{
- /* Use the larger of the two minimums. */
- if (compare_values (vr_p->min, var_vr->min) == -1)
- min = var_vr->min;
- else
- min = vr_p->min;
+ /* If the two ranges have a non-empty intersection, we can
+ refine the resulting range. Since the assert expression
+ creates an equivalency and at the same time it asserts a
+ predicate, we can take the intersection of the two ranges to
+ get better precision. */
+ if (value_ranges_intersect_p (var_vr, vr_p))
+ {
+ /* Use the larger of the two minimums. */
+ if (compare_values (vr_p->min, var_vr->min) == -1)
+ min = var_vr->min;
+ else
+ min = vr_p->min;
- /* Use the smaller of the two maximums. */
- if (compare_values (vr_p->max, var_vr->max) == 1)
- max = var_vr->max;
+ /* Use the smaller of the two maximums. */
+ if (compare_values (vr_p->max, var_vr->max) == 1)
+ max = var_vr->max;
+ else
+ max = vr_p->max;
+
+ set_value_range (vr_p, vr_p->type, min, max, vr_p->equiv);
+ }
else
- max = vr_p->max;
+ {
+ /* The two ranges do not intersect, set the new range to
+ VARYING, because we will not be able to do anything
+ meaningful with it. */
+ set_value_range_to_varying (vr_p);
+ }
+ }
+ else if ((var_vr->type == VR_RANGE && vr_p->type == VR_ANTI_RANGE)
+ || (var_vr->type == VR_ANTI_RANGE && vr_p->type == VR_RANGE))
+ {
+ /* A range and an anti-range will cancel each other only if
+ their ends are the same. For instance, in the example above,
+ p_8's range ~[0, 0] and p_6's range [0, 0] are incompatible,
+ so VR_P should be set to VR_VARYING. */
+ if (compare_values (var_vr->min, vr_p->min) == 0
+ && compare_values (var_vr->max, vr_p->max) == 0)
+ set_value_range_to_varying (vr_p);
+ else
+ {
+ tree min, max, anti_min, anti_max, real_min, real_max;
+
+ /* We want to compute the logical AND of the two ranges;
+ there are three cases to consider.
+
+
+ 1. The VR_ANTI_RANGE range is completely within the
+ VR_RANGE and the endpoints of the ranges are
+ different. In that case the resulting range
+ should be whichever range is more precise.
+ Typically that will be the VR_RANGE.
- set_value_range (vr_p, vr_p->type, min, max, vr_p->equiv);
+ 2. The VR_ANTI_RANGE is completely disjoint from
+ the VR_RANGE. In this case the resulting range
+ should be the VR_RANGE.
+
+ 3. There is some overlap between the VR_ANTI_RANGE
+ and the VR_RANGE.
+
+ 3a. If the high limit of the VR_ANTI_RANGE resides
+ within the VR_RANGE, then the result is a new
+ VR_RANGE starting at the high limit of the
+ the VR_ANTI_RANGE + 1 and extending to the
+ high limit of the original VR_RANGE.
+
+ 3b. If the low limit of the VR_ANTI_RANGE resides
+ within the VR_RANGE, then the result is a new
+ VR_RANGE starting at the low limit of the original
+ VR_RANGE and extending to the low limit of the
+ VR_ANTI_RANGE - 1. */
+ if (vr_p->type == VR_ANTI_RANGE)
+ {
+ anti_min = vr_p->min;
+ anti_max = vr_p->max;
+ real_min = var_vr->min;
+ real_max = var_vr->max;
+ }
+ else
+ {
+ anti_min = var_vr->min;
+ anti_max = var_vr->max;
+ real_min = vr_p->min;
+ real_max = vr_p->max;
+ }
+
+
+ /* Case 1, VR_ANTI_RANGE completely within VR_RANGE,
+ not including any endpoints. */
+ 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);
+ }
+ /* Case 2, VR_ANTI_RANGE completely disjoint from
+ VR_RANGE. */
+ else if (compare_values (anti_min, real_max) == 1
+ || compare_values (anti_max, real_min) == -1)
+ {
+ set_value_range (vr_p, VR_RANGE, real_min,
+ real_max, vr_p->equiv);
+ }
+ /* Case 3a, the anti-range extends into the low
+ part of the real range. Thus creating a new
+ low for the real range. */
+ else if ((compare_values (anti_max, real_min) == 1
+ || compare_values (anti_max, real_min) == 0)
+ && compare_values (anti_max, real_max) == -1)
+ {
+ min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+ anti_max,
+ build_int_cst (TREE_TYPE (var_vr->min), 1));
+ max = real_max;
+ set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+ }
+ /* Case 3b, the anti-range extends into the high
+ part of the real range. Thus creating a new
+ higher for the real range. */
+ else if (compare_values (anti_min, real_min) == 1
+ && (compare_values (anti_min, real_max) == -1
+ || compare_values (anti_min, real_max) == 0))
+ {
+ max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+ anti_min,
+ build_int_cst (TREE_TYPE (var_vr->min), 1));
+ min = real_min;
+ set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+ }
+ }
}
}
{
tree res;
- if (flag_wrapv)
- return int_const_binop (code, val1, val2, 0);
+ res = int_const_binop (code, val1, val2, 0);
/* If we are not using wrapping arithmetic, operate symbolically
on -INF and +INF. */
- res = int_const_binop (code, val1, val2, 0);
-
- if (TYPE_UNSIGNED (TREE_TYPE (val1)))
+ if (TYPE_UNSIGNED (TREE_TYPE (val1))
+ || flag_wrapv)
{
int checkz = compare_values (res, val1);
+ bool overflow = false;
- /* Ensure that res = val1 + val2 >= val1
+ /* Ensure that res = val1 [+*] val2 >= val1
or that res = val1 - val2 <= val1. */
- if ((code == PLUS_EXPR && !(checkz == 1 || checkz == 0))
- || (code == MINUS_EXPR && !(checkz == 0 || checkz == -1)))
+ if ((code == PLUS_EXPR
+ && !(checkz == 1 || checkz == 0))
+ || (code == MINUS_EXPR
+ && !(checkz == 0 || checkz == -1)))
+ {
+ overflow = true;
+ }
+ /* Checking for multiplication overflow is done by dividing the
+ output of the multiplication by the first input of the
+ multiplication. If the result of that division operation is
+ not equal to the second input of the multiplication, then the
+ multiplication overflowed. */
+ else if (code == MULT_EXPR && !integer_zerop (val1))
+ {
+ tree tmp = int_const_binop (TRUNC_DIV_EXPR,
+ res,
+ val1, 0);
+ int check = compare_values (tmp, val2);
+
+ if (check != 0)
+ overflow = true;
+ }
+
+ if (overflow)
{
res = copy_node (res);
TREE_OVERFLOW (res) = 1;
}
+
}
- /* If the operation overflowed but neither VAL1 nor VAL2 are
- overflown, return -INF or +INF depending on the operation
- and the combination of signs of the operands. */
else if (TREE_OVERFLOW (res)
&& !TREE_OVERFLOW (val1)
&& !TREE_OVERFLOW (val2))
{
+ /* If the operation overflowed but neither VAL1 nor VAL2 are
+ overflown, return -INF or +INF depending on the operation
+ and the combination of signs of the operands. */
int sgn1 = tree_int_cst_sgn (val1);
int sgn2 = tree_int_cst_sgn (val2);
extract_range_from_binary_expr (value_range_t *vr, tree expr)
{
enum tree_code code = TREE_CODE (expr);
+ enum value_range_type type;
tree op0, op1, min, max;
int cmp;
value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
&& code != ROUND_DIV_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
- && code != TRUTH_XOR_EXPR)
+ && code != TRUTH_OR_EXPR)
{
set_value_range_to_varying (vr);
return;
return;
}
+ /* The type of the resulting value range defaults to VR0.TYPE. */
+ type = vr0.type;
+
/* Refuse to operate on VARYING ranges, ranges of different kinds
- and symbolic ranges. TODO, we may be able to derive anti-ranges
- in some cases. */
- if (vr0.type == VR_VARYING
- || vr1.type == VR_VARYING
- || vr0.type != vr1.type
- || symbolic_range_p (&vr0)
- || symbolic_range_p (&vr1))
+ and symbolic ranges. As an exception, we allow BIT_AND_EXPR
+ because we may be able to derive a useful range even if one of
+ the operands is VR_VARYING or symbolic range. TODO, we may be
+ able to derive anti-ranges in some cases. */
+ if (code != BIT_AND_EXPR
+ && code != TRUTH_AND_EXPR
+ && code != TRUTH_OR_EXPR
+ && (vr0.type == VR_VARYING
+ || vr1.type == VR_VARYING
+ || vr0.type != vr1.type
+ || symbolic_range_p (&vr0)
+ || symbolic_range_p (&vr1)))
{
set_value_range_to_varying (vr);
return;
if (code == TRUTH_ANDIF_EXPR
|| code == TRUTH_ORIF_EXPR
|| code == TRUTH_AND_EXPR
- || code == TRUTH_OR_EXPR
- || code == TRUTH_XOR_EXPR)
+ || code == TRUTH_OR_EXPR)
{
- /* 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);
+ /* If one of the operands is zero, we know that the whole
+ expression evaluates zero. */
+ if (code == TRUTH_AND_EXPR
+ && ((vr0.type == VR_RANGE
+ && integer_zerop (vr0.min)
+ && integer_zerop (vr0.max))
+ || (vr1.type == VR_RANGE
+ && integer_zerop (vr1.min)
+ && integer_zerop (vr1.max))))
+ {
+ type = VR_RANGE;
+ min = max = build_int_cst (TREE_TYPE (expr), 0);
+ }
+ /* If one of the operands is one, we know that the whole
+ expression evaluates one. */
+ else if (code == TRUTH_OR_EXPR
+ && ((vr0.type == VR_RANGE
+ && integer_onep (vr0.min)
+ && integer_onep (vr0.max))
+ || (vr1.type == VR_RANGE
+ && integer_onep (vr1.min)
+ && integer_onep (vr1.max))))
+ {
+ type = VR_RANGE;
+ min = max = build_int_cst (TREE_TYPE (expr), 1);
+ }
+ else if (vr0.type != VR_VARYING
+ && vr1.type != VR_VARYING
+ && vr0.type == vr1.type
+ && !symbolic_range_p (&vr0)
+ && !symbolic_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);
+ }
+ else
+ {
+ set_value_range_to_varying (vr);
+ return;
+ }
}
else if (code == PLUS_EXPR
|| code == MIN_EXPR
max = val[0];
for (i = 1; i < 4; i++)
{
- if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
+ if (!is_gimple_min_invariant (min) || TREE_OVERFLOW (min)
+ || !is_gimple_min_invariant (max) || TREE_OVERFLOW (max))
break;
if (val[i])
{
- if (TREE_OVERFLOW (val[i]))
+ if (!is_gimple_min_invariant (val[i]) || TREE_OVERFLOW (val[i]))
{
/* If we found an overflowed value, set MIN and MAX
to it so that we set the resulting range to
min = vrp_int_const_binop (code, vr0.min, vr1.max);
max = vrp_int_const_binop (code, vr0.max, vr1.min);
}
+ else if (code == BIT_AND_EXPR)
+ {
+ if (vr0.type == VR_RANGE
+ && vr0.min == vr0.max
+ && tree_expr_nonnegative_p (vr0.max)
+ && TREE_CODE (vr0.max) == INTEGER_CST)
+ {
+ min = build_int_cst (TREE_TYPE (expr), 0);
+ max = vr0.max;
+ }
+ else if (vr1.type == VR_RANGE
+ && vr1.min == vr1.max
+ && tree_expr_nonnegative_p (vr1.max)
+ && TREE_CODE (vr1.max) == INTEGER_CST)
+ {
+ type = VR_RANGE;
+ min = build_int_cst (TREE_TYPE (expr), 0);
+ max = vr1.max;
+ }
+ else
+ {
+ set_value_range_to_varying (vr);
+ return;
+ }
+ }
else
gcc_unreachable ();
/* If either MIN or MAX overflowed, then set the resulting range to
VARYING. */
- if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
+ if (!is_gimple_min_invariant (min) || TREE_OVERFLOW (min)
+ || !is_gimple_min_invariant (max) || TREE_OVERFLOW (max))
{
set_value_range_to_varying (vr);
return;
set_value_range_to_varying (vr);
}
else
- set_value_range (vr, vr0.type, min, max, NULL);
+ set_value_range (vr, type, min, max, NULL);
}
/* Refuse to operate on certain unary expressions for which we
cannot easily determine a resulting range. */
if (code == FIX_TRUNC_EXPR
- || code == FIX_CEIL_EXPR
- || code == FIX_FLOOR_EXPR
- || code == FIX_ROUND_EXPR
|| code == FLOAT_EXPR
|| code == BIT_NOT_EXPR
|| code == NON_LVALUE_EXPR
return;
}
- /* Refuse to operate on varying and symbolic ranges. Also, if the
- operand is neither a pointer nor an integral type, set the
- resulting range to VARYING. TODO, in some cases we may be able
- to derive anti-ranges (like nonzero values). */
- if (vr0.type == VR_VARYING
- || (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
- && !POINTER_TYPE_P (TREE_TYPE (op0)))
- || symbolic_range_p (&vr0))
+ /* Refuse to operate on symbolic ranges, or if neither operand is
+ a pointer or integral type. */
+ if ((!INTEGRAL_TYPE_P (TREE_TYPE (op0))
+ && !POINTER_TYPE_P (TREE_TYPE (op0)))
+ || (vr0.type != VR_VARYING
+ && symbolic_range_p (&vr0)))
{
set_value_range_to_varying (vr);
return;
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)
+ if (vr0.type == VR_RANGE
+ || (vr0.type == VR_VARYING
+ && TYPE_PRECISION (outer_type) > TYPE_PRECISION (inner_type)))
{
- tree new_min, new_max;
+ tree new_min, new_max, orig_min, orig_max;
- /* Convert VR0's min/max to OUTER_TYPE. */
- new_min = fold_convert (outer_type, vr0.min);
- new_max = fold_convert (outer_type, vr0.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 VR0's min/max values. */
+ 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, vr0.min)
- && tree_int_cst_equal (new_max, vr0.max)
+ && tree_int_cst_equal (new_min, orig_min)
+ && tree_int_cst_equal (new_max, orig_max)
&& compare_values (new_min, new_max) <= 0
&& compare_values (new_min, new_max) >= -1)
{
}
}
+ /* Conversion of a VR_VARYING value to a wider type can result
+ in a usable range. So wait until after we've handled conversions
+ before dropping the result to VR_VARYING if we had a source
+ operand that is VR_VARYING. */
+ if (vr0.type == VR_VARYING)
+ {
+ set_value_range_to_varying (vr);
+ return;
+ }
+
/* 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)))
{
- /* NEGATE_EXPR flips the range around. */
- min = (vr0.max == TYPE_MAX_VALUE (TREE_TYPE (expr)) && !flag_wrapv)
- ? TYPE_MIN_VALUE (TREE_TYPE (expr))
- : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
+ /* NEGATE_EXPR flips the range around. We need to treat
+ TYPE_MIN_VALUE specially dependent on wrapping, range type
+ and if it was used as minimum or maximum value:
+ -~[MIN, MIN] == ~[MIN, MIN]
+ -[MIN, 0] == [0, MAX] for -fno-wrapv
+ -[MIN, 0] == [0, MIN] for -fwrapv (will be set to varying later) */
+ min = vr0.max == TYPE_MIN_VALUE (TREE_TYPE (expr))
+ ? TYPE_MIN_VALUE (TREE_TYPE (expr))
+ : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max);
+
+ max = vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr))
+ ? (vr0.type == VR_ANTI_RANGE || flag_wrapv
+ ? TYPE_MIN_VALUE (TREE_TYPE (expr))
+ : TYPE_MAX_VALUE (TREE_TYPE (expr)))
+ : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
- max = (vr0.min == TYPE_MIN_VALUE (TREE_TYPE (expr)) && !flag_wrapv)
- ? TYPE_MAX_VALUE (TREE_TYPE (expr))
- : fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min);
+ }
+ else if (code == NEGATE_EXPR
+ && TYPE_UNSIGNED (TREE_TYPE (expr)))
+ {
+ 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);
+ }
+ else
+ {
+ if (range_is_null (&vr0))
+ set_value_range_to_null (vr, TREE_TYPE (expr));
+ else
+ set_value_range_to_varying (vr);
+ return;
+ }
}
else if (code == ABS_EXPR
&& !TYPE_UNSIGNED (TREE_TYPE (expr)))
extract_range_from_comparison (vr, expr);
else if (is_gimple_min_invariant (expr))
set_value_range (vr, VR_RANGE, expr, expr, NULL);
- else if (vrp_expr_computes_nonzero (expr))
- set_value_range_to_nonnull (vr, TREE_TYPE (expr));
else
set_value_range_to_varying (vr);
+
+ /* If we got a varying range from the tests above, try a final
+ time to derive a nonnegative or nonzero range. This time
+ relying primarily on generic routines in fold in conjunction
+ with range data. */
+ if (vr->type == VR_VARYING)
+ {
+ if (INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ && vrp_expr_computes_nonnegative (expr))
+ set_value_range_to_nonnegative (vr, TREE_TYPE (expr));
+ else if (vrp_expr_computes_nonzero (expr))
+ set_value_range_to_nonnull (vr, TREE_TYPE (expr));
+ }
}
/* Given a range VR, a LOOP and a variable VAR, determine whether it
adjust_range_with_scev (value_range_t *vr, struct loop *loop, tree stmt,
tree var)
{
- tree init, step, chrec;
- bool init_is_max, unknown_max;
+ tree init, step, chrec, tmin, tmax, min, max, type;
+ enum ev_direction dir;
/* TODO. Don't adjust anti-ranges. An anti-range may provide
better opportunities than a regular range, but I'm not sure. */
step = evolution_part_in_loop_num (chrec, loop->num);
/* If STEP is symbolic, we can't know whether INIT will be the
- minimum or maximum value in the range. */
+ minimum or maximum value in the range. Also, unless INIT is
+ a simple expression, compare_values and possibly other functions
+ in tree-vrp won't be able to handle it. */
if (step == NULL_TREE
- || !is_gimple_min_invariant (step))
+ || !is_gimple_min_invariant (step)
+ || !valid_value_p (init))
return;
- /* Do not adjust ranges when chrec may wrap. */
- if (scev_probably_wraps_p (chrec_type (chrec), init, step, stmt,
- cfg_loops->parray[CHREC_VARIABLE (chrec)],
- &init_is_max, &unknown_max)
- || unknown_max)
+ dir = scev_direction (chrec);
+ if (/* Do not adjust ranges if we do not know whether the iv increases
+ or decreases, ... */
+ dir == EV_DIR_UNKNOWN
+ /* ... or if it may wrap. */
+ || scev_probably_wraps_p (init, step, stmt,
+ current_loops->parray[CHREC_VARIABLE (chrec)],
+ true))
return;
- if (!POINTER_TYPE_P (TREE_TYPE (init))
- && (vr->type == VR_VARYING || vr->type == VR_UNDEFINED))
+ type = TREE_TYPE (var);
+ if (POINTER_TYPE_P (type) || !TYPE_MIN_VALUE (type))
+ tmin = lower_bound_in_type (type, type);
+ else
+ tmin = TYPE_MIN_VALUE (type);
+ if (POINTER_TYPE_P (type) || !TYPE_MAX_VALUE (type))
+ tmax = upper_bound_in_type (type, type);
+ else
+ tmax = TYPE_MAX_VALUE (type);
+
+ if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
{
+ min = tmin;
+ max = tmax;
+
/* For VARYING or UNDEFINED ranges, just about anything we get
from scalar evolutions should be better. */
- if (init_is_max)
- set_value_range (vr, VR_RANGE, TYPE_MIN_VALUE (TREE_TYPE (init)),
- init, vr->equiv);
+
+ if (dir == EV_DIR_DECREASES)
+ max = init;
else
- set_value_range (vr, VR_RANGE, init, TYPE_MAX_VALUE (TREE_TYPE (init)),
- vr->equiv);
+ min = init;
+
+ /* If we would create an invalid range, then just assume we
+ know absolutely nothing. This may be over-conservative,
+ but it's clearly safe, and should happen only in unreachable
+ parts of code, or for invalid programs. */
+ if (compare_values (min, max) == 1)
+ return;
+
+ set_value_range (vr, VR_RANGE, min, max, vr->equiv);
}
else if (vr->type == VR_RANGE)
{
- tree min = vr->min;
- tree max = vr->max;
+ min = vr->min;
+ max = vr->max;
- if (init_is_max)
+ if (dir == EV_DIR_DECREASES)
{
/* INIT is the maximum value. If INIT is lower than VR->MAX
but no smaller than VR->MIN, set VR->MAX to INIT. */
max = init;
/* If we just created an invalid range with the minimum
- greater than the maximum, take the minimum all the
- way to -INF. */
+ greater than the maximum, we fail conservatively.
+ This should happen only in unreachable
+ parts of code, or for invalid programs. */
if (compare_values (min, max) == 1)
- min = TYPE_MIN_VALUE (TREE_TYPE (min));
+ return;
}
}
else
{
min = init;
- /* If we just created an invalid range with the minimum
- greater than the maximum, take the maximum all the
- way to +INF. */
+ /* Again, avoid creating invalid range by failing. */
if (compare_values (min, max) == 1)
- max = TYPE_MAX_VALUE (TREE_TYPE (max));
+ return;
}
}
else if (cmp_min != -2 && cmp_max != -2)
return boolean_false_node;
}
+ /* If [V0_MIN, V1_MAX] < [V1_MIN, V1_MAX] then V0 != V1. */
+ else if (compare_values (vr0->min, vr1->max) == 1
+ || compare_values (vr1->min, vr0->max) == 1)
+ return boolean_false_node;
return NULL_TREE;
}
debug_value_range (value_range_t *vr)
{
dump_value_range (stderr, vr);
+ fprintf (stderr, "\n");
}
if (COMPARISON_CLASS_P (cond))
{
- tree a = build (ASSERT_EXPR, TREE_TYPE (v), v, cond);
- assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, a);
+ tree a = build2 (ASSERT_EXPR, TREE_TYPE (v), v, cond);
+ assertion = build2 (MODIFY_EXPR, TREE_TYPE (v), n, a);
}
else if (TREE_CODE (cond) == TRUTH_NOT_EXPR)
{
/* Given !V, build the assignment N = false. */
tree op0 = TREE_OPERAND (cond, 0);
gcc_assert (op0 == v);
- assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, boolean_false_node);
+ assertion = build2 (MODIFY_EXPR, TREE_TYPE (v), n, boolean_false_node);
}
else if (TREE_CODE (cond) == SSA_NAME)
{
/* Given V, build the assignment N = true. */
gcc_assert (v == cond);
- assertion = build (MODIFY_EXPR, TREE_TYPE (v), n, boolean_true_node);
+ assertion = build2 (MODIFY_EXPR, TREE_TYPE (v), n, boolean_true_node);
}
else
gcc_unreachable ();
if (tree_could_throw_p (stmt))
return false;
- if (POINTER_TYPE_P (TREE_TYPE (op)))
+ /* If STMT is the last statement of a basic block with no
+ successors, there is no point inferring anything about any of its
+ operands. We would not be able to find a proper insertion point
+ for the assertion, anyway. */
+ if (stmt_ends_bb_p (stmt) && EDGE_COUNT (bb_for_stmt (stmt)->succs) == 0)
+ return false;
+
+ /* We can only assume that a pointer dereference will yield
+ non-NULL if -fdelete-null-pointer-checks is enabled. */
+ if (flag_delete_null_pointer_checks && POINTER_TYPE_P (TREE_TYPE (op)))
{
bool is_store;
unsigned num_uses, num_derefs;
count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
- if (num_derefs > 0 && flag_delete_null_pointer_checks)
+ if (num_derefs > 0)
{
- /* We can only assume that a pointer dereference will yield
- non-NULL if -fdelete-null-pointer-checks is enabled. */
*val_p = build_int_cst (TREE_TYPE (op), 0);
*comp_code_p = NE_EXPR;
return true;
/* If we didn't find an assertion already registered for
NAME COMP_CODE VAL, add a new one at the end of the list of
assertions associated with NAME. */
- n = xmalloc (sizeof (*n));
+ n = XNEW (struct assert_locus_d);
n->bb = dest_bb;
n->e = e;
n->si = si;
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.
-/* Try to register an edge assertion for SSA name NAME on edge E for
- the conditional jump pointed to by SI. Return true if an assertion
- for NAME could be registered. */
+ 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
-register_edge_assert_for (tree name, edge e, block_stmt_iterator si)
+extract_code_and_val_from_cond (tree name, tree cond, bool invert,
+ enum tree_code *code_p, tree *val_p)
{
- tree val, stmt;
enum tree_code comp_code;
+ tree val;
- stmt = bsi_stmt (si);
+ /* Predicates may be a single SSA name or NAME OP VAL. */
+ if (cond == name)
+ {
+ /* 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;
+ }
+ 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);
+ }
+ else
+ {
+ /* 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);
+ }
+
+ /* 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;
+}
+
+/* OP is an operand of a truth value expression which is known to have
+ a particular value. Register any asserts for OP and for any
+ operands in OP's defining statement.
+
+ If CODE is EQ_EXPR, then we want to register OP is zero (false),
+ if CODE is NE_EXPR, then we want to register OP is nonzero (true). */
+
+static bool
+register_edge_assert_for_1 (tree op, enum tree_code code,
+ edge e, block_stmt_iterator bsi)
+{
+ bool retval = false;
+ tree op_def, rhs, val;
+
+ /* We only care about SSA_NAMEs. */
+ if (TREE_CODE (op) != SSA_NAME)
+ return false;
+
+ /* We know that OP will have a zero or nonzero value. If OP is used
+ more than once go ahead and register an assert for OP.
+
+ The FOUND_IN_SUBGRAPH support is not helpful in this situation as
+ it will always be set for OP (because OP is used in a COND_EXPR in
+ the subgraph). */
+ if (!has_single_use (op))
+ {
+ val = build_int_cst (TREE_TYPE (op), 0);
+ register_new_assert_for (op, code, val, NULL, e, bsi);
+ retval = true;
+ }
+
+ /* Now look at how OP is set. If it's set from a comparison,
+ a truth operation or some bit operations, then we may be able
+ to register information about the operands of that assignment. */
+ op_def = SSA_NAME_DEF_STMT (op);
+ if (TREE_CODE (op_def) != MODIFY_EXPR)
+ return retval;
+
+ rhs = TREE_OPERAND (op_def, 1);
+
+ if (COMPARISON_CLASS_P (rhs))
+ {
+ bool invert = (code == EQ_EXPR ? true : false);
+ 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;
+ }
+ }
+ else if ((code == NE_EXPR
+ && (TREE_CODE (rhs) == TRUTH_AND_EXPR
+ || TREE_CODE (rhs) == BIT_AND_EXPR))
+ || (code == EQ_EXPR
+ && (TREE_CODE (rhs) == TRUTH_OR_EXPR
+ || TREE_CODE (rhs) == BIT_IOR_EXPR)))
+ {
+ /* Recurse on each operand. */
+ retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 0),
+ code, e, bsi);
+ retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 1),
+ code, e, bsi);
+ }
+ else if (TREE_CODE (rhs) == TRUTH_NOT_EXPR)
+ {
+ /* Recurse, flipping CODE. */
+ code = invert_tree_comparison (code, false);
+ retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 0),
+ code, e, bsi);
+ }
+ else if (TREE_CODE (rhs) == SSA_NAME)
+ {
+ /* Recurse through the copy. */
+ retval |= register_edge_assert_for_1 (rhs, code, e, bsi);
+ }
+ else if (TREE_CODE (rhs) == NOP_EXPR
+ || TREE_CODE (rhs) == CONVERT_EXPR
+ || TREE_CODE (rhs) == VIEW_CONVERT_EXPR
+ || TREE_CODE (rhs) == NON_LVALUE_EXPR)
+ {
+ /* Recurse through the type conversion. */
+ retval |= register_edge_assert_for_1 (TREE_OPERAND (rhs, 0),
+ code, e, bsi);
+ }
+
+ return retval;
+}
+
+/* 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 SI.
+ 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)
+{
+ tree val;
+ enum tree_code comp_code;
+ bool retval = false;
+ bool is_else_edge = (e->flags & EDGE_FALSE_VALUE) != 0;
/* Do not attempt to infer anything in names that flow through
abnormal edges. */
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
return false;
- /* If NAME was not found in the sub-graph reachable from E, then
- there's nothing to do. */
- if (!TEST_BIT (found_in_subgraph, SSA_NAME_VERSION (name)))
+ if (!extract_code_and_val_from_cond (name, cond, is_else_edge,
+ &comp_code, &val))
return false;
- /* We found a use of NAME in the sub-graph rooted at E->DEST.
- Register an assertion for NAME according to the value that NAME
- takes on edge E. */
- if (TREE_CODE (stmt) == COND_EXPR)
+ /* 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)))
{
- /* If BB ends in a COND_EXPR then NAME then we should insert
- the original predicate on EDGE_TRUE_VALUE and the
- opposite predicate on EDGE_FALSE_VALUE. */
- tree cond = COND_EXPR_COND (stmt);
- bool is_else_edge = (e->flags & EDGE_FALSE_VALUE) != 0;
+ register_new_assert_for (name, comp_code, val, NULL, e, si);
+ retval = true;
+ }
- /* Predicates may be a single SSA name or NAME OP VAL. */
- if (cond == name)
- {
- /* 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 = (is_else_edge) ? boolean_false_node : boolean_true_node;
- }
- 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);
- }
- else
- {
- /* 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);
- }
+ /* 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
+ for SSA_NAMEs which flow into COND. */
- /* If we are inserting the assertion on the ELSE edge, we
- need to invert the sign comparison. */
- if (is_else_edge)
- comp_code = invert_tree_comparison (comp_code, 0);
+ /* In the case of NAME == 1 or NAME != 0, for TRUTH_AND_EXPR defining
+ statement of NAME we can assert both operands of the TRUTH_AND_EXPR
+ have non-zero value. */
+ if (((comp_code == EQ_EXPR && integer_onep (val))
+ || (comp_code == NE_EXPR && integer_zerop (val))))
+ {
+ tree def_stmt = SSA_NAME_DEF_STMT (name);
+
+ if (TREE_CODE (def_stmt) == MODIFY_EXPR
+ && (TREE_CODE (TREE_OPERAND (def_stmt, 1)) == TRUTH_AND_EXPR
+ || TREE_CODE (TREE_OPERAND (def_stmt, 1)) == BIT_AND_EXPR))
+ {
+ tree op0 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+ tree op1 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 1);
+ retval |= register_edge_assert_for_1 (op0, NE_EXPR, e, si);
+ retval |= register_edge_assert_for_1 (op1, NE_EXPR, e, si);
}
}
- else
+
+ /* In the case of NAME == 0 or NAME != 1, for TRUTH_OR_EXPR defining
+ statement of NAME we can assert both operands of the TRUTH_OR_EXPR
+ have zero value. */
+ if (((comp_code == EQ_EXPR && integer_zerop (val))
+ || (comp_code == NE_EXPR && integer_onep (val))))
{
- /* FIXME. Handle SWITCH_EXPR. */
- gcc_unreachable ();
+ tree def_stmt = SSA_NAME_DEF_STMT (name);
+
+ if (TREE_CODE (def_stmt) == MODIFY_EXPR
+ && (TREE_CODE (TREE_OPERAND (def_stmt, 1)) == TRUTH_OR_EXPR
+ || TREE_CODE (TREE_OPERAND (def_stmt, 1)) == BIT_IOR_EXPR))
+ {
+ tree op0 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+ tree op1 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 1);
+ retval |= register_edge_assert_for_1 (op0, EQ_EXPR, e, si);
+ retval |= register_edge_assert_for_1 (op1, EQ_EXPR, e, si);
+ }
}
- register_new_assert_for (name, comp_code, val, NULL, e, si);
- return true;
+ return retval;
}
static bool find_assert_locations (basic_block bb);
/* Determine whether the outgoing edges of BB should receive an
- ASSERT_EXPR for each of the operands of BB's last statement. The
- last statement of BB must be a COND_EXPR or a SWITCH_EXPR.
+ ASSERT_EXPR for each of the operands of BB's LAST statement.
+ The last statement of BB must be a COND_EXPR or a SWITCH_EXPR.
If any of the sub-graphs rooted at BB have an interesting use of
the predicate operands, an assert location node is added to the
list of assertions for the corresponding operands. */
static bool
-find_conditional_asserts (basic_block bb)
+find_conditional_asserts (basic_block bb, tree last)
{
bool need_assert;
- block_stmt_iterator last_si;
- tree op, last;
+ block_stmt_iterator bsi;
+ tree op;
edge_iterator ei;
edge e;
ssa_op_iter iter;
need_assert = false;
- last_si = bsi_last (bb);
- last = bsi_stmt (last_si);
+ bsi = bsi_for_stmt (last);
/* Look for uses of the operands in each of the sub-graphs
rooted at BB. We need to check each of the outgoing edges
/* Remove the COND_EXPR operands from the FOUND_IN_SUBGRAPH bitmap.
Otherwise, when we finish traversing each of the sub-graphs, we
won't know whether the variables were found in the sub-graphs or
- if they had been found in a block upstream from BB. */
+ if they had been found in a block upstream from BB.
+
+ This is actually a bad idea is some cases, particularly jump
+ threading. Consider a CFG like the following:
+
+ 0
+ /|
+ 1 |
+ \|
+ 2
+ / \
+ 3 4
+
+ Assume that one or more operands in the conditional at the
+ end of block 0 are used in a conditional in block 2, but not
+ anywhere in block 1. In this case we will not insert any
+ assert statements in block 1, which may cause us to miss
+ opportunities to optimize, particularly for jump threading. */
FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE)
RESET_BIT (found_in_subgraph, SSA_NAME_VERSION (op));
/* 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, last_si);
+ need_assert |= register_edge_assert_for (op, e, bsi,
+ COND_EXPR_COND (last));
}
/* Finally, indicate that we have found the operands in the
operands it was looking for was present in the sub-graph. */
SET_BIT (found_in_subgraph, SSA_NAME_VERSION (op));
- /* If OP is used only once, namely in this STMT, don't
- bother creating an ASSERT_EXPR for it. Such an
- ASSERT_EXPR would do nothing but increase compile time.
- Experiments show that with this simple check, we can save
- more than 20% of ASSERT_EXPRs. */
- if (has_single_use (op))
- continue;
-
/* If OP is used in such a way that we can infer a value
range for it, and we don't find a previous assertion for
it, create a new assertion location node for OP. */
if (infer_value_range (stmt, op, &comp_code, &value))
{
- register_new_assert_for (op, comp_code, value, bb, NULL, si);
- need_assert = true;
+ /* If we are able to infer a nonzero value range for OP,
+ then walk backwards through the use-def chain to see if OP
+ was set via a typecast.
+
+ If so, then we can also infer a nonzero value range
+ for the operand of the NOP_EXPR. */
+ if (comp_code == NE_EXPR && integer_zerop (value))
+ {
+ tree t = op;
+ tree def_stmt = SSA_NAME_DEF_STMT (t);
+
+ while (TREE_CODE (def_stmt) == MODIFY_EXPR
+ && TREE_CODE (TREE_OPERAND (def_stmt, 1)) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0)) == SSA_NAME
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0))))
+ {
+ t = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+ def_stmt = SSA_NAME_DEF_STMT (t);
+
+ /* Note we want to register the assert for the
+ operand of the NOP_EXPR after SI, not after the
+ conversion. */
+ if (! has_single_use (t))
+ {
+ register_new_assert_for (t, comp_code, value,
+ bb, NULL, si);
+ need_assert = true;
+ }
+ }
+ }
+
+ /* If OP is used only once, namely in this STMT, don't
+ bother creating an ASSERT_EXPR for it. Such an
+ 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);
+ need_assert = true;
+ }
}
}
&& TREE_CODE (last) == COND_EXPR
&& !fp_predicate (COND_EXPR_COND (last))
&& !ZERO_SSA_OPERANDS (last, SSA_OP_USE))
- need_assert |= find_conditional_asserts (bb);
+ need_assert |= find_conditional_asserts (bb, last);
/* Recurse into the dominator children of BB. */
for (son = first_dom_son (CDI_DOMINATORS, bb);
edge_iterator ei;
edge e;
- cond = build (loc->comp_code, boolean_type_node, name, loc->val);
+ cond = build2 (loc->comp_code, boolean_type_node, name, loc->val);
assert_expr = build_assert_expr_for (cond, name);
if (loc->e)
sbitmap_zero (blocks_visited);
need_assert_for = BITMAP_ALLOC (NULL);
- asserts_for = xmalloc (num_ssa_names * sizeof (assert_locus_t));
- memset (asserts_for, 0, num_ssa_names * sizeof (assert_locus_t));
+ asserts_for = XCNEWVEC (assert_locus_t, num_ssa_names);
calculate_dominance_info (CDI_DOMINATORS);
for (si = bsi_start (bb); !bsi_end_p (si);)
{
tree stmt = bsi_stmt (si);
+ tree use_stmt;
if (TREE_CODE (stmt) == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR)
{
- tree rhs = TREE_OPERAND (stmt, 1);
+ tree rhs = TREE_OPERAND (stmt, 1), var;
tree cond = fold (ASSERT_EXPR_COND (rhs));
use_operand_p use_p;
imm_use_iterator iter;
gcc_assert (cond != boolean_false_node);
- TREE_OPERAND (stmt, 1) = ASSERT_EXPR_VAR (rhs);
- update_stmt (stmt);
- /* The statement is now a copy. Propagate the RHS into
- every use of the LHS. */
- FOR_EACH_IMM_USE_SAFE (use_p, iter, TREE_OPERAND (stmt, 0))
- {
- SET_USE (use_p, ASSERT_EXPR_VAR (rhs));
- update_stmt (USE_STMT (use_p));
- }
+ /* Propagate the RHS into every use of the LHS. */
+ var = ASSERT_EXPR_VAR (rhs);
+ FOR_EACH_IMM_USE_STMT (use_stmt, iter, TREE_OPERAND (stmt, 0))
+ FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+ {
+ SET_USE (use_p, var);
+ gcc_assert (TREE_CODE (var) == SSA_NAME);
+ }
/* And finally, remove the copy, it is not needed. */
- bsi_remove (&si);
+ bsi_remove (&si, true);
}
else
bsi_next (&si);
else if (TREE_CODE (stmt) == MODIFY_EXPR)
{
tree lhs = TREE_OPERAND (stmt, 0);
+ tree rhs = TREE_OPERAND (stmt, 1);
+ /* In general, assignments with virtual operands are not useful
+ for deriving ranges, with the obvious exception of calls to
+ builtin functions. */
if (TREE_CODE (lhs) == SSA_NAME
&& (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|| POINTER_TYPE_P (TREE_TYPE (lhs)))
- && ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
+ && ((TREE_CODE (rhs) == CALL_EXPR
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0))
+ && DECL_IS_BUILTIN (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)))
+ || ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)))
return true;
}
else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
{
basic_block bb;
- vr_value = xmalloc (num_ssa_names * sizeof (value_range_t *));
- memset (vr_value, 0, num_ssa_names * sizeof (value_range_t *));
+ vr_value = XCNEWVEC (value_range_t *, num_ssa_names);
FOR_EACH_BB (bb)
{
/* We only keep track of ranges in integral and pointer types. */
if (TREE_CODE (lhs) == SSA_NAME
- && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ && ((INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ /* It is valid to have NULL MIN/MAX values on a type. See
+ build_range_type. */
+ && TYPE_MIN_VALUE (TREE_TYPE (lhs))
+ && TYPE_MAX_VALUE (TREE_TYPE (lhs)))
|| POINTER_TYPE_P (TREE_TYPE (lhs))))
{
struct loop *l;
/* If STMT is inside a loop, we may be able to know something
else about the range of LHS by examining scalar evolution
information. */
- if (cfg_loops && (l = loop_containing_stmt (stmt)))
+ if (current_loops && (l = loop_containing_stmt (stmt)))
adjust_range_with_scev (&new_vr, l, stmt, lhs);
if (update_value_range (lhs, &new_vr))
t = compare_range_with_value (comp, &equiv_vr, val);
if (t)
{
- /* All the ranges should compare the same against VAL. */
- gcc_assert (retval == NULL || t == retval);
+ /* If we get different answers from different members
+ of the equivalence set this check must be in a dead
+ code region. Folding it to a trap representation
+ would be correct here. For now just return don't-know. */
+ if (retval != NULL
+ && t != retval)
+ {
+ retval = NULL_TREE;
+ break;
+ }
retval = t;
}
}
t = compare_ranges (comp, &vr1, &vr2);
if (t)
{
- /* All the ranges in the equivalent sets should compare
- the same. */
- gcc_assert (retval == NULL || t == retval);
+ /* If we get different answers from different members
+ of the equivalence set this check must be in a dead
+ code region. Folding it to a trap representation
+ would be correct here. For now just return don't-know. */
+ if (retval != NULL
+ && t != retval)
+ {
+ bitmap_clear_bit (e1, SSA_NAME_VERSION (n1));
+ bitmap_clear_bit (e2, SSA_NAME_VERSION (n2));
+ return NULL_TREE;
+ }
retval = t;
}
}
}
ann = stmt_ann (stmt);
- if (TREE_CODE (stmt) == MODIFY_EXPR
- && ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
- return vrp_visit_assignment (stmt, output_p);
+ if (TREE_CODE (stmt) == MODIFY_EXPR)
+ {
+ tree rhs = TREE_OPERAND (stmt, 1);
+
+ /* In general, assignments with virtual operands are not useful
+ for deriving ranges, with the obvious exception of calls to
+ builtin functions. */
+ if ((TREE_CODE (rhs) == CALL_EXPR
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0))
+ && DECL_IS_BUILTIN (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)))
+ || 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)
return vrp_visit_cond_stmt (stmt, taken_edge_p);
&& !symbolic_range_p (vr1)
&& !value_ranges_intersect_p (vr0, vr1))
{
+ /* Copy most of VR1 into VR0. Don't copy VR1's equivalence
+ set. We need to compute the intersection of the two
+ equivalence sets. */
if (vr1->type == VR_ANTI_RANGE)
- copy_value_range (vr0, vr1);
+ set_value_range (vr0, vr1->type, vr1->min, vr1->max, vr0->equiv);
/* The resulting set of equivalences is the intersection of
the two sets. */
no_meet:
/* The two range VR0 and VR1 do not meet. Before giving up and
setting the result to VARYING, see if we can at least derive a
- useful anti-range. */
+ useful anti-range. FIXME, all this nonsense about distinguishing
+ anti-ranges from ranges is necessary because of the odd
+ semantics of range_includes_zero_p and friends. */
if (!symbolic_range_p (vr0)
- && !range_includes_zero_p (vr0)
+ && ((vr0->type == VR_RANGE && !range_includes_zero_p (vr0))
+ || (vr0->type == VR_ANTI_RANGE && range_includes_zero_p (vr0)))
&& !symbolic_range_p (vr1)
- && !range_includes_zero_p (vr1))
- set_value_range_to_nonnull (vr0, TREE_TYPE (vr0->min));
+ && ((vr1->type == VR_RANGE && !range_includes_zero_p (vr1))
+ || (vr1->type == VR_ANTI_RANGE && range_includes_zero_p (vr1))))
+ {
+ set_value_range_to_nonnull (vr0, TREE_TYPE (vr0->min));
+
+ /* Since this meet operation did not result from the meeting of
+ two equivalent names, VR0 cannot have any equivalences. */
+ if (vr0->equiv)
+ bitmap_clear (vr0->equiv);
+ }
else
set_value_range_to_varying (vr0);
}
/* To prevent infinite iterations in the algorithm, derive ranges
when the new value is slightly bigger or smaller than the
previous one. */
- if (lhs_vr->type == VR_RANGE)
+ if (lhs_vr->type == VR_RANGE && vr_result.type == VR_RANGE)
{
if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
{
if (cond_code == GT_EXPR)
{
tree one = build_int_cst (TREE_TYPE (op0), 1);
- max = fold_build2 (PLUS_EXPR, TREE_TYPE (op0), max, one);
+ min = fold_build2 (PLUS_EXPR, TREE_TYPE (op0), min, one);
}
}
else
max = vr->max;
- /* If the new min/max values have converged to a
- single value, then there is only one value which
- can satisfy the condition, return that value. */
- if (min == max && is_gimple_min_invariant (min))
+ /* If the new min/max values have converged to a single value,
+ then there is only one value which can satisfy the condition,
+ return that value. */
+ if (operand_equal_p (min, max, 0) && is_gimple_min_invariant (min))
return min;
}
return NULL;
}
COND_EXPR_COND (stmt)
- = build (EQ_EXPR, boolean_type_node, op0, new);
+ = build2 (EQ_EXPR, boolean_type_node, op0, new);
update_stmt (stmt);
if (dump_file)
}
COND_EXPR_COND (stmt)
- = build (NE_EXPR, boolean_type_node, op0, new);
+ = build2 (NE_EXPR, boolean_type_node, op0, new);
update_stmt (stmt);
if (dump_file)
}
}
+/* Stack of dest,src equivalency pairs that need to be restored after
+ each attempt to thread a block's incoming edge to an outgoing edge.
+
+ A NULL entry is used to mark the end of pairs which need to be
+ restored. */
+static VEC(tree,heap) *stack;
+
+/* A trivial wrapper so that we can present the generic jump
+ threading code with a simple API for simplifying statements. */
+static tree
+simplify_stmt_for_jump_threading (tree stmt)
+{
+ /* We only use VRP information to simplify conditionals. This is
+ overly conservative, but it's unclear if doing more would be
+ worth the compile time cost. */
+ if (TREE_CODE (stmt) != COND_EXPR)
+ return NULL;
+
+ return vrp_evaluate_conditional (COND_EXPR_COND (stmt), true);
+}
+
+/* Blocks which have more than one predecessor and more than
+ one successor present jump threading opportunities. ie,
+ when the block is reached from a specific predecessor, we
+ may be able to determine which of the outgoing edges will
+ be traversed. When this optimization applies, we are able
+ to avoid conditionals at runtime and we may expose secondary
+ optimization opportunities.
+
+ This routine is effectively a driver for the generic jump
+ threading code. It basically just presents the generic code
+ with edges that may be suitable for jump threading.
+
+ Unlike DOM, we do not iterate VRP if jump threading was successful.
+ While iterating may expose new opportunities for VRP, it is expected
+ those opportunities would be very limited and the compile time cost
+ to expose those opportunities would be significant.
+
+ As jump threading opportunities are discovered, they are registered
+ for later realization. */
+
+static void
+identify_jump_threads (void)
+{
+ basic_block bb;
+ tree dummy;
+
+ /* Ugh. When substituting values earlier in this pass we can
+ wipe the dominance information. So rebuild the dominator
+ information as we need it within the jump threading code. */
+ calculate_dominance_info (CDI_DOMINATORS);
+
+ /* We do not allow VRP information to be used for jump threading
+ across a back edge in the CFG. Otherwise it becomes too
+ difficult to avoid eliminating loop exit tests. Of course
+ EDGE_DFS_BACK is not accurate at this time so we have to
+ recompute it. */
+ mark_dfs_back_edges ();
+
+ /* Allocate our unwinder stack to unwind any temporary equivalences
+ that might be recorded. */
+ stack = VEC_alloc (tree, heap, 20);
+
+ /* To avoid lots of silly node creation, we create a single
+ conditional and just modify it in-place when attempting to
+ thread jumps. */
+ dummy = build2 (EQ_EXPR, boolean_type_node, NULL, NULL);
+ dummy = build3 (COND_EXPR, void_type_node, dummy, NULL, NULL);
+
+ /* Walk through all the blocks finding those which present a
+ potential jump threading opportunity. We could set this up
+ as a dominator walker and record data during the walk, but
+ I doubt it's worth the effort for the classes of jump
+ threading opportunities we are trying to identify at this
+ point in compilation. */
+ FOR_EACH_BB (bb)
+ {
+ tree last, cond;
+
+ /* If the generic jump threading code does not find this block
+ interesting, then there is nothing to do. */
+ if (! potentially_threadable_block (bb))
+ continue;
+
+ /* We only care about blocks ending in a COND_EXPR. While there
+ may be some value in handling SWITCH_EXPR here, I doubt it's
+ terribly important. */
+ last = bsi_stmt (bsi_last (bb));
+ if (TREE_CODE (last) != COND_EXPR)
+ continue;
+
+ /* We're basically looking for any kind of conditional with
+ integral type arguments. */
+ cond = COND_EXPR_COND (last);
+ if ((TREE_CODE (cond) == SSA_NAME
+ && INTEGRAL_TYPE_P (TREE_TYPE (cond)))
+ || (COMPARISON_CLASS_P (cond)
+ && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 0)))
+ && (TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME
+ || is_gimple_min_invariant (TREE_OPERAND (cond, 1)))
+ && 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
+ each predecessor, see if we can thread it to a specific
+ successor. */
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ /* Do not thread across back edges or abnormal edges
+ in the CFG. */
+ if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+ continue;
+
+ thread_across_edge (dummy, e, true,
+ &stack,
+ simplify_stmt_for_jump_threading);
+ }
+ }
+ }
+
+ /* We do not actually update the CFG or SSA graphs at this point as
+ ASSERT_EXPRs are still in the IL and cfg cleanup code does not yet
+ handle ASSERT_EXPRs gracefully. */
+}
+
+/* We identified all the jump threading opportunities earlier, but could
+ not transform the CFG at that time. This routine transforms the
+ CFG and arranges for the dominator tree to be rebuilt if necessary.
+
+ Note the SSA graph update will occur during the normal TODO
+ processing by the pass manager. */
+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, to safely do that we must clean up the CFG first. */
+ if (cfg_altered)
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ cleanup_tree_cfg ();
+ calculate_dominance_info (CDI_DOMINATORS);
+ }
+ VEC_free (tree, heap, stack);
+}
/* Traverse all the blocks folding conditionals with known ranges. */
/* We may have ended with ranges that have exactly one value. Those
values can be substituted as any other copy/const propagated
value using substitute_and_fold. */
- single_val_range = xmalloc (num_ssa_names * sizeof (*single_val_range));
- memset (single_val_range, 0, num_ssa_names * sizeof (*single_val_range));
+ single_val_range = XCNEWVEC (prop_value_t, num_ssa_names);
do_value_subst_p = false;
for (i = 0; i < num_ssa_names; i++)
substitute_and_fold (single_val_range, true);
+ /* We must identify jump threading opportunities before we release
+ the datastructures built by VRP. */
+ identify_jump_threads ();
+
/* Free allocated memory. */
for (i = 0; i < num_ssa_names; i++)
if (vr_value[i])
free (single_val_range);
free (vr_value);
+
+ /* So that we can distinguish between VRP data being available
+ and not available. */
+ vr_value = NULL;
}
DON'T KNOW. In the future, it may be worthwhile to propagate
probabilities to aid branch prediction. */
-static void
+static unsigned int
execute_vrp (void)
{
insert_range_assertions ();
- cfg_loops = loop_optimizer_init (NULL);
- if (cfg_loops)
- scev_initialize (cfg_loops);
+ loop_optimizer_init (LOOPS_NORMAL);
+ if (current_loops)
+ scev_initialize (current_loops);
vrp_initialize ();
ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
vrp_finalize ();
- if (cfg_loops)
+ if (current_loops)
{
scev_finalize ();
- loop_optimizer_finalize (cfg_loops, NULL);
- current_loops = NULL;
+ loop_optimizer_finalize ();
}
+ /* ASSERT_EXPRs must be removed before finalizing jump threads
+ as finalizing jump threads calls the CFG cleanup code which
+ does not properly handle ASSERT_EXPRs. */
remove_range_assertions ();
+
+ /* If we exposed any new variables, go ahead and put them into
+ SSA form now, before we handle jump threading. This simplifies
+ interactions between rewriting of _DECL nodes into SSA form
+ and rewriting SSA_NAME nodes into SSA form after block
+ duplication and CFG manipulation. */
+ update_ssa (TODO_update_ssa);
+
+ finalize_jump_threads ();
+ return 0;
}
static bool
TV_TREE_VRP, /* tv_id */
PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
- 0, /* properties_destroyed */
+ PROP_smt_usage, /* properties_destroyed */
0, /* todo_flags_start */
TODO_cleanup_cfg
| TODO_ggc_collect
| TODO_verify_ssa
| TODO_dump_func
- | TODO_update_ssa, /* todo_flags_finish */
+ | TODO_update_ssa
+ | TODO_update_smt_usage, /* todo_flags_finish */
0 /* letter */
};