aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog37
-rw-r--r--gcc/cgraph.c76
-rw-r--r--gcc/cgraph.h9
-rw-r--r--gcc/ipa-cp.c11
-rw-r--r--gcc/ipa-inline.c10
-rw-r--r--gcc/ipa-pure-const.c16
-rw-r--r--gcc/ipa.c43
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/tree-profile.c5
9 files changed, 151 insertions, 61 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 661e0c1..48d6bdd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,40 @@
+2010-10-26 Jan Hubicka <jh@suse.cz>
+
+ PR middle-end/45736
+ * cgraph.c (cgraph_set_readonly_flag): Rename to...
+ (cgraph_set_const_flags) ... this one; get also looping argument;
+ clear constructor/destructor flags.
+ (cgraph_set_pure_flag): Likewise.
+ (cgraph_set_looping_const_or_pure_flag): Remove.
+ (cgraph_can_remove_if_no_direct_calls_and_refs): Do not try
+ to optimize away static ctors/dtors; it does not work on inline clones;
+ external functions can always be rmeoved.
+ (cgraph_will_be_removed_from_program_if_no_direct_calls): Assert on inline
+ clones; in LTO external functions always can go.
+ (cgraph_used_from_object_file_p): Handle EXTERNAL functions correctly.
+ (cgraph_mark_address_taken_node): Assert that we are not taking address of
+ inline clone.
+ (cgraph_can_remove_if_no_direct_calls_p): We always eventually remove
+ external functions.
+ * ipa-cp.c (ipcp_cloning_candidate_p): Do not clone functions with address taken.
+ (ipcp_initialize_node_lattices): Only local functions can be handled without cloning.
+ * cgraph.h (cgraph_set_readonly_flag,
+ cgraph_set_looping_const_or_pure_flag): Remove.
+ (cgraph_set_const_flag): Declare.
+ (cgraph_set_pure_flag): Update.
+ * ipa-pure-const (propagate_pure_const, local_pure_const): Update
+ flags setting code.
+ * ipa.c (cgraph_remove_unreachable_nodes): Fix formating; do not look at inline
+ clones; fix handling of external definitions.
+ (cgraph_postorder): Do not look at inline clones in the first pass.
+ (function_and_variable_visibility): Drop constructors/destructor
+ flags at pure and const functions.
+ * tree-profile.c (tree_profiling): Update.
+ * ipa-inline.c (cgraph_clone_inlined_nodes): Always clone functions with
+ address taken; external functions do not account to whole program size.
+ (cgraph_decide_inlining): Likewise; do not try to inline functions already
+ inlined.
+
2010-10-26 Jie Zhang <jie@codesourcery.com>
* doc/invoke.texi: Improve documentation of
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index e1f47c2..1451d2b 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1723,6 +1723,7 @@ cgraph_mark_needed_node (struct cgraph_node *node)
void
cgraph_mark_address_taken_node (struct cgraph_node *node)
{
+ gcc_assert (!node->global.inlined_to);
cgraph_mark_reachable_node (node);
node->address_taken = 1;
}
@@ -2591,37 +2592,50 @@ cgraph_set_nothrow_flag (struct cgraph_node *node, bool nothrow)
if any to READONLY. */
void
-cgraph_set_readonly_flag (struct cgraph_node *node, bool readonly)
+cgraph_set_const_flag (struct cgraph_node *node, bool readonly, bool looping)
{
struct cgraph_node *alias;
+ /* Static constructors and destructors without a side effect can be
+ optimized out. */
+ if (!looping && readonly)
+ {
+ if (DECL_STATIC_CONSTRUCTOR (node->decl))
+ DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
+ if (DECL_STATIC_DESTRUCTOR (node->decl))
+ DECL_STATIC_DESTRUCTOR (node->decl) = 0;
+ }
TREE_READONLY (node->decl) = readonly;
+ DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
for (alias = node->same_body; alias; alias = alias->next)
- TREE_READONLY (alias->decl) = readonly;
+ {
+ TREE_READONLY (alias->decl) = readonly;
+ DECL_LOOPING_CONST_OR_PURE_P (alias->decl) = looping;
+ }
}
/* Set DECL_PURE_P on NODE's decl and on same_body aliases of NODE
if any to PURE. */
void
-cgraph_set_pure_flag (struct cgraph_node *node, bool pure)
+cgraph_set_pure_flag (struct cgraph_node *node, bool pure, bool looping)
{
struct cgraph_node *alias;
+ /* Static constructors and destructors without a side effect can be
+ optimized out. */
+ if (!looping && pure)
+ {
+ if (DECL_STATIC_CONSTRUCTOR (node->decl))
+ DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
+ if (DECL_STATIC_DESTRUCTOR (node->decl))
+ DECL_STATIC_DESTRUCTOR (node->decl) = 0;
+ }
DECL_PURE_P (node->decl) = pure;
+ DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
for (alias = node->same_body; alias; alias = alias->next)
- DECL_PURE_P (alias->decl) = pure;
-}
-
-/* Set DECL_LOOPING_CONST_OR_PURE_P on NODE's decl and on
- same_body aliases of NODE if any to LOOPING_CONST_OR_PURE. */
-
-void
-cgraph_set_looping_const_or_pure_flag (struct cgraph_node *node,
- bool looping_const_or_pure)
-{
- struct cgraph_node *alias;
- DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping_const_or_pure;
- for (alias = node->same_body; alias; alias = alias->next)
- DECL_LOOPING_CONST_OR_PURE_P (alias->decl) = looping_const_or_pure;
+ {
+ DECL_PURE_P (alias->decl) = pure;
+ DECL_LOOPING_CONST_OR_PURE_P (alias->decl) = looping;
+ }
}
/* See if the frequency of NODE can be updated based on frequencies of its
@@ -2768,25 +2782,21 @@ cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e)
bool
cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
{
+ gcc_assert (!node->global.inlined_to);
+ /* Extern inlines can always go, we will use the external definition. */
+ if (DECL_EXTERNAL (node->decl))
+ return true;
/* When function is needed, we can not remove it. */
if (node->needed || node->reachable_from_other_partition)
return false;
+ if (DECL_STATIC_CONSTRUCTOR (node->decl)
+ || DECL_STATIC_DESTRUCTOR (node->decl))
+ return false;
/* Only COMDAT functions can be removed if externally visible. */
if (node->local.externally_visible
&& (!DECL_COMDAT (node->decl)
|| cgraph_used_from_object_file_p (node)))
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;
}
@@ -2807,12 +2817,17 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
bool
cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node)
{
+ gcc_assert (!node->global.inlined_to);
if (cgraph_used_from_object_file_p (node))
return false;
if (!in_lto_p && !flag_whole_program)
return cgraph_only_called_directly_p (node);
else
- return cgraph_can_remove_if_no_direct_calls_p (node);
+ {
+ if (DECL_EXTERNAL (node->decl))
+ return true;
+ return cgraph_can_remove_if_no_direct_calls_p (node);
+ }
}
/* Return true when RESOLUTION indicate that linker will use
@@ -2835,7 +2850,8 @@ cgraph_used_from_object_file_p (struct cgraph_node *node)
{
struct cgraph_node *alias;
- if (!TREE_PUBLIC (node->decl))
+ gcc_assert (!node->global.inlined_to);
+ if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))
return false;
if (resolution_used_from_other_file_p (node->resolution))
return true;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index ea95f70..2b7ed4b 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -602,9 +602,8 @@ struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node *old_node,
const char *clone_name);
void cgraph_set_nothrow_flag (struct cgraph_node *, bool);
-void cgraph_set_readonly_flag (struct cgraph_node *, bool);
-void cgraph_set_pure_flag (struct cgraph_node *, bool);
-void cgraph_set_looping_const_or_pure_flag (struct cgraph_node *, bool);
+void cgraph_set_const_flag (struct cgraph_node *, bool, bool);
+void cgraph_set_pure_flag (struct cgraph_node *, bool, 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 *);
@@ -909,6 +908,7 @@ varpool_node_set_nonempty_p (varpool_node_set set)
static inline bool
cgraph_only_called_directly_p (struct cgraph_node *node)
{
+ gcc_assert (!node->global.inlined_to);
return (!node->needed && !node->address_taken
&& !node->reachable_from_other_partition
&& !DECL_STATIC_CONSTRUCTOR (node->decl)
@@ -922,6 +922,9 @@ cgraph_only_called_directly_p (struct cgraph_node *node)
static inline bool
cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
{
+ /* Extern inlines can always go, we will use the external definition. */
+ if (DECL_EXTERNAL (node->decl))
+ return true;
return !node->address_taken && cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
}
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 140dfc0..33ed496 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -457,6 +457,15 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
if (cgraph_only_called_directly_p (node) || !node->analyzed)
return false;
+ /* When function address is taken, we are pretty sure it will be called in hidden way. */
+ if (node->address_taken)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not considering %s for cloning; address is taken.\n",
+ cgraph_node_name (node));
+ return false;
+ }
+
if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
{
if (dump_file)
@@ -561,7 +570,7 @@ ipcp_initialize_node_lattices (struct cgraph_node *node)
if (ipa_is_called_with_var_arguments (info))
type = IPA_BOTTOM;
- else if (cgraph_only_called_directly_p (node))
+ else if (node->local.local)
type = IPA_TOP;
/* When cloning is allowed, we can assume that externally visible functions
are not called. We will compensate this by cloning later. */
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 8d9db0b..7241dcb 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -250,6 +250,10 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
/* We may eliminate the need for out-of-line copy to be output.
In that case just go ahead and re-use it. */
if (!e->callee->callers->next_caller
+ /* FIXME: When address is taken of DECL_EXTERNAL function we still can remove its
+ offline copy, but we would need to keep unanalyzed node in the callgraph so
+ references can point to it. */
+ && !e->callee->address_taken
&& cgraph_can_remove_if_no_direct_calls_p (e->callee)
/* Inlining might enable more devirtualizing, so we want to remove
those only after all devirtualizable virtual calls are processed.
@@ -264,7 +268,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
&& !cgraph_new_nodes)
{
gcc_assert (!e->callee->global.inlined_to);
- if (e->callee->analyzed)
+ if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->decl))
{
overall_size -= e->callee->global.size;
nfunctions_inlined++;
@@ -1449,7 +1453,8 @@ cgraph_decide_inlining (void)
struct cgraph_edge *e;
gcc_assert (inline_summary (node)->self_size == node->global.size);
- initial_size += node->global.size;
+ if (!DECL_EXTERNAL (node->decl))
+ initial_size += node->global.size;
for (e = node->callees; e; e = e->next_callee)
if (max_count < e->count)
max_count = e->count;
@@ -1512,6 +1517,7 @@ cgraph_decide_inlining (void)
if (node->callers
&& !node->callers->next_caller
+ && !node->global.inlined_to
&& cgraph_will_be_removed_from_program_if_no_direct_calls (node)
&& node->local.inlinable
&& cgraph_function_body_availability (node) >= AVAIL_AVAILABLE
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 334b33c..d671643 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -1322,8 +1322,7 @@ propagate_pure_const (void)
this_looping ? "looping " : "",
cgraph_node_name (w));
}
- cgraph_set_readonly_flag (w, true);
- cgraph_set_looping_const_or_pure_flag (w, this_looping);
+ cgraph_set_const_flag (w, true, this_looping);
break;
case IPA_PURE:
@@ -1335,8 +1334,7 @@ propagate_pure_const (void)
this_looping ? "looping " : "",
cgraph_node_name (w));
}
- cgraph_set_pure_flag (w, true);
- cgraph_set_looping_const_or_pure_flag (w, this_looping);
+ cgraph_set_pure_flag (w, true, this_looping);
break;
default:
@@ -1599,8 +1597,7 @@ local_pure_const (void)
warn_function_const (current_function_decl, !l->looping);
if (!skip)
{
- cgraph_set_readonly_flag (node, true);
- cgraph_set_looping_const_or_pure_flag (node, l->looping);
+ cgraph_set_const_flag (node, true, l->looping);
changed = true;
}
if (dump_file)
@@ -1614,7 +1611,7 @@ local_pure_const (void)
{
if (!skip)
{
- cgraph_set_looping_const_or_pure_flag (node, false);
+ cgraph_set_const_flag (node, true, false);
changed = true;
}
if (dump_file)
@@ -1629,8 +1626,7 @@ local_pure_const (void)
{
if (!skip)
{
- cgraph_set_pure_flag (node, true);
- cgraph_set_looping_const_or_pure_flag (node, l->looping);
+ cgraph_set_pure_flag (node, true, l->looping);
changed = true;
}
warn_function_pure (current_function_decl, !l->looping);
@@ -1645,7 +1641,7 @@ local_pure_const (void)
{
if (!skip)
{
- cgraph_set_looping_const_or_pure_flag (node, false);
+ cgraph_set_pure_flag (node, true, false);
changed = true;
}
if (dump_file)
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 7db27f3..2eb43b8 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -57,8 +57,9 @@ cgraph_postorder (struct cgraph_node **order)
for (node = cgraph_nodes; node; node = node->next)
if (!node->aux
&& (pass
- || (!cgraph_only_called_directly_p (node)
- && !node->address_taken)))
+ || (!node->address_taken
+ && !node->global.inlined_to
+ && !cgraph_only_called_directly_p (node))))
{
node2 = node;
if (!node->callers)
@@ -237,15 +238,22 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
gcc_assert (!vnode->aux);
#endif
varpool_reset_queue ();
+ /* Mark functions whose bodies are obviously needed.
+ This is mostly when they can be referenced externally. Inline clones
+ are special since their declarations are shared with master clone and thus
+ cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */
for (node = cgraph_nodes; node; node = node->next)
- if ((!cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
- /* Keep around virtual functions for possible devirtualization. */
- || (!before_inlining_p
- && !node->global.inlined_to
- && DECL_VIRTUAL_P (node->decl)
- && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))))
- && ((!DECL_EXTERNAL (node->decl))
- || before_inlining_p))
+ if (node->analyzed && !node->global.inlined_to
+ && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
+ /* Keep around virtual functions for possible devirtualization. */
+ || (before_inlining_p
+ && DECL_VIRTUAL_P (node->decl)
+ && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl)))
+ /* Also external functions with address taken are better to stay
+ for indirect inlining. */
+ || (before_inlining_p
+ && DECL_EXTERNAL (node->decl)
+ && node->address_taken)))
{
gcc_assert (!node->global.inlined_to);
enqueue_cgraph_node (node, &first);
@@ -256,6 +264,8 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
gcc_assert (!node->aux);
node->reachable = false;
}
+
+ /* Mark variables that are obviously needed. */
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
{
vnode->next_needed = NULL;
@@ -428,10 +438,10 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
node->clone_of->clones = node->next_sibling_clone;
if (node->next_sibling_clone)
node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
- #ifdef ENABLE_CHECKING
+#ifdef ENABLE_CHECKING
if (node->clone_of)
node->former_clone_of = node->clone_of->decl;
- #endif
+#endif
node->clone_of = NULL;
node->next_sibling_clone = NULL;
node->prev_sibling_clone = NULL;
@@ -771,6 +781,15 @@ function_and_variable_visibility (bool whole_program)
for (node = cgraph_nodes; node; node = node->next)
{
+ int flags = flags_from_decl_or_type (node->decl);
+ if (optimize
+ && (flags & (ECF_CONST | ECF_PURE))
+ && !(flags & ECF_LOOPING_CONST_OR_PURE))
+ {
+ DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
+ DECL_STATIC_DESTRUCTOR (node->decl) = 0;
+ }
+
/* C++ FE on lack of COMDAT support create local COMDAT functions
(that ought to be shared but can not due to object format
limitations). It is neccesary to keep the flag to make rest of C++ FE
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 762ceea..fcb3d87 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-10-26 Jan Hubicka <jh@suse.cz>
+
+ PR middle-end/45736
+ * testsuite/gcc.dg/lto/pr45736_0.c: New function.
+
2010-10-26 Ira Rosen <irar@il.ibm.com>
PR tree-optimization/46167
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index 5b7c12b..ba38504 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -510,9 +510,8 @@ tree_profiling (void)
|| DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile)
continue;
- cgraph_set_readonly_flag (node, false);
- cgraph_set_pure_flag (node, false);
- cgraph_set_looping_const_or_pure_flag (node, false);
+ cgraph_set_const_flag (node, false, false);
+ cgraph_set_pure_flag (node, false, false);
}
/* Update call statements and rebuild the cgraph. */