diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 56fef865fa524b95f6e08a0bee8a34915da4cef9..4f467cac8a982bfb105c7f074c812dc41a30b6ce 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2010-08-20 Jan Hubicka <jh@suse.cz> + + PR c++/45307 + PR c++/17736 + * cgraph.h (cgraph_only_called_directly_p, + cgraph_can_remove_if_no_direct_calls_and_refs_p): Handle + static cdtors. + * cgraphunit.c (cgraph_decide_is_function_needed): Static cdtors + are not needed. + (cgraph_finalize_function): Static cdtors are reachable. + (cgraph_mark_functions_to_output): Use cgraph_only_called_directly_p. + 2010-08-20 Jan Hubicka <jh@suse.cz> * lto-cgraph.c (lto_output_edge): Use gimple_has_body_p instead of flag_wpa. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 32ad190135b296f236924ef53247027c3ec90298..470fb5a78fb4afa66cfb628290fc04243f39d062 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2709,6 +2709,33 @@ cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e) return cgraph_node_cannot_return (e->callee); } +/* Return true when function NODE can be removed from callgraph + if all direct calls are eliminated. */ + +bool +cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node) +{ + /* When function is needed, we can not remove it. */ + if (node->needed || node->reachable_from_other_partition) + return false; + /* Only COMDAT functions can be removed if externally visible. */ + if (node->local.externally_visible + && (!DECL_COMDAT (node->decl) || node->local.used_from_object_file)) + return false; + /* Constructors and destructors are executed by the runtime, however + we can get rid of all pure constructors and destructors. */ + if (DECL_STATIC_CONSTRUCTOR (node->decl) + || DECL_STATIC_DESTRUCTOR (node->decl)) + { + int flags = flags_from_decl_or_type (node->decl); + if (!optimize + || !(flags & (ECF_CONST | ECF_PURE)) + || (flags & ECF_LOOPING_CONST_OR_PURE)) + return false; + } + return true; +} + /* Return true when function NODE can be excpected to be removed from program when direct calls in this compilation unit are removed. diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 2dcdf2f22f3d0c3d704efa55b94bbd5e63a93804..f77a280d12f7f435ed66b5f07eea39050a224ae6 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -608,6 +608,10 @@ void cgraph_set_looping_const_or_pure_flag (struct cgraph_node *, bool); tree clone_function_name (tree decl, const char *); bool cgraph_node_cannot_return (struct cgraph_node *); bool cgraph_edge_cannot_lead_to_return (struct cgraph_edge *); +bool cgraph_will_be_removed_from_program_if_no_direct_calls + (struct cgraph_node *node); +bool cgraph_can_remove_if_no_direct_calls_and_refs_p + (struct cgraph_node *node); /* In cgraphunit.c */ extern FILE *cgraph_dump_file; @@ -664,8 +668,6 @@ void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *); void cgraph_materialize_all_clones (void); gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *); bool cgraph_propagate_frequency (struct cgraph_node *node); -bool cgraph_will_be_removed_from_program_if_no_direct_calls - (struct cgraph_node *node); /* In cgraphbuild.c */ unsigned int rebuild_cgraph_edges (void); void cgraph_rebuild_references (void); @@ -903,17 +905,11 @@ varpool_node_set_nonempty_p (varpool_node_set set) static inline bool cgraph_only_called_directly_p (struct cgraph_node *node) { - return !node->needed && !node->address_taken && !node->local.externally_visible; -} - -/* Return true when function NODE can be removed from callgraph - if all direct calls are eliminated. */ - -static inline bool -cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node) -{ - return (!node->needed && !node->reachable_from_other_partition - && (DECL_COMDAT (node->decl) || !node->local.externally_visible)); + return (!node->needed && !node->address_taken + && !node->reachable_from_other_partition + && !DECL_STATIC_CONSTRUCTOR (node->decl) + && !DECL_STATIC_DESTRUCTOR (node->decl) + && !node->local.externally_visible); } /* Return true when function NODE can be removed from callgraph diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 4ef63a2d350766e2fa2a3a4bb5d4c9089b30e2c0..57b7a8d9efa3fe13a64c159f59811586fea21f08 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -367,11 +367,6 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; - /* Constructors and destructors are reachable from the runtime by - some mechanism. */ - if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl)) - return true; - return false; } @@ -532,7 +527,9 @@ cgraph_finalize_function (tree decl, bool nested) /* Since we reclaim unreachable nodes at the end of every language level unit, we need to be conservative about possible entry points there. */ - if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))) + if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) + || DECL_STATIC_CONSTRUCTOR (decl) + || DECL_STATIC_DESTRUCTOR (decl)) cgraph_mark_reachable_node (node); /* If we've not yet emitted decl, tell the debug info about it. */ @@ -1219,8 +1216,7 @@ cgraph_mark_functions_to_output (void) outside the current compilation unit. */ if (node->analyzed && !node->global.inlined_to - && (node->needed || node->reachable_from_other_partition - || node->address_taken + && (!cgraph_only_called_directly_p (node) || (e && node->reachable)) && !TREE_ASM_WRITTEN (decl) && !DECL_EXTERNAL (decl)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 878b6aa242e3fe6c7414b74a10622ab7c23df4f6..423729ba81aa0e3f60873d727834a66ebff2a657 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2010-08-20 Jan Hubicka <jh@suse.cz> + + PR c++/45307 + PR c++/17736 + * gcc.dg/ipa/ctor-empty-1.c: Add testcase. + * g++.dg/tree-ssa/empty-2.C: Check that constructor got optimized out. + 2010-08-20 H.J. Lu <hongjiu.lu@intel.com> PR target/45336 diff --git a/gcc/testsuite/g++.dg/tree-ssa/empty-2.C b/gcc/testsuite/g++.dg/tree-ssa/empty-2.C index 728678af30e15f17a0e2245946aa3d38647f20ff..2036bebe3046b36be844efc95bbce64344dcaaff 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/empty-2.C +++ b/gcc/testsuite/g++.dg/tree-ssa/empty-2.C @@ -1,8 +1,11 @@ // PR c++/45307 -// { dg-options -fdump-tree-gimple } +// { dg-options "-fdump-tree-gimple -fdump-tree-optimized" } struct fallible_t { }; const fallible_t fallible = fallible_t(); // { dg-final { scan-tree-dump-not "fallible" "gimple" } } +// Whole constructor should be optimized away. +// { dg-final { scan-tree-dump-not "int" "optimized" } } // { dg-final { cleanup-tree-dump "gimple" } } +// { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gcc.dg/ipa/ctor-empty-1.c b/gcc/testsuite/gcc.dg/ipa/ctor-empty-1.c new file mode 100644 index 0000000000000000000000000000000000000000..9cd2b09fb0da6e38668efa585329ec50b0fcaa40 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ctor-empty-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -c -fdump-ipa-whole-program" } */ +static __attribute__((constructor)) +void empty_constructor() +{ +} +/* { dg-final { scan-ipa-dump "Reclaiming functions: empty_constructor" "whole-program" } } */ +/* { dg-final { cleanup-ipa-dump "whole-program" } } */