Thanks Anthony.  This has been bothering me for quite some time.

Anthony Green wrote:
Our compiler inlines many null pointer tests because the language
requires that we throw NullPointerExeceptions in certain cases that can
only be detected through explicit tests.

What's frustrating is that there are many cases where we're testing the
nullness of a function return value that we know can never be null.  For
instance, the result of string appends can never be null.  Neither can
object allocations.

See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24242


The attached experimental patch detects one special instance of a
non-null function result (gnu.gcj.runtime.StringBuffer.append()), and
marks it as being non-null.  GCC's value range propagation code then
magically eliminates any redundant null pointer checks.

I think all methods returning a reference in gnu.gcj.runtime.StringBuffer, java.lang.StringBuffer, java.lang.StringBuilder fall into this category.


Eventually we should manually mark certain function DECLs as
not-returning-null instead of my kludgy test for this one case.  I don't
know if/when I can get to that.  Perhaps somebody else can take it from
here.

Looks like all the bits in struct tree_common are used up.

Q: Would it make sense to add a flag to struct tree_decl_common to indicate !zero, set it using an attribute, (and automatically in the java front-end for the cases above), and then test for it in tree-vrp.c similar to below?


In any case, here's a patch Diego and I came up with.  It will eliminate
null-pointer checks related to the string concatenation operator (foo =
"blah" + bar).

(Thanks Diego!)

AG




------------------------------------------------------------------------

Index: tree-vrp.c
===================================================================
--- tree-vrp.c  (revision 106799)
+++ tree-vrp.c  (working copy)
@@ -2216,6 +2216,42 @@ infer_value_range (tree stmt, tree op, e
   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op))
     return false;
+ /* Is this a function call that is guaranteed not to
+     return null?  */
+  if (TREE_CODE (stmt) == MODIFY_EXPR
+      && op == TREE_OPERAND (stmt, 0)
+      && TREE_CODE (TREE_TYPE (stmt)) == POINTER_TYPE
+      && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
+    {
+      /* Ok, we know we have an assignment from a function
+        call returning a pointer.  Now - for testing purposes
+        - I'm just going to hard-code a test for a specific
+        java method known not to return null. */
+ + tree node = TREE_TYPE (TREE_TYPE (stmt));
+      if (TREE_CODE (node) == RECORD_TYPE
+         && TYPE_NAME (node)
+         && TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
+         && DECL_NAME (TYPE_NAME (node))
+         && strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
+                    "gnu.gcj.runtime.StringBuffer") == 0)
+       {
+ tree function = + TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (stmt, 1), 0), 0); + + if (TREE_CODE (function) == FUNCTION_DECL
+             && DECL_NAME (function)
+             && strcmp (IDENTIFIER_POINTER (DECL_NAME (function)),
+                        "append") == 0)
+           {
+             puts ("WOOHOO!");
+             *val_p = build_int_cst (TREE_TYPE (op), 0);
+             *comp_code_p = NE_EXPR;
+             return true;
+           }
+       }
+    }
+ /* Similarly, don't infer anything from statements that may throw
      exceptions.  */
   if (tree_could_throw_p (stmt))
@@ -2734,6 +2770,28 @@ find_assert_locations (basic_block bb)
            }
        }
+ /* Some assignments may compute values that guarantee certain
+        known ranges to their LHS.  */
+      FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_DEF)
+       {
+         tree value;
+         enum tree_code comp_code;
+
+         /* If OP is used only once, namely in this STMT, don't
+            bother creating an ASSERT_EXPR for it.  */
+         if (has_single_use (op))
+           continue;
+
+         /* If OP is used in such a way that we can infer a value
+            range for it, and we don't find a previous assertion for
+            it, create a new assertion location node for OP.  */
+         if (infer_value_range (stmt, op, &comp_code, &value))
+           {
+             register_new_assert_for (op, comp_code, value, bb, NULL, si);
+             need_assert = true;
+           }
+       }
+
       /* Remember the last statement of the block.  */
       last = stmt;
     }

Reply via email to