From 508e475706c3560a86b08446e1bb764773b93ed9 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 21 Aug 2010 11:46:15 +0200 Subject: [PATCH] re PR middle-end/45307 (Stores expanding to no RTL not removed by tree optimizers, Empty ctors/dtors not eliminated) 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. * gcc.dg/ipa/ctor-empty-1.c: Add testcase. * g++.dg/tree-ssa/empty-2.C: Check that constructor got optimized out. From-SVN: r163439 --- gcc/ChangeLog | 12 ++++++++++++ gcc/cgraph.c | 27 +++++++++++++++++++++++++++ gcc/cgraph.h | 22 +++++++++------------- gcc/cgraphunit.c | 12 ++++-------- gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/g++.dg/tree-ssa/empty-2.C | 5 ++++- gcc/testsuite/gcc.dg/ipa/ctor-empty-1.c | 8 ++++++++ 7 files changed, 71 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/ctor-empty-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 56fef86..4f467ca 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,17 @@ 2010-08-20 Jan Hubicka + 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 + * lto-cgraph.c (lto_output_edge): Use gimple_has_body_p instead of flag_wpa. * lto-streamer-out.c (lto_output): Likewise. * passes.c (ipa_write_optimization_summaries): Initialize statement uids. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 32ad190..470fb5a 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 2dcdf2f..f77a280 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 4ef63a2..57b7a8d 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 878b6aa..423729b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2010-08-20 Jan Hubicka + + 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 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 728678a..2036beb 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 0000000..9cd2b09 --- /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" } } */ -- 2.7.4