diff options
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 162 |
1 files changed, 123 insertions, 39 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index db4d3f8e101..094b7eb899a 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -36,14 +36,13 @@ along with GCC; see the file COPYING3. If not see #include "tree-scalar-evolution.h" #include "tree-ssa-propagate.h" #include "tree-chrec.h" -#include "gimple-fold.h" +#include "tree-ssa-threadupdate.h" #include "expr.h" #include "optabs.h" +#include "tree-ssa-threadedge.h" +#include "wide-int.h" -/* Type of value ranges. See value_range_d for a description of these - types. */ -enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING }; /* Range of values that can be associated with an SSA_NAME after VRP has executed. */ @@ -1041,7 +1040,7 @@ gimple_assign_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p) } } -/* Return true if STMT is know to to compute a non-zero value. +/* Return true if STMT is known to compute a non-zero value. If the return value is based on the assumption that signed overflow is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change *STRICT_OVERFLOW_P.*/ @@ -1054,7 +1053,19 @@ gimple_stmt_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p) case GIMPLE_ASSIGN: return gimple_assign_nonzero_warnv_p (stmt, strict_overflow_p); case GIMPLE_CALL: - return gimple_alloca_call_p (stmt); + { + tree fndecl = gimple_call_fndecl (stmt); + if (!fndecl) return false; + if (flag_delete_null_pointer_checks && !flag_check_new + && DECL_IS_OPERATOR_NEW (fndecl) + && !TREE_NOTHROW (fndecl)) + return true; + if (flag_delete_null_pointer_checks && + lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (gimple_call_fntype (stmt)))) + return true; + return gimple_alloca_call_p (stmt); + } default: gcc_unreachable (); } @@ -4415,6 +4426,56 @@ fp_predicate (gimple stmt) } +/* If OP can be inferred to be non-zero after STMT executes, return true. */ + +static bool +infer_nonnull_range (gimple stmt, tree op) +{ + /* 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)) + || gimple_code (stmt) == GIMPLE_ASM) + return false; + + unsigned num_uses, num_loads, num_stores; + + count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores); + if (num_loads + num_stores > 0) + return true; + + if (is_gimple_call (stmt) && !gimple_call_internal_p (stmt)) + { + tree fntype = gimple_call_fntype (stmt); + tree attrs = TYPE_ATTRIBUTES (fntype); + for (; attrs; attrs = TREE_CHAIN (attrs)) + { + attrs = lookup_attribute ("nonnull", attrs); + + /* If "nonnull" wasn't specified, we know nothing about + the argument. */ + if (attrs == NULL_TREE) + return false; + + /* If "nonnull" applies to all the arguments, then ARG + is non-null. */ + if (TREE_VALUE (attrs) == NULL_TREE) + return true; + + /* Now see if op appears in the nonnull list. */ + for (tree t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t)) + { + int idx = tree_to_shwi (TREE_VALUE (t)) - 1; + tree arg = gimple_call_arg (stmt, idx); + if (op == arg) + return true; + } + } + } + + return false; +} + /* If the range of values taken by OP can be inferred after STMT executes, return the comparison code (COMP_CODE_P) and value (VAL_P) that describes the inferred range. Return true if a range could be @@ -4432,7 +4493,7 @@ infer_value_range (gimple stmt, tree op, enum tree_code *comp_code_p, tree *val_ return false; /* Similarly, don't infer anything from statements that may throw - exceptions. */ + exceptions. ??? Relax this requirement? */ if (stmt_could_throw_p (stmt)) return false; @@ -4443,21 +4504,11 @@ 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; - /* 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)) - && gimple_code (stmt) != GIMPLE_ASM) + if (infer_nonnull_range (stmt, op)) { - unsigned num_uses, num_loads, num_stores; - - count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores); - if (num_loads + num_stores > 0) - { - *val_p = build_int_cst (TREE_TYPE (op), 0); - *comp_code_p = NE_EXPR; - return true; - } + *val_p = build_int_cst (TREE_TYPE (op), 0); + *comp_code_p = NE_EXPR; + return true; } return false; @@ -4494,7 +4545,7 @@ dump_asserts_for (FILE *file, tree name) } fprintf (file, "\n\tPREDICATE: "); print_generic_expr (file, name, 0); - fprintf (file, " %s ", tree_code_name[(int)loc->comp_code]); + fprintf (file, " %s ", get_tree_code_name (loc->comp_code)); print_generic_expr (file, loc->val, 0); fprintf (file, "\n\n"); loc = loc->next; @@ -5815,7 +5866,7 @@ find_assert_locations_1 (basic_block bb, sbitmap live) } /* Traverse all PHI nodes in BB, updating live. */ - for (si = gsi_start_phis (bb); !gsi_end_p(si); gsi_next (&si)) + for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) { use_operand_p arg_p; ssa_op_iter i; @@ -6449,9 +6500,7 @@ stmt_interesting_for_vrp (gimple stmt) if (lhs && TREE_CODE (lhs) == SSA_NAME && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) || POINTER_TYPE_P (TREE_TYPE (lhs))) - && ((is_gimple_call (stmt) - && gimple_call_fndecl (stmt) != NULL_TREE - && DECL_BUILT_IN (gimple_call_fndecl (stmt))) + && (is_gimple_call (stmt) || !gimple_vuse (stmt))) return true; } @@ -7372,16 +7421,7 @@ vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p) if (!stmt_interesting_for_vrp (stmt)) gcc_assert (stmt_ends_bb_p (stmt)); else if (is_gimple_assign (stmt) || is_gimple_call (stmt)) - { - /* In general, assignments with virtual operands are not useful - for deriving ranges, with the obvious exception of calls to - builtin functions. */ - if ((is_gimple_call (stmt) - && gimple_call_fndecl (stmt) != NULL_TREE - && DECL_BUILT_IN (gimple_call_fndecl (stmt))) - || !gimple_vuse (stmt)) - return vrp_visit_assignment_or_call (stmt, output_p); - } + return vrp_visit_assignment_or_call (stmt, output_p); else if (gimple_code (stmt) == GIMPLE_COND) return vrp_visit_cond_stmt (stmt, taken_edge_p); else if (gimple_code (stmt) == GIMPLE_SWITCH) @@ -9426,6 +9466,50 @@ vrp_finalize (void) the datastructures built by VRP. */ identify_jump_threads (); + /* Set value range to non pointer SSA_NAMEs. */ + for (i = 0; i < num_vr_values; i++) + if (vr_value[i]) + { + tree name = ssa_name (i); + + if (!name + || POINTER_TYPE_P (TREE_TYPE (name)) + || (vr_value[i]->type == VR_VARYING) + || (vr_value[i]->type == VR_UNDEFINED)) + 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, vr_value[i]->min, 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)) + { + max_wide_int tmmwi + = max_wide_int::from (wi::max_value (TYPE_PRECISION (TREE_TYPE (name)), + UNSIGNED), + UNSIGNED); + set_range_info (name, 1, tmmwi); + } + else + set_range_info (name, + vr_value[i]->max + 1, + vr_value[i]->min - 1); + } + } + } + /* Free allocated memory. */ for (i = 0; i < num_vr_values; i++) if (vr_value[i]) @@ -9596,12 +9680,12 @@ const pass_data pass_data_vrp = class pass_vrp : public gimple_opt_pass { public: - pass_vrp(gcc::context *ctxt) - : gimple_opt_pass(pass_data_vrp, ctxt) + pass_vrp (gcc::context *ctxt) + : gimple_opt_pass (pass_data_vrp, ctxt) {} /* opt_pass methods: */ - opt_pass * clone () { return new pass_vrp (ctxt_); } + opt_pass * clone () { return new pass_vrp (m_ctxt); } bool gate () { return gate_vrp (); } unsigned int execute () { return execute_vrp (); } |