Commit 530f3a1b by Jan Hubicka Committed by Jan Hubicka

re PR lto/45736 (ICE: in cgraph_remove_unreachable_nodes, at ipa.c:245 with…

re PR lto/45736 (ICE: in cgraph_remove_unreachable_nodes, at ipa.c:245 with -flto and attribute((constructor)))


	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.
	* testsuite/gcc.dg/lto/pr45736_0.c: New function.

From-SVN: r165972
parent 0d600fce
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> 2010-10-26 Jie Zhang <jie@codesourcery.com>
* doc/invoke.texi: Improve documentation of * doc/invoke.texi: Improve documentation of
...@@ -1723,6 +1723,7 @@ cgraph_mark_needed_node (struct cgraph_node *node) ...@@ -1723,6 +1723,7 @@ cgraph_mark_needed_node (struct cgraph_node *node)
void void
cgraph_mark_address_taken_node (struct cgraph_node *node) cgraph_mark_address_taken_node (struct cgraph_node *node)
{ {
gcc_assert (!node->global.inlined_to);
cgraph_mark_reachable_node (node); cgraph_mark_reachable_node (node);
node->address_taken = 1; node->address_taken = 1;
} }
...@@ -2591,37 +2592,50 @@ cgraph_set_nothrow_flag (struct cgraph_node *node, bool nothrow) ...@@ -2591,37 +2592,50 @@ cgraph_set_nothrow_flag (struct cgraph_node *node, bool nothrow)
if any to READONLY. */ if any to READONLY. */
void 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; 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; TREE_READONLY (node->decl) = readonly;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
for (alias = node->same_body; alias; alias = alias->next) 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 /* Set DECL_PURE_P on NODE's decl and on same_body aliases of NODE
if any to PURE. */ if any to PURE. */
void 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; 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_PURE_P (node->decl) = pure;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
for (alias = node->same_body; alias; alias = alias->next) for (alias = node->same_body; alias; alias = alias->next)
DECL_PURE_P (alias->decl) = pure; {
} DECL_PURE_P (alias->decl) = pure;
DECL_LOOPING_CONST_OR_PURE_P (alias->decl) = looping;
/* 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;
} }
/* See if the frequency of NODE can be updated based on frequencies of its /* 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) ...@@ -2768,25 +2782,21 @@ cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e)
bool bool
cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node) 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. */ /* When function is needed, we can not remove it. */
if (node->needed || node->reachable_from_other_partition) if (node->needed || node->reachable_from_other_partition)
return false; return false;
if (DECL_STATIC_CONSTRUCTOR (node->decl)
|| DECL_STATIC_DESTRUCTOR (node->decl))
return false;
/* Only COMDAT functions can be removed if externally visible. */ /* Only COMDAT functions can be removed if externally visible. */
if (node->local.externally_visible if (node->local.externally_visible
&& (!DECL_COMDAT (node->decl) && (!DECL_COMDAT (node->decl)
|| cgraph_used_from_object_file_p (node))) || cgraph_used_from_object_file_p (node)))
return false; 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;
} }
...@@ -2807,12 +2817,17 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node) ...@@ -2807,12 +2817,17 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
bool bool
cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node) 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)) if (cgraph_used_from_object_file_p (node))
return false; return false;
if (!in_lto_p && !flag_whole_program) if (!in_lto_p && !flag_whole_program)
return cgraph_only_called_directly_p (node); return cgraph_only_called_directly_p (node);
else 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 /* Return true when RESOLUTION indicate that linker will use
...@@ -2835,7 +2850,8 @@ cgraph_used_from_object_file_p (struct cgraph_node *node) ...@@ -2835,7 +2850,8 @@ cgraph_used_from_object_file_p (struct cgraph_node *node)
{ {
struct cgraph_node *alias; 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; return false;
if (resolution_used_from_other_file_p (node->resolution)) if (resolution_used_from_other_file_p (node->resolution))
return true; return true;
......
...@@ -602,9 +602,8 @@ struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node *old_node, ...@@ -602,9 +602,8 @@ struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node *old_node,
const char *clone_name); const char *clone_name);
void cgraph_set_nothrow_flag (struct cgraph_node *, bool); void cgraph_set_nothrow_flag (struct cgraph_node *, bool);
void cgraph_set_readonly_flag (struct cgraph_node *, bool); void cgraph_set_const_flag (struct cgraph_node *, bool, bool);
void cgraph_set_pure_flag (struct cgraph_node *, bool); void cgraph_set_pure_flag (struct cgraph_node *, bool, bool);
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 *);
...@@ -909,6 +908,7 @@ varpool_node_set_nonempty_p (varpool_node_set set) ...@@ -909,6 +908,7 @@ 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)
{ {
gcc_assert (!node->global.inlined_to);
return (!node->needed && !node->address_taken return (!node->needed && !node->address_taken
&& !node->reachable_from_other_partition && !node->reachable_from_other_partition
&& !DECL_STATIC_CONSTRUCTOR (node->decl) && !DECL_STATIC_CONSTRUCTOR (node->decl)
...@@ -922,6 +922,9 @@ cgraph_only_called_directly_p (struct cgraph_node *node) ...@@ -922,6 +922,9 @@ cgraph_only_called_directly_p (struct cgraph_node *node)
static inline bool static inline bool
cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) 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); return !node->address_taken && cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
} }
......
...@@ -457,6 +457,15 @@ ipcp_cloning_candidate_p (struct cgraph_node *node) ...@@ -457,6 +457,15 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
if (cgraph_only_called_directly_p (node) || !node->analyzed) if (cgraph_only_called_directly_p (node) || !node->analyzed)
return false; 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 (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
{ {
if (dump_file) if (dump_file)
...@@ -561,7 +570,7 @@ ipcp_initialize_node_lattices (struct cgraph_node *node) ...@@ -561,7 +570,7 @@ ipcp_initialize_node_lattices (struct cgraph_node *node)
if (ipa_is_called_with_var_arguments (info)) if (ipa_is_called_with_var_arguments (info))
type = IPA_BOTTOM; type = IPA_BOTTOM;
else if (cgraph_only_called_directly_p (node)) else if (node->local.local)
type = IPA_TOP; type = IPA_TOP;
/* When cloning is allowed, we can assume that externally visible functions /* When cloning is allowed, we can assume that externally visible functions
are not called. We will compensate this by cloning later. */ are not called. We will compensate this by cloning later. */
......
...@@ -250,6 +250,10 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, ...@@ -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. /* We may eliminate the need for out-of-line copy to be output.
In that case just go ahead and re-use it. */ In that case just go ahead and re-use it. */
if (!e->callee->callers->next_caller 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) && cgraph_can_remove_if_no_direct_calls_p (e->callee)
/* Inlining might enable more devirtualizing, so we want to remove /* Inlining might enable more devirtualizing, so we want to remove
those only after all devirtualizable virtual calls are processed. those only after all devirtualizable virtual calls are processed.
...@@ -264,7 +268,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, ...@@ -264,7 +268,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
&& !cgraph_new_nodes) && !cgraph_new_nodes)
{ {
gcc_assert (!e->callee->global.inlined_to); 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; overall_size -= e->callee->global.size;
nfunctions_inlined++; nfunctions_inlined++;
...@@ -1449,7 +1453,8 @@ cgraph_decide_inlining (void) ...@@ -1449,7 +1453,8 @@ cgraph_decide_inlining (void)
struct cgraph_edge *e; struct cgraph_edge *e;
gcc_assert (inline_summary (node)->self_size == node->global.size); 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) for (e = node->callees; e; e = e->next_callee)
if (max_count < e->count) if (max_count < e->count)
max_count = e->count; max_count = e->count;
...@@ -1512,6 +1517,7 @@ cgraph_decide_inlining (void) ...@@ -1512,6 +1517,7 @@ cgraph_decide_inlining (void)
if (node->callers if (node->callers
&& !node->callers->next_caller && !node->callers->next_caller
&& !node->global.inlined_to
&& cgraph_will_be_removed_from_program_if_no_direct_calls (node) && cgraph_will_be_removed_from_program_if_no_direct_calls (node)
&& node->local.inlinable && node->local.inlinable
&& cgraph_function_body_availability (node) >= AVAIL_AVAILABLE && cgraph_function_body_availability (node) >= AVAIL_AVAILABLE
......
...@@ -1322,8 +1322,7 @@ propagate_pure_const (void) ...@@ -1322,8 +1322,7 @@ propagate_pure_const (void)
this_looping ? "looping " : "", this_looping ? "looping " : "",
cgraph_node_name (w)); cgraph_node_name (w));
} }
cgraph_set_readonly_flag (w, true); cgraph_set_const_flag (w, true, this_looping);
cgraph_set_looping_const_or_pure_flag (w, this_looping);
break; break;
case IPA_PURE: case IPA_PURE:
...@@ -1335,8 +1334,7 @@ propagate_pure_const (void) ...@@ -1335,8 +1334,7 @@ propagate_pure_const (void)
this_looping ? "looping " : "", this_looping ? "looping " : "",
cgraph_node_name (w)); cgraph_node_name (w));
} }
cgraph_set_pure_flag (w, true); cgraph_set_pure_flag (w, true, this_looping);
cgraph_set_looping_const_or_pure_flag (w, this_looping);
break; break;
default: default:
...@@ -1599,8 +1597,7 @@ local_pure_const (void) ...@@ -1599,8 +1597,7 @@ local_pure_const (void)
warn_function_const (current_function_decl, !l->looping); warn_function_const (current_function_decl, !l->looping);
if (!skip) if (!skip)
{ {
cgraph_set_readonly_flag (node, true); cgraph_set_const_flag (node, true, l->looping);
cgraph_set_looping_const_or_pure_flag (node, l->looping);
changed = true; changed = true;
} }
if (dump_file) if (dump_file)
...@@ -1614,7 +1611,7 @@ local_pure_const (void) ...@@ -1614,7 +1611,7 @@ local_pure_const (void)
{ {
if (!skip) if (!skip)
{ {
cgraph_set_looping_const_or_pure_flag (node, false); cgraph_set_const_flag (node, true, false);
changed = true; changed = true;
} }
if (dump_file) if (dump_file)
...@@ -1629,8 +1626,7 @@ local_pure_const (void) ...@@ -1629,8 +1626,7 @@ local_pure_const (void)
{ {
if (!skip) if (!skip)
{ {
cgraph_set_pure_flag (node, true); cgraph_set_pure_flag (node, true, l->looping);
cgraph_set_looping_const_or_pure_flag (node, l->looping);
changed = true; changed = true;
} }
warn_function_pure (current_function_decl, !l->looping); warn_function_pure (current_function_decl, !l->looping);
...@@ -1645,7 +1641,7 @@ local_pure_const (void) ...@@ -1645,7 +1641,7 @@ local_pure_const (void)
{ {
if (!skip) if (!skip)
{ {
cgraph_set_looping_const_or_pure_flag (node, false); cgraph_set_pure_flag (node, true, false);
changed = true; changed = true;
} }
if (dump_file) if (dump_file)
......
...@@ -57,8 +57,9 @@ cgraph_postorder (struct cgraph_node **order) ...@@ -57,8 +57,9 @@ cgraph_postorder (struct cgraph_node **order)
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
if (!node->aux if (!node->aux
&& (pass && (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; node2 = node;
if (!node->callers) if (!node->callers)
...@@ -237,15 +238,22 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -237,15 +238,22 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
gcc_assert (!vnode->aux); gcc_assert (!vnode->aux);
#endif #endif
varpool_reset_queue (); 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) for (node = cgraph_nodes; node; node = node->next)
if ((!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) if (node->analyzed && !node->global.inlined_to
/* Keep around virtual functions for possible devirtualization. */ && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
|| (!before_inlining_p /* Keep around virtual functions for possible devirtualization. */
&& !node->global.inlined_to || (before_inlining_p
&& DECL_VIRTUAL_P (node->decl) && DECL_VIRTUAL_P (node->decl)
&& (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl)))) && (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl)))
&& ((!DECL_EXTERNAL (node->decl)) /* Also external functions with address taken are better to stay
|| before_inlining_p)) for indirect inlining. */
|| (before_inlining_p
&& DECL_EXTERNAL (node->decl)
&& node->address_taken)))
{ {
gcc_assert (!node->global.inlined_to); gcc_assert (!node->global.inlined_to);
enqueue_cgraph_node (node, &first); enqueue_cgraph_node (node, &first);
...@@ -256,6 +264,8 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -256,6 +264,8 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
gcc_assert (!node->aux); gcc_assert (!node->aux);
node->reachable = false; node->reachable = false;
} }
/* Mark variables that are obviously needed. */
for (vnode = varpool_nodes; vnode; vnode = vnode->next) for (vnode = varpool_nodes; vnode; vnode = vnode->next)
{ {
vnode->next_needed = NULL; vnode->next_needed = NULL;
...@@ -428,10 +438,10 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) ...@@ -428,10 +438,10 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
node->clone_of->clones = node->next_sibling_clone; node->clone_of->clones = node->next_sibling_clone;
if (node->next_sibling_clone) if (node->next_sibling_clone)
node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone; node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
if (node->clone_of) if (node->clone_of)
node->former_clone_of = node->clone_of->decl; node->former_clone_of = node->clone_of->decl;
#endif #endif
node->clone_of = NULL; node->clone_of = NULL;
node->next_sibling_clone = NULL; node->next_sibling_clone = NULL;
node->prev_sibling_clone = NULL; node->prev_sibling_clone = NULL;
...@@ -771,6 +781,15 @@ function_and_variable_visibility (bool whole_program) ...@@ -771,6 +781,15 @@ function_and_variable_visibility (bool whole_program)
for (node = cgraph_nodes; node; node = node->next) 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 /* C++ FE on lack of COMDAT support create local COMDAT functions
(that ought to be shared but can not due to object format (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 limitations). It is neccesary to keep the flag to make rest of C++ FE
......
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> 2010-10-26 Ira Rosen <irar@il.ibm.com>
PR tree-optimization/46167 PR tree-optimization/46167
......
...@@ -510,9 +510,8 @@ tree_profiling (void) ...@@ -510,9 +510,8 @@ tree_profiling (void)
|| DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile) || DECL_STRUCT_FUNCTION (node->decl)->after_tree_profile)
continue; continue;
cgraph_set_readonly_flag (node, false); cgraph_set_const_flag (node, false, false);
cgraph_set_pure_flag (node, false); cgraph_set_pure_flag (node, false, false);
cgraph_set_looping_const_or_pure_flag (node, false);
} }
/* Update call statements and rebuild the cgraph. */ /* Update call statements and rebuild the cgraph. */
......
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