diff mbox

[RFA] Improvements to infer_nonnull_range

Message ID 526F4174.9080300@redhat.com
State New
Headers show

Commit Message

Jeff Law Oct. 29, 2013, 5:02 a.m. UTC
Based on a suggestion from Marc, I want to use infer_nonnull_range in 
the erroneous path isolation optimization.

In the process of doing that, I found  a few deficiencies in 
infer_nonnull_range that need to be addressed.


First, infer_nonnull_range_p doesn't infer ranges from a GIMPLE_RETURN 
if the current function is marked as returns_nonnull.  That's fixed in 
the relatively obvious way.

Second, infer_nonnull_range_p, when presented with an arglist where the 
non-null attribute applies to all pointer arguments, it won't bother to 
determine if OP is actually one of the arguments :(  It just assumes 
that OP is in the argument list.  Opps.

Third, I want to be able to call infer_nonnull_range with OP being 0B. 
That lets me use infer_nonnull_range to look for explicit null pointer 
dereferences, explicit uses of null in a return statement in functions 
that can't return non-null and explicit uses of null arguments when 
those arguments can't be null.   Sadly, to make that work we need to use 
operand_equal_p rather than simple pointer comparisons to see if OP 
shows up in STMT.

Finally, for detecting explicit null pointers, infer_nonnull_range calls 
count_ptr_derefs.  count_ptr_derefs counts things in two ways.  One with 
a FOR_EACH_SSA_TREE_OPERAND, then again with simple walks of the tree 
structures.   Not surprisingly if we're looking for an explicit 0B, then 
the loop over the operands finds nothing, but walking the tree 
structures does. And the checking assert triggers.  This change removes 
the assert and instead sets *num_uses_p to a sane value.

I don't have testcases for this stuff that are independent of the 
erroneous path isolation optimization.  However, each is triggered by 
tests I'll include in the the erroneous path isolation patch.

Bootstrapped and regression tested on x86_64-unknown-linux-gnu.  OK for 
the trunk?

jeff
* tree-ssa.c (count_ptr_derefs): Use operand_equal_p rather than
	testing pointer equality.  Remove invalid assert.  Clamp minimum
	value for *num_uses_p at *num_loads_p + *num_stores_p.
	
	* tree-vrp.c (infer_nonnull_range): Verify OP is in the argument
	list and the argument corresponding to OP is a pointer type.
	Use operand_equal_p rather than pointer equality when testing
	if OP is on the nonnull list.  Handle GIMPLE_RETURN statements too.

Comments

Jeff Law Oct. 31, 2013, 5:41 a.m. UTC | #1
On 10/28/13 23:02, Jeff Law wrote:
>
> Based on a suggestion from Marc, I want to use infer_nonnull_range in
> the erroneous path isolation optimization.
>
> In the process of doing that, I found  a few deficiencies in
> infer_nonnull_range that need to be addressed.
>
>
> First, infer_nonnull_range_p doesn't infer ranges from a GIMPLE_RETURN
> if the current function is marked as returns_nonnull.  That's fixed in
> the relatively obvious way.
>
> Second, infer_nonnull_range_p, when presented with an arglist where the
> non-null attribute applies to all pointer arguments, it won't bother to
> determine if OP is actually one of the arguments :(  It just assumes
> that OP is in the argument list.  Opps.
>
> Third, I want to be able to call infer_nonnull_range with OP being 0B.
> That lets me use infer_nonnull_range to look for explicit null pointer
> dereferences, explicit uses of null in a return statement in functions
> that can't return non-null and explicit uses of null arguments when
> those arguments can't be null.   Sadly, to make that work we need to use
> operand_equal_p rather than simple pointer comparisons to see if OP
> shows up in STMT.
>
> Finally, for detecting explicit null pointers, infer_nonnull_range calls
> count_ptr_derefs.  count_ptr_derefs counts things in two ways.  One with
> a FOR_EACH_SSA_TREE_OPERAND, then again with simple walks of the tree
> structures.   Not surprisingly if we're looking for an explicit 0B, then
> the loop over the operands finds nothing, but walking the tree
> structures does. And the checking assert triggers.  This change removes
> the assert and instead sets *num_uses_p to a sane value.
>
> I don't have testcases for this stuff that are independent of the
> erroneous path isolation optimization.  However, each is triggered by
> tests I'll include in the the erroneous path isolation patch.
>
> Bootstrapped and regression tested on x86_64-unknown-linux-gnu.  OK for
> the trunk?
I'm withdrawing this patch.  While everything works exactly how I 
wanted, I think it's best to rework things a bit and totally eliminate 
count_ptr_derefs entirely.

That change makes it significantly easier to move infer_nonnull_range 
out of tree-vrp.c and into gimple.c (or wherever Andrew wants it) 
without a significant modularity break.

Jeff
Richard Biener Nov. 4, 2013, 12:53 p.m. UTC | #2
On Thu, Oct 31, 2013 at 6:41 AM, Jeff Law <law@redhat.com> wrote:
> On 10/28/13 23:02, Jeff Law wrote:
>>
>>
>> Based on a suggestion from Marc, I want to use infer_nonnull_range in
>> the erroneous path isolation optimization.
>>
>> In the process of doing that, I found  a few deficiencies in
>> infer_nonnull_range that need to be addressed.
>>
>>
>> First, infer_nonnull_range_p doesn't infer ranges from a GIMPLE_RETURN
>> if the current function is marked as returns_nonnull.  That's fixed in
>> the relatively obvious way.
>>
>> Second, infer_nonnull_range_p, when presented with an arglist where the
>> non-null attribute applies to all pointer arguments, it won't bother to
>> determine if OP is actually one of the arguments :(  It just assumes
>> that OP is in the argument list.  Opps.
>>
>> Third, I want to be able to call infer_nonnull_range with OP being 0B.
>> That lets me use infer_nonnull_range to look for explicit null pointer
>> dereferences, explicit uses of null in a return statement in functions
>> that can't return non-null and explicit uses of null arguments when
>> those arguments can't be null.   Sadly, to make that work we need to use
>> operand_equal_p rather than simple pointer comparisons to see if OP
>> shows up in STMT.
>>
>> Finally, for detecting explicit null pointers, infer_nonnull_range calls
>> count_ptr_derefs.  count_ptr_derefs counts things in two ways.  One with
>> a FOR_EACH_SSA_TREE_OPERAND, then again with simple walks of the tree
>> structures.   Not surprisingly if we're looking for an explicit 0B, then
>> the loop over the operands finds nothing, but walking the tree
>> structures does. And the checking assert triggers.  This change removes
>> the assert and instead sets *num_uses_p to a sane value.
>>
>> I don't have testcases for this stuff that are independent of the
>> erroneous path isolation optimization.  However, each is triggered by
>> tests I'll include in the the erroneous path isolation patch.
>>
>> Bootstrapped and regression tested on x86_64-unknown-linux-gnu.  OK for
>> the trunk?
>
> I'm withdrawing this patch.  While everything works exactly how I wanted, I
> think it's best to rework things a bit and totally eliminate
> count_ptr_derefs entirely.

Yes!  And count_uses_and_derefs, too.  See walk_stmt_load_store_addr_ops.

Richard.


> That change makes it significantly easier to move infer_nonnull_range out of
> tree-vrp.c and into gimple.c (or wherever Andrew wants it) without a
> significant modularity break.

> Jeff
>
diff mbox

Patch

diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 0b743d1..d29665b 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -265,7 +265,8 @@  count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
       return NULL_TREE;
     }
 
-  if (TREE_CODE (*tp) == MEM_REF && TREE_OPERAND (*tp, 0) == count_p->ptr)
+  if (TREE_CODE (*tp) == MEM_REF
+      && operand_equal_p (TREE_OPERAND (*tp, 0), count_p->ptr, 0))
     {
       if (wi_p->is_lhs)
 	count_p->num_stores++;
@@ -326,7 +327,11 @@  count_uses_and_derefs (tree ptr, gimple stmt, unsigned *num_uses_p,
       *num_loads_p = count.num_loads;
     }
 
-  gcc_assert (*num_uses_p >= *num_loads_p + *num_stores_p);
+  /* This can happen if PTR refers to something other than an SSA_NAME.
+     In that case we will find no uses as the FOR_EACH_SSA_TREE_OPERAND
+     only iterates over the SSA_NAMEs in a statement.  */
+  if (*num_uses_p < *num_loads_p + *num_stores_p)
+    *num_uses_p = *num_loads_p + *num_stores_p;
 }
 
 
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index d3a07f3..bbcb34c 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -4509,21 +4509,38 @@  infer_nonnull_range (gimple stmt, tree op)
 	    return false;
 
 	  /* If "nonnull" applies to all the arguments, then ARG
-	     is non-null.  */
+	     is non-null if it's in the argument list.  */
 	  if (TREE_VALUE (attrs) == NULL_TREE)
-	    return true;
+	    {
+	      for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
+		{
+		  if (operand_equal_p (op, gimple_call_arg (stmt, i), 0)
+		      && POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (stmt, i))))
+		    return true;
+		}
+	      return false;
+	    }
 
 	  /* 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)
+	      if (operand_equal_p (op, arg, 0))
 		return true;
 	    }
 	}
     }
 
+  /* If this function is marked as returning non-null, then we can
+     infer OP is non-null if it is used in the return statement.  */
+  if (gimple_code (stmt) == GIMPLE_RETURN
+      && gimple_return_retval (stmt)
+      && operand_equal_p (gimple_return_retval (stmt), op, 0)
+      && lookup_attribute ("returns_nonnull",
+			   TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
+    return true;
+
   return false;
 }