===================================================================
@@ -282,6 +282,9 @@ public:
void set_init_priority (priority_type priority);
priority_type get_init_priority ();
+
+ /* Return true if symbol is known to be nonzero. */
+ bool nonzero_address ();
};
/* Walk all aliases for NODE. */
@@ -1148,6 +1151,17 @@ tree varpool_get_constructor (struct var
/* In cgraph.c */
extern void change_decl_assembler_name (tree, tree);
+/* Return true if DECL should have entry in symbol table if used.
+ Those are functions and static & external veriables*/
+
+static bool
+decl_in_symtab_p (const_tree decl)
+{
+ return (TREE_CODE (decl) == FUNCTION_DECL
+ || (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))));
+}
+
/* Return symbol table node associated with DECL, if any,
and NULL otherwise. */
@@ -1155,12 +1169,7 @@ static inline symtab_node *
symtab_get_node (const_tree decl)
{
#ifdef ENABLE_CHECKING
- /* Check that we are called for sane type of object - functions
- and static or external variables. */
- gcc_checking_assert (TREE_CODE (decl) == FUNCTION_DECL
- || (TREE_CODE (decl) == VAR_DECL
- && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)
- || in_lto_p)));
+ gcc_checking_assert (decl_in_symtab_p (decl));
/* Check that the mapping is sane - perhaps this check can go away,
but at the moment frontends tends to corrupt the mapping by calling
memcpy/memset on the tree nodes. */
===================================================================
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.
#include "tree-dfa.h"
#include "hash-table.h" /* Required for ENABLE_FOLD_CHECKING. */
#include "builtins.h"
+#include "cgraph.h"
/* Nonzero if we are folding constants inside an initializer; zero
otherwise. */
@@ -16020,21 +16021,33 @@ tree_single_nonzero_warnv_p (tree t, boo
case ADDR_EXPR:
{
tree base = TREE_OPERAND (t, 0);
+
if (!DECL_P (base))
base = get_base_address (base);
if (!base)
return false;
- /* Weak declarations may link to NULL. Other things may also be NULL
- so protect with -fdelete-null-pointer-checks; but not variables
- allocated on the stack. */
+ /* For objects in symbol table check if we know they are non-zero.
+ Don't do anything for variables and functions before symtab is built;
+ it is quite possible that they will be declared weak later. */
+ if (DECL_P (base) && decl_in_symtab_p (base))
+ {
+ struct symtab_node *symbol;
+
+ symbol = symtab_get_node (base);
+ if (symbol)
+ return symbol->nonzero_address ();
+ else
+ return false;
+ }
+
+ /* Function local objects are never NULL. */
if (DECL_P (base)
- && (flag_delete_null_pointer_checks
- || (DECL_CONTEXT (base)
- && TREE_CODE (DECL_CONTEXT (base)) == FUNCTION_DECL
- && auto_var_in_fn_p (base, DECL_CONTEXT (base)))))
- return !VAR_OR_FUNCTION_DECL_P (base) || !DECL_WEAK (base);
+ && (DECL_CONTEXT (base)
+ && TREE_CODE (DECL_CONTEXT (base)) == FUNCTION_DECL
+ && auto_var_in_fn_p (base, DECL_CONTEXT (base))))
+ return true;
/* Constants are never weak. */
if (CONSTANT_CLASS_P (base))
===================================================================
@@ -1,6 +1,2 @@
-#if defined(AVR) /* flag_delete_null_pointer_checks = 0 */
int sc = (&sc >= 0);
-#else
-int sc = (&sc > 0);
-#endif
===================================================================
@@ -1,5 +1,5 @@
/* { dg-do link } */
-/* { dg-options "-fdelete-null-pointer-checks -fdump-tree-original" } */
+/* { dg-options "-fdelete-null-pointer-checks -fdump-tree-ccp1" } */
void foo();
@@ -10,5 +10,5 @@ int main()
return 0;
}
-/* { dg-final { scan-tree-dump-not "foo" "original" { target { ! avr*-*-* } } } } */
-/* { dg-final { cleanup-tree-dump "original" } } */
+/* { dg-final { scan-tree-dump-not "foo" "ccp1" { target { ! avr*-*-* } } } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
===================================================================
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+extern int a;
+t()
+{
+ return &a!=0;
+}
+extern int a __attribute__ ((weak));
+
+/* { dg-final { scan-tree-dump-not "return 1" "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
===================================================================
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ccp1" } */
+inline void t()
+{
+}
+int m()
+{
+ void *q = (void *)&t;
+ return q != 0;
+}
+/* { dg-final { scan-tree-dump "return 1" "ccp1"} } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ccp1 -fdelete-null-pointer-checks" } */
+struct t
+{
+ static inline void tt()
+ {
+ }
+ virtual void q();
+};
+int m()
+{
+ void *q = (void *)&t::tt;
+ return q != 0;
+}
+/* { dg-final { scan-tree-dump "return 1" "ccp1"} } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
===================================================================
@@ -1890,4 +1890,67 @@ symtab_get_symbol_partitioning_class (sy
return SYMBOL_PARTITION;
}
+
+/* Return true when symbol is known to be non-zero. */
+
+bool
+symtab_node::nonzero_address ()
+{
+ /* Weakrefs may be NULL when their target is not defined. */
+ if (this->alias && this->weakref)
+ {
+ if (this->analyzed)
+ {
+ symtab_node *target = symtab_alias_ultimate_target (this);
+
+ if (target->alias && target->weakref)
+ return false;
+ /* We can not recurse to target::nonzero. It is possible that the
+ target is used only via the alias.
+ We may walk references and look for strong use, but we do not know
+ if this strong use will survive to final binary, so be
+ conservative here.
+ ??? Maybe we could do the lookup during late optimization that
+ could be useful to eliminate the NULL pointer checks in LTO
+ programs. */
+ if (target->definition && !DECL_EXTERNAL (target->decl))
+ return true;
+ if (target->resolution != LDPR_UNKNOWN
+ && target->resolution != LDPR_UNDEF
+ && flag_delete_null_pointer_checks)
+ return true;
+ return false;
+ }
+ else
+ return false;
+ }
+
+ /* With !flag_delete_null_pointer_checks we assume that symbols may
+ bind to NULL. This is on by default on embedded targets only.
+
+ Otherwise all non-WEAK symbols must be defined and thus non-NULL or
+ linking fails. Important case of WEAK we want to do well are comdats.
+ Those are handled by later check for definition.
+
+ When parsing, beware the cases when WEAK attribute is added later. */
+ if (!DECL_WEAK (this->decl)
+ && flag_delete_null_pointer_checks
+ && cgraph_state > CGRAPH_STATE_PARSING)
+ return true;
+
+ /* If target is defined and not extern, we know it will be output and thus
+ it will bind to non-NULL.
+ Play safe for flag_delete_null_pointer_checks where weak definition maye
+ be re-defined by NULL. */
+ if (this->definition && !DECL_EXTERNAL (this->decl)
+ && (flag_delete_null_pointer_checks || !DECL_WEAK (this->decl)))
+ return true;
+
+ /* As the last resort, check the resolution info. */
+ if (this->resolution != LDPR_UNKNOWN
+ && this->resolution != LDPR_UNDEF
+ && flag_delete_null_pointer_checks)
+ return true;
+ return false;
+}
#include "gt-symtab.h"