diff options
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 201 |
1 files changed, 147 insertions, 54 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index c47b8e6e313..f6da19252c6 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -1,5 +1,5 @@ /* Support routines for Value Range Propagation (VRP). - Copyright (C) 2005-2013 Free Software Foundation, Inc. + Copyright (C) 2005-2014 Free Software Foundation, Inc. Contributed by Diego Novillo <dnovillo@redhat.com>. This file is part of GCC. @@ -441,6 +441,9 @@ set_value_range (value_range_t *vr, enum value_range_type t, tree min, gcc_assert (min && max); + gcc_assert ((!TREE_OVERFLOW_P (min) || is_overflow_infinity (min)) + && (!TREE_OVERFLOW_P (max) || is_overflow_infinity (max))); + if (INTEGRAL_TYPE_P (TREE_TYPE (min)) && t == VR_ANTI_RANGE) gcc_assert (!vrp_val_is_min (min) || !vrp_val_is_max (max)); @@ -616,7 +619,8 @@ static inline void set_value_range_to_value (value_range_t *vr, tree val, bitmap equiv) { gcc_assert (is_gimple_min_invariant (val)); - val = avoid_overflow_infinity (val); + if (TREE_OVERFLOW_P (val)) + val = drop_tree_overflow (val); set_value_range (vr, VR_RANGE, val, val, equiv); } @@ -3198,9 +3202,9 @@ extract_range_from_unary_expr_1 (value_range_t *vr, } /* Handle operations that we express in terms of others. */ - if (code == PAREN_EXPR) + if (code == PAREN_EXPR || code == OBJ_TYPE_REF) { - /* PAREN_EXPR is a simple copy. */ + /* PAREN_EXPR and OBJ_TYPE_REF are simple copies. */ copy_value_range (vr, &vr0); return; } @@ -3753,6 +3757,47 @@ extract_range_basic (value_range_t *vr, gimple stmt) break; } } + else if (is_gimple_call (stmt) + && gimple_call_internal_p (stmt)) + { + enum tree_code subcode = ERROR_MARK; + switch (gimple_call_internal_fn (stmt)) + { + case IFN_UBSAN_CHECK_ADD: + subcode = PLUS_EXPR; + break; + case IFN_UBSAN_CHECK_SUB: + subcode = MINUS_EXPR; + break; + case IFN_UBSAN_CHECK_MUL: + subcode = MULT_EXPR; + break; + default: + break; + } + if (subcode != ERROR_MARK) + { + bool saved_flag_wrapv = flag_wrapv; + /* Pretend the arithmetics is wrapping. If there is + any overflow, we'll complain, but will actually do + wrapping operation. */ + flag_wrapv = 1; + extract_range_from_binary_expr (vr, subcode, type, + gimple_call_arg (stmt, 0), + gimple_call_arg (stmt, 1)); + flag_wrapv = saved_flag_wrapv; + + /* If for both arguments vrp_valueize returned non-NULL, + this should have been already folded and if not, it + wasn't folded because of overflow. Avoid removing the + UBSAN_CHECK_* calls in that case. */ + if (vr->type == VR_RANGE + && (vr->min == vr->max + || operand_equal_p (vr->min, vr->max, 0))) + set_value_range_to_varying (vr); + return; + } + } if (INTEGRAL_TYPE_P (type) && gimple_stmt_nonnegative_warnv_p (stmt, &sop)) set_value_range_to_nonnegative (vr, type, @@ -4496,7 +4541,7 @@ infer_value_range (gimple stmt, tree op, enum tree_code *comp_code_p, tree *val_ if (stmt_ends_bb_p (stmt) && EDGE_COUNT (gimple_bb (stmt)->succs) == 0) return false; - if (infer_nonnull_range (stmt, op)) + if (infer_nonnull_range (stmt, op, true, true)) { *val_p = build_int_cst (TREE_TYPE (op), 0); *comp_code_p = NE_EXPR; @@ -5434,9 +5479,13 @@ register_edge_assert_for_1 (tree op, enum tree_code code, } else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (op_def))) { - /* Recurse through the type conversion. */ - retval |= register_edge_assert_for_1 (gimple_assign_rhs1 (op_def), - code, e, bsi); + /* Recurse through the type conversion, unless it is a narrowing + conversion or conversion from non-integral type. */ + tree rhs = gimple_assign_rhs1 (op_def); + if (INTEGRAL_TYPE_P (TREE_TYPE (rhs)) + && (TYPE_PRECISION (TREE_TYPE (rhs)) + <= TYPE_PRECISION (TREE_TYPE (op)))) + retval |= register_edge_assert_for_1 (rhs, code, e, bsi); } return retval; @@ -5885,13 +5934,13 @@ find_assert_locations_1 (basic_block bb, sbitmap live) static bool find_assert_locations (void) { - int *rpo = XNEWVEC (int, last_basic_block); - int *bb_rpo = XNEWVEC (int, last_basic_block); - int *last_rpo = XCNEWVEC (int, last_basic_block); + int *rpo = XNEWVEC (int, last_basic_block_for_fn (cfun)); + int *bb_rpo = XNEWVEC (int, last_basic_block_for_fn (cfun)); + int *last_rpo = XCNEWVEC (int, last_basic_block_for_fn (cfun)); int rpo_cnt, i; bool need_asserts; - live = XCNEWVEC (sbitmap, last_basic_block); + live = XCNEWVEC (sbitmap, last_basic_block_for_fn (cfun)); rpo_cnt = pre_and_rev_post_order_compute (NULL, rpo, false); for (i = 0; i < rpo_cnt; ++i) bb_rpo[rpo[i]] = i; @@ -5926,7 +5975,7 @@ find_assert_locations (void) need_asserts = false; for (i = rpo_cnt - 1; i >= 0; --i) { - basic_block bb = BASIC_BLOCK (rpo[i]); + basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]); edge e; edge_iterator ei; @@ -5985,7 +6034,7 @@ find_assert_locations (void) XDELETEVEC (rpo); XDELETEVEC (bb_rpo); XDELETEVEC (last_rpo); - for (i = 0; i < last_basic_block; ++i) + for (i = 0; i < last_basic_block_for_fn (cfun); ++i) if (live[i]) sbitmap_free (live[i]); XDELETEVEC (live); @@ -6382,7 +6431,7 @@ check_all_array_refs (void) basic_block bb; gimple_stmt_iterator si; - FOR_EACH_BB (bb) + FOR_EACH_BB_FN (bb, cfun) { edge_iterator ei; edge e; @@ -6544,7 +6593,7 @@ remove_range_assertions (void) /* Note that the BSI iterator bump happens at the bottom of the loop and no bump is necessary if we're removing the statement referenced by the current BSI. */ - FOR_EACH_BB (bb) + FOR_EACH_BB_FN (bb, cfun) for (si = gsi_after_labels (bb), is_unreachable = -1; !gsi_end_p (si);) { gimple stmt = gsi_stmt (si); @@ -6588,7 +6637,8 @@ remove_range_assertions (void) && all_imm_uses_in_stmt_or_feed_cond (var, stmt, single_pred (bb))) { - set_range_info (var, SSA_NAME_RANGE_INFO (lhs)->min, + set_range_info (var, SSA_NAME_RANGE_TYPE (lhs), + SSA_NAME_RANGE_INFO (lhs)->min, SSA_NAME_RANGE_INFO (lhs)->max); maybe_set_nonzero_bits (bb, var); } @@ -6658,7 +6708,7 @@ vrp_initialize (void) vr_value = XCNEWVEC (value_range_t *, num_vr_values); vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names); - FOR_EACH_BB (bb) + FOR_EACH_BB_FN (bb, cfun) { gimple_stmt_iterator si; @@ -6738,8 +6788,8 @@ vrp_visit_assignment_or_call (gimple stmt, tree *output_p) /* Try folding the statement to a constant first. */ tree tem = gimple_fold_stmt_to_constant (stmt, vrp_valueize); - if (tem && !is_overflow_infinity (tem)) - set_value_range (&new_vr, VR_RANGE, tem, tem, NULL); + if (tem) + set_value_range_to_value (&new_vr, tem, NULL); /* Then dispatch to value-range extracting functions. */ else if (code == GIMPLE_CALL) extract_range_basic (&new_vr, stmt); @@ -7749,7 +7799,8 @@ union_ranges (enum value_range_type *vr0type, } else if ((operand_less_p (vr1min, *vr0max) == 1 || operand_equal_p (vr1min, *vr0max, 0)) - && operand_less_p (*vr0min, vr1min) == 1) + && operand_less_p (*vr0min, vr1min) == 1 + && operand_less_p (*vr0max, vr1max) == 1) { /* [ ( ] ) or [ ]( ) */ if (*vr0type == VR_RANGE @@ -7783,7 +7834,8 @@ union_ranges (enum value_range_type *vr0type, } else if ((operand_less_p (*vr0min, vr1max) == 1 || operand_equal_p (*vr0min, vr1max, 0)) - && operand_less_p (vr1min, *vr0min) == 1) + && operand_less_p (vr1min, *vr0min) == 1 + && operand_less_p (vr1max, *vr0max) == 1) { /* ( [ ) ] or ( )[ ] */ if (*vr0type == VR_RANGE @@ -8336,7 +8388,7 @@ vrp_visit_phi_node (gimple phi) } else { - if (is_overflow_infinity (arg)) + if (TREE_OVERFLOW_P (arg)) arg = drop_tree_overflow (arg); vr_arg.type = VR_RANGE; @@ -9247,6 +9299,68 @@ simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt) return true; } +/* Simplify an internal fn call using ranges if possible. */ + +static bool +simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple stmt) +{ + enum tree_code subcode; + switch (gimple_call_internal_fn (stmt)) + { + case IFN_UBSAN_CHECK_ADD: + subcode = PLUS_EXPR; + break; + case IFN_UBSAN_CHECK_SUB: + subcode = MINUS_EXPR; + break; + case IFN_UBSAN_CHECK_MUL: + subcode = MULT_EXPR; + break; + default: + return false; + } + + value_range_t vr0 = VR_INITIALIZER; + value_range_t vr1 = VR_INITIALIZER; + tree op0 = gimple_call_arg (stmt, 0); + tree op1 = gimple_call_arg (stmt, 1); + + if (TREE_CODE (op0) == SSA_NAME) + vr0 = *get_value_range (op0); + else if (TREE_CODE (op0) == INTEGER_CST) + set_value_range_to_value (&vr0, op0, NULL); + else + return false; + + if (TREE_CODE (op1) == SSA_NAME) + vr1 = *get_value_range (op1); + else if (TREE_CODE (op1) == INTEGER_CST) + set_value_range_to_value (&vr1, op1, NULL); + else + return false; + + if (!range_int_cst_p (&vr0) || !range_int_cst_p (&vr1)) + return false; + + tree r1 = int_const_binop (subcode, vr0.min, vr1.min); + tree r2 = int_const_binop (subcode, vr0.max, vr1.max); + if (r1 == NULL_TREE || TREE_OVERFLOW (r1) + || r2 == NULL_TREE || TREE_OVERFLOW (r2)) + return false; + if (subcode == MULT_EXPR) + { + tree r3 = int_const_binop (subcode, vr0.min, vr1.max); + tree r4 = int_const_binop (subcode, vr0.max, vr1.min); + if (r3 == NULL_TREE || TREE_OVERFLOW (r3) + || r4 == NULL_TREE || TREE_OVERFLOW (r4)) + return false; + } + gimple g = gimple_build_assign_with_ops (subcode, gimple_call_lhs (stmt), + op0, op1); + gsi_replace (gsi, g, false); + return true; +} + /* Simplify STMT using ranges if possible. */ static bool @@ -9315,6 +9429,9 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) return simplify_cond_using_ranges (stmt); else if (gimple_code (stmt) == GIMPLE_SWITCH) return simplify_switch_using_ranges (stmt); + else if (is_gimple_call (stmt) + && gimple_call_internal_p (stmt)) + return simplify_internal_call_using_ranges (gsi, stmt); return false; } @@ -9491,7 +9608,7 @@ identify_jump_threads (void) 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) + FOR_EACH_BB_FN (bb, cfun) { gimple last; @@ -9594,36 +9711,12 @@ vrp_finalize (void) continue; if ((TREE_CODE (vr_value[i]->min) == INTEGER_CST) - && (TREE_CODE (vr_value[i]->max) == INTEGER_CST)) - { - if (vr_value[i]->type == VR_RANGE) - set_range_info (name, - tree_to_double_int (vr_value[i]->min), - tree_to_double_int (vr_value[i]->max)); - else if (vr_value[i]->type == VR_ANTI_RANGE) - { - /* VR_ANTI_RANGE ~[min, max] is encoded compactly as - [max + 1, min - 1] without additional attributes. - When min value > max value, we know that it is - VR_ANTI_RANGE; it is VR_RANGE otherwise. */ - - /* ~[0,0] anti-range is represented as - range. */ - if (TYPE_UNSIGNED (TREE_TYPE (name)) - && integer_zerop (vr_value[i]->min) - && integer_zerop (vr_value[i]->max)) - set_range_info (name, - double_int_one, - double_int::max_value - (TYPE_PRECISION (TREE_TYPE (name)), true)); - else - set_range_info (name, - tree_to_double_int (vr_value[i]->max) - + double_int_one, - tree_to_double_int (vr_value[i]->min) - - double_int_one); - } - } + && (TREE_CODE (vr_value[i]->max) == INTEGER_CST) + && (vr_value[i]->type == VR_RANGE + || vr_value[i]->type == VR_ANTI_RANGE)) + set_range_info (name, vr_value[i]->type, + tree_to_double_int (vr_value[i]->min), + tree_to_double_int (vr_value[i]->max)); } /* Free allocated memory. */ |