From 508e475706c3560a86b08446e1bb764773b93ed9 Mon Sep 17 00:00:00 2001
From: Jan Hubicka <jh@suse.cz>
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 56fef865fa52..4f467cac8a98 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 32ad190135b2..470fb5a78fb4 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 2dcdf2f22f3d..f77a280d12f7 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 4ef63a2d3507..57b7a8d9efa3 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 878b6aa242e3..423729ba81aa 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 728678af30e1..2036bebe3046 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 000000000000..9cd2b09fb0da
--- /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" } } */
-- 
GitLab