Hi, this is variant of patch I comitted (the change is only testsuite compensation for pr36902 and 44024) and updated predicate name to nonzero_address
Honza * cgraph.h (symtab_node): Add nonzero_address. (decl_in_symtab_p): Break out from ... (symtab_get_node): ... here. * fold-const.c: Include cgraph.h (tree_single_nonzero_warnv_p): Use symtab to determine if symbol is non-zero. * symtab.c (symtab_node::nonzero_address): New method. * gcc.dg/pr36901.h: Simplify because non-zero symbol folding no longer happens during parsing. * gcc.dg/pr44024.c: Update template. * g++.dg/tree-ssa/nonzero-2.C: New testcase. * g++.dg/tree-ssa/nonzero-1.C: New testcase. * gcc.dg/tree-ssa/nonzero-1.c: New testcase. Index: cgraph.h =================================================================== --- cgraph.h (revision 212495) +++ cgraph.h (working copy) @@ -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. */ Index: fold-const.c =================================================================== --- fold-const.c (revision 212495) +++ fold-const.c (working copy) @@ -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)) Index: testsuite/gcc.dg/pr36901.h =================================================================== --- testsuite/gcc.dg/pr36901.h (revision 212495) +++ testsuite/gcc.dg/pr36901.h (working copy) @@ -1,6 +1,2 @@ -#if defined(AVR) /* flag_delete_null_pointer_checks = 0 */ int sc = (&sc >= 0); -#else -int sc = (&sc > 0); -#endif Index: testsuite/gcc.dg/pr44024.c =================================================================== --- testsuite/gcc.dg/pr44024.c (revision 212495) +++ testsuite/gcc.dg/pr44024.c (working copy) @@ -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" } } */ Index: testsuite/gcc.dg/tree-ssa/nonzero-1.c =================================================================== --- testsuite/gcc.dg/tree-ssa/nonzero-1.c (revision 0) +++ testsuite/gcc.dg/tree-ssa/nonzero-1.c (revision 0) @@ -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" } } */ Index: testsuite/g++.dg/tree-ssa/nonzero-1.C =================================================================== --- testsuite/g++.dg/tree-ssa/nonzero-1.C (revision 0) +++ testsuite/g++.dg/tree-ssa/nonzero-1.C (revision 0) @@ -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" } } */ Index: testsuite/g++.dg/tree-ssa/nonzero-2.C =================================================================== --- testsuite/g++.dg/tree-ssa/nonzero-2.C (revision 0) +++ testsuite/g++.dg/tree-ssa/nonzero-2.C (revision 0) @@ -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" } } */ Index: symtab.c =================================================================== --- symtab.c (revision 212495) +++ symtab.c (working copy) @@ -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"