diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-04-05 10:32:23 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-04-05 10:32:23 +0000 |
commit | fe410b3e0f7de0376d98b922113c80f9ab4bd192 (patch) | |
tree | 2907bc726434f732f093ecd43d5f5ba62ac08265 /gcc/tree-vrp.c | |
parent | 941f2a0d21995a3e06f340891a639c4462850312 (diff) | |
download | gcc-fe410b3e0f7de0376d98b922113c80f9ab4bd192.tar.gz |
2008-04-05 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk r133930
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@133932 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 1274 |
1 files changed, 922 insertions, 352 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 64f60003733..9741262dba2 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -47,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 @@ -71,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; }; @@ -99,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 @@ -109,7 +182,11 @@ static int *vr_phi_edge_counts; static inline bool 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 @@ -121,13 +198,14 @@ needs_overflow_infinity (const_tree type) static inline bool 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 @@ -152,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. */ @@ -163,7 +241,7 @@ 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. */ @@ -174,7 +252,7 @@ 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. */ @@ -185,7 +263,7 @@ 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. */ @@ -196,8 +274,7 @@ 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 @@ -210,48 +287,18 @@ avoid_overflow_infinity (tree val) if (!is_overflow_infinity (val)) return val; - if (operand_equal_p (val, TYPE_MAX_VALUE (TREE_TYPE (val)), 0)) - return TYPE_MAX_VALUE (TREE_TYPE (val)); + if (vrp_val_is_max (val)) + return vrp_val_max (TREE_TYPE (val)); else { #ifdef ENABLE_CHECKING - gcc_assert (operand_equal_p (val, TYPE_MIN_VALUE (TREE_TYPE (val)), 0)); + gcc_assert (vrp_val_is_min (val)); #endif - return TYPE_MIN_VALUE (TREE_TYPE (val)); + return vrp_val_min (TREE_TYPE (val)); } } -/* 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 = TYPE_MAX_VALUE (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 = TYPE_MIN_VALUE (TREE_TYPE (val)); - - return (val == type_min - || (type_min != NULL_TREE - && operand_equal_p (val, type_min, 0))); -} - - /* Return true if ARG is marked with the nonnull attribute in the current function signature. */ @@ -300,6 +347,18 @@ nonnull_arg_p (const_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 @@ -352,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 @@ -1102,20 +1227,24 @@ 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); @@ -1159,8 +1288,46 @@ extract_range_from_assert (value_range_t *vr_p, tree expr) instance, ASSERT_EXPR <x_2, x_2 <= b_4>. 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; @@ -1444,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. */ @@ -1691,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 }; @@ -1726,7 +1898,6 @@ 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)) @@ -1734,7 +1905,6 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr) 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)) @@ -1771,7 +1941,7 @@ 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))) { @@ -1782,9 +1952,9 @@ extract_range_from_binary_expr (value_range_t *vr, tree expr) 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, TREE_TYPE (expr)); + 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); @@ -1794,9 +1964,9 @@ extract_range_from_binary_expr (value_range_t *vr, tree 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, TREE_TYPE (expr)); + 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); @@ -1821,7 +1991,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. */ @@ -1834,7 +2004,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 @@ -1845,13 +2015,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; } } @@ -1917,7 +2087,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); @@ -2046,7 +2216,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 @@ -2056,7 +2226,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 @@ -2114,10 +2284,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 }; @@ -2135,7 +2305,6 @@ 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)) @@ -2163,17 +2332,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); @@ -2181,71 +2350,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) - && (!is_overflow_infinity (new_min) - || !is_overflow_infinity (new_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 @@ -2261,22 +2422,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)); + min = positive_overflow_infinity (type); else if (!vrp_val_is_min (vr0.max)) - min = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.max); - else if (needs_overflow_infinity (TREE_TYPE (expr))) + 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) && !vrp_val_is_min (vr0.min)) - min = positive_overflow_infinity (TREE_TYPE (expr)); + min = positive_overflow_infinity (type); else { set_value_range_to_varying (vr); @@ -2284,18 +2445,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)); + max = positive_overflow_infinity (type); else if (!vrp_val_is_min (vr0.min)) - max = fold_unary_to_constant (code, TREE_TYPE (expr), vr0.min); - else if (needs_overflow_infinity (TREE_TYPE (expr))) + 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); @@ -2303,31 +2464,31 @@ 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 && vrp_val_is_min (vr0.min)) || (vr0.type == VR_ANTI_RANGE @@ -2341,13 +2502,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)); + min = positive_overflow_infinity (type); else if (!vrp_val_is_min (vr0.min)) - 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 = 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); @@ -2355,13 +2516,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)); + max = positive_overflow_infinity (type); else if (!vrp_val_is_min (vr0.max)) - 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 = 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); @@ -2384,9 +2545,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, @@ -2396,9 +2557,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 @@ -2407,11 +2568,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); @@ -2419,7 +2580,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); } } @@ -2429,7 +2590,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 { @@ -2445,10 +2606,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); @@ -2467,7 +2628,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))); @@ -2482,7 +2643,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))); @@ -2546,10 +2707,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 @@ -2561,7 +2726,7 @@ 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); + val = fold_convert (type, val); if (is_gimple_min_invariant (val)) set_value_range_to_value (vr, val, vr->equiv); else @@ -2569,7 +2734,7 @@ extract_range_from_comparison (value_range_t *vr, tree expr) } 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); } @@ -2591,13 +2756,18 @@ extract_range_from_expr (value_range_t *vr, tree 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, NULL); else @@ -3388,9 +3558,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 <NAME, NAME COMP_CODE VAL>. + for ASSERT_EXPR <NAME, EXPR COMP_CODE VAL>. 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 @@ -3399,7 +3569,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, @@ -3453,7 +3623,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 @@ -3500,6 +3672,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) @@ -3510,82 +3683,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); + + 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; + } - /* 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 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 @@ -3601,6 +3895,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) @@ -3615,7 +3910,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; } @@ -3627,6 +3922,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)) { @@ -3634,26 +3930,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 @@ -3697,7 +3979,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; @@ -3709,17 +3993,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 @@ -3835,8 +4118,17 @@ find_conditional_asserts (basic_block bb, tree last) /* 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 @@ -3887,7 +4179,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); @@ -3954,14 +4246,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)); } } @@ -4126,7 +4421,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; } @@ -4138,7 +4433,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; } } @@ -4183,7 +4479,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) @@ -4938,6 +5234,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 @@ -4986,47 +5327,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; @@ -5136,11 +5441,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)) @@ -5234,6 +5534,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. @@ -5272,8 +5713,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. */ @@ -5857,6 +6300,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 @@ -5883,9 +6426,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 @@ -5937,6 +6480,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 @@ -5950,6 +6495,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); @@ -5995,7 +6545,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 @@ -6162,6 +6711,10 @@ record_numbers_of_iterations (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 (); @@ -6179,10 +6732,27 @@ execute_vrp (void) 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 (); + /* 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 does not properly handle ASSERT_EXPRs. */ |