Commit 0e6a0e48 by Marc Glisse Committed by Marc Glisse

re PR tree-optimization/58480 (Use attribute((nonnull)) to optimize callers)

2013-10-08  Marc Glisse  <marc.glisse@inria.fr>

	PR tree-optimization/58480
gcc/
	* tree-vrp.c (infer_nonnull_range): New function.
	(infer_value_range): Call infer_nonnull_range.

gcc/testsuite/
	* gcc.dg/tree-ssa/pr58480.c: New file.

From-SVN: r203271
parent ef6179d1
2013-10-08 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/58480
* tree-vrp.c (infer_nonnull_range): New function.
(infer_value_range): Call infer_nonnull_range.
2013-10-08 Dehao Chen <dehao@google.com> 2013-10-08 Dehao Chen <dehao@google.com>
PR tree-optimization/58619 PR tree-optimization/58619
......
2013-10-08 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/58480
* gcc.dg/tree-ssa/pr58480.c: New file.
2013-10-07 Bill Schmidt <wschmidt@linux.vnet.ibm.com> 2013-10-07 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
* gcc.target/powerpc/pr43154.c: Skip for ppc64 little endian. * gcc.target/powerpc/pr43154.c: Skip for ppc64 little endian.
......
/* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
extern void eliminate (void);
extern void* f1 (void *a, void *b) __attribute__((nonnull));
extern void* f2 (void *a, void *b) __attribute__((nonnull(2)));
void g1 (void*p, void*q){
f1 (q, p);
if (p == 0)
eliminate ();
}
void g2 (void*p, void*q){
f2 (q, p);
if (p == 0)
eliminate ();
}
/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 2 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */
...@@ -4462,6 +4462,56 @@ fp_predicate (gimple stmt) ...@@ -4462,6 +4462,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 (gimple_code (stmt) == GIMPLE_CALL)
{
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_INT_CST_LOW (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, /* 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 return the comparison code (COMP_CODE_P) and value (VAL_P) that
describes the inferred range. Return true if a range could be describes the inferred range. Return true if a range could be
...@@ -4479,7 +4529,7 @@ infer_value_range (gimple stmt, tree op, enum tree_code *comp_code_p, tree *val_ ...@@ -4479,7 +4529,7 @@ infer_value_range (gimple stmt, tree op, enum tree_code *comp_code_p, tree *val_
return false; return false;
/* Similarly, don't infer anything from statements that may throw /* Similarly, don't infer anything from statements that may throw
exceptions. */ exceptions. ??? Relax this requirement? */
if (stmt_could_throw_p (stmt)) if (stmt_could_throw_p (stmt))
return false; return false;
...@@ -4490,21 +4540,11 @@ infer_value_range (gimple stmt, tree op, enum tree_code *comp_code_p, tree *val_ ...@@ -4490,21 +4540,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) if (stmt_ends_bb_p (stmt) && EDGE_COUNT (gimple_bb (stmt)->succs) == 0)
return false; return false;
/* We can only assume that a pointer dereference will yield if (infer_nonnull_range (stmt, op))
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)
{ {
unsigned num_uses, num_loads, num_stores; *val_p = build_int_cst (TREE_TYPE (op), 0);
*comp_code_p = NE_EXPR;
count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores); return true;
if (num_loads + num_stores > 0)
{
*val_p = build_int_cst (TREE_TYPE (op), 0);
*comp_code_p = NE_EXPR;
return true;
}
} }
return false; return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment