Commit 508e4757 by Jan Hubicka Committed by Jan Hubicka

re PR middle-end/45307 (Stores expanding to no RTL not removed by tree…

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
parent f1395d4a
2010-08-20 Jan Hubicka <jh@suse.cz> 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. * lto-cgraph.c (lto_output_edge): Use gimple_has_body_p instead of flag_wpa.
* lto-streamer-out.c (lto_output): Likewise. * lto-streamer-out.c (lto_output): Likewise.
* passes.c (ipa_write_optimization_summaries): Initialize statement uids. * passes.c (ipa_write_optimization_summaries): Initialize statement uids.
......
...@@ -2709,6 +2709,33 @@ cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e) ...@@ -2709,6 +2709,33 @@ cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e)
return cgraph_node_cannot_return (e->callee); 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 /* Return true when function NODE can be excpected to be removed
from program when direct calls in this compilation unit are removed. from program when direct calls in this compilation unit are removed.
......
...@@ -608,6 +608,10 @@ void cgraph_set_looping_const_or_pure_flag (struct cgraph_node *, bool); ...@@ -608,6 +608,10 @@ void cgraph_set_looping_const_or_pure_flag (struct cgraph_node *, bool);
tree clone_function_name (tree decl, const char *); tree clone_function_name (tree decl, const char *);
bool cgraph_node_cannot_return (struct cgraph_node *); bool cgraph_node_cannot_return (struct cgraph_node *);
bool cgraph_edge_cannot_lead_to_return (struct cgraph_edge *); 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 */ /* In cgraphunit.c */
extern FILE *cgraph_dump_file; extern FILE *cgraph_dump_file;
...@@ -664,8 +668,6 @@ void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *); ...@@ -664,8 +668,6 @@ void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *);
void cgraph_materialize_all_clones (void); void cgraph_materialize_all_clones (void);
gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *); gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *);
bool cgraph_propagate_frequency (struct cgraph_node *node); 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 */ /* In cgraphbuild.c */
unsigned int rebuild_cgraph_edges (void); unsigned int rebuild_cgraph_edges (void);
void cgraph_rebuild_references (void); void cgraph_rebuild_references (void);
...@@ -903,17 +905,11 @@ varpool_node_set_nonempty_p (varpool_node_set set) ...@@ -903,17 +905,11 @@ varpool_node_set_nonempty_p (varpool_node_set set)
static inline bool static inline bool
cgraph_only_called_directly_p (struct cgraph_node *node) cgraph_only_called_directly_p (struct cgraph_node *node)
{ {
return !node->needed && !node->address_taken && !node->local.externally_visible; return (!node->needed && !node->address_taken
} && !node->reachable_from_other_partition
&& !DECL_STATIC_CONSTRUCTOR (node->decl)
/* Return true when function NODE can be removed from callgraph && !DECL_STATIC_DESTRUCTOR (node->decl)
if all direct calls are eliminated. */ && !node->local.externally_visible);
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 true when function NODE can be removed from callgraph /* Return true when function NODE can be removed from callgraph
......
...@@ -367,11 +367,6 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl) ...@@ -367,11 +367,6 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
&& !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
return true; 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; return false;
} }
...@@ -532,7 +527,9 @@ cgraph_finalize_function (tree decl, bool nested) ...@@ -532,7 +527,9 @@ cgraph_finalize_function (tree decl, bool nested)
/* Since we reclaim unreachable nodes at the end of every language /* Since we reclaim unreachable nodes at the end of every language
level unit, we need to be conservative about possible entry points level unit, we need to be conservative about possible entry points
there. */ 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); cgraph_mark_reachable_node (node);
/* If we've not yet emitted decl, tell the debug info about it. */ /* If we've not yet emitted decl, tell the debug info about it. */
...@@ -1219,8 +1216,7 @@ cgraph_mark_functions_to_output (void) ...@@ -1219,8 +1216,7 @@ cgraph_mark_functions_to_output (void)
outside the current compilation unit. */ outside the current compilation unit. */
if (node->analyzed if (node->analyzed
&& !node->global.inlined_to && !node->global.inlined_to
&& (node->needed || node->reachable_from_other_partition && (!cgraph_only_called_directly_p (node)
|| node->address_taken
|| (e && node->reachable)) || (e && node->reachable))
&& !TREE_ASM_WRITTEN (decl) && !TREE_ASM_WRITTEN (decl)
&& !DECL_EXTERNAL (decl)) && !DECL_EXTERNAL (decl))
......
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> 2010-08-20 H.J. Lu <hongjiu.lu@intel.com>
PR target/45336 PR target/45336
......
// PR c++/45307 // PR c++/45307
// { dg-options -fdump-tree-gimple } // { dg-options "-fdump-tree-gimple -fdump-tree-optimized" }
struct fallible_t { }; struct fallible_t { };
const fallible_t fallible = fallible_t(); const fallible_t fallible = fallible_t();
// { dg-final { scan-tree-dump-not "fallible" "gimple" } } // { 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 "gimple" } }
// { dg-final { cleanup-tree-dump "optimized" } }
/* { 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" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment