This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][RFA] Improvements to infer_nonnull_range

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?

	* 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.

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)
@@ -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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]