summaryrefslogtreecommitdiff
path: root/gcc/tree-vrp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r--gcc/tree-vrp.c162
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 (); }