Commit 39e2db00 by Jan Hubicka Committed by Jan Hubicka

lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code.

	* lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code.
	(lto_symtab_resolve_can_prevail_p): Likewise.
	(lto_symtab_merge_cgraph_nodes): Update merging of aliases.
	* cgraph.c (same_body_aliases_done): New global var.
	(cgraph_same_body_alias_1): Rename to ...
	(cgraph_create_function_alias): ... this one; reorg to new
	representation.
	(cgraph_same_body_alias): Use cgraph_create_function_alias;
	record references when asked to.
	(cgraph_add_thunk): Fix formating.
	(cgraph_get_node): Kill same body alias code.
	(cgraph_node_for_asm): Likewise.
	(cgraph_remove_same_body_alias): Remove.
	(cgraph_remove_node): Kill same body alias code.
	(cgraph_mark_address_taken_node): Mark also the aliased function
	as having address taken.
	(dump_cgraph_node): Dump same body aliases.
	(cgraph_for_node_thunks_and_aliases): Update for new alias
	representation.
	(cgraph_for_node_and_aliases): Likewise.
	* cgraph.h (same_body): Kll pointer.
	(same_body_alias): Update comment.
	(same_body_aliases_done): Declare.
	(cgraph_remove_same_body_alias): Remove declaration.
	(cgraph_create_function_alias): Declare.
	(cgraph_process_same_body_aliases): Declare.
	(cgraph_function_with_gimple_body_p): Check for alias.
	(cgraph_can_remove_if_no_direct_calls_p): Look for aliases.
	(cgraph_alias_aliased_node): New function.
	(cgraph_function_node): Update for new aliases.
	(cgraph_function_or_thunk_node): Likewise.
	* ipa-inline-transform.c (can_remove_node_now_p): Look for aliases.
	(inline_call): Remove dead aliases.
	* cgraphunit.c (cgraph_decide_is_function_needed): Disable assembler name
	hack for same body aliases.
	(clone_of_p): Look through aliases.
	(verify_cgraph_node): Verify aliases.
	(cgraph_analyze_function): Analyze aliases; fixup C++ bugs.
	(cgraph_process_same_body_aliases): New function.
	(process_function_and_variable_attributes): Disable weakref warning on
	alias.
	(cgraph_analyze_functions): Handle aliases.
	(cgraph_mark_functions_to_output): Handle aliases same way as thunks.
	(assemble_thunks): Rename to ...
	(assemble_thunks_and_aliases): ... this one; handle aliases, too.
	(cgraph_expand_function): Remove alias output code.
	(cgraph_output_in_order): Skip aliases.
	(cgraph_preserve_function_body_p): Aliases don't need preserving.
	* ipa-ref.c (ipa_ref_use_name): Add alias reference.
	(ipa_record_reference): Do not assert on alias references.
	(ipa_ref_has_aliases_p): New function.
	* ipa-ref.h (enum ipa_ref_use): Add IPA_REF_ALIAS.
	(ipa_ref_has_aliases_p): Declare.
	* lto-cgraph.c (lto_output_node): Handle aliases.
	(input_node): Likewise.
	* lto-streamer-out.c (lto_output): Skip aliases.
	(produce_symtab): Kill same_body_alias code.
	* ipa-utils.c (ipa_reverse_postorder): Add FIXME.
	(ipa_reverse_postorder): Use cgraph_only_called_directly_or_aliased_p.
	* ipa-inline.c (update_caller_keys): Walk aliases.
	(inline_small_functions): Fix thinko in previous patch.
	* ipa.c (cgraph_externally_visible_p): Do not walk aliases.
	(function_and_variable_visibility): Do not walk same body aliases.
	* tree-ssa-structalias.c (associate_varinfo_to_alias): New function.
	(ipa_pta_execute): Use it.

	* lto.c (add_cgraph_node_to_partition_1): Break out from ...
	(add_cgraph_node_to_partition) ... here; walk aliases.
	(lto_1_to_1_map): Remove same body alias code.
	(promote_fn): Likewise.
	(lto_promote_cross_file_statics): Update comment.

	* decl2.c (cp_write_global_declarations): Process aliases; look trhough
	same body aliases.

From-SVN: r174952
parent c44ddf96
2011-06-11 Jan Hubicka <jh@suse.cz>
* lto-symtab.c (lto_cgraph_replace_node): Kill same body alias code.
(lto_symtab_resolve_can_prevail_p): Likewise.
(lto_symtab_merge_cgraph_nodes): Update merging of aliases.
* cgraph.c (same_body_aliases_done): New global var.
(cgraph_same_body_alias_1): Rename to ...
(cgraph_create_function_alias): ... this one; reorg to new
representation.
(cgraph_same_body_alias): Use cgraph_create_function_alias;
record references when asked to.
(cgraph_add_thunk): Fix formating.
(cgraph_get_node): Kill same body alias code.
(cgraph_node_for_asm): Likewise.
(cgraph_remove_same_body_alias): Remove.
(cgraph_remove_node): Kill same body alias code.
(cgraph_mark_address_taken_node): Mark also the aliased function
as having address taken.
(dump_cgraph_node): Dump same body aliases.
(cgraph_for_node_thunks_and_aliases): Update for new alias
representation.
(cgraph_for_node_and_aliases): Likewise.
* cgraph.h (same_body): Kll pointer.
(same_body_alias): Update comment.
(same_body_aliases_done): Declare.
(cgraph_remove_same_body_alias): Remove declaration.
(cgraph_create_function_alias): Declare.
(cgraph_process_same_body_aliases): Declare.
(cgraph_function_with_gimple_body_p): Check for alias.
(cgraph_can_remove_if_no_direct_calls_p): Look for aliases.
(cgraph_alias_aliased_node): New function.
(cgraph_function_node): Update for new aliases.
(cgraph_function_or_thunk_node): Likewise.
* ipa-inline-transform.c (can_remove_node_now_p): Look for aliases.
(inline_call): Remove dead aliases.
* cgraphunit.c (cgraph_decide_is_function_needed): Disable assembler name
hack for same body aliases.
(clone_of_p): Look through aliases.
(verify_cgraph_node): Verify aliases.
(cgraph_analyze_function): Analyze aliases; fixup C++ bugs.
(cgraph_process_same_body_aliases): New function.
(process_function_and_variable_attributes): Disable weakref warning on
alias.
(cgraph_analyze_functions): Handle aliases.
(cgraph_mark_functions_to_output): Handle aliases same way as thunks.
(assemble_thunks): Rename to ...
(assemble_thunks_and_aliases): ... this one; handle aliases, too.
(cgraph_expand_function): Remove alias output code.
(cgraph_output_in_order): Skip aliases.
(cgraph_preserve_function_body_p): Aliases don't need preserving.
* ipa-ref.c (ipa_ref_use_name): Add alias reference.
(ipa_record_reference): Do not assert on alias references.
(ipa_ref_has_aliases_p): New function.
* ipa-ref.h (enum ipa_ref_use): Add IPA_REF_ALIAS.
(ipa_ref_has_aliases_p): Declare.
* lto-cgraph.c (lto_output_node): Handle aliases.
(input_node): Likewise.
* lto-streamer-out.c (lto_output): Skip aliases.
(produce_symtab): Kill same_body_alias code.
* ipa-utils.c (ipa_reverse_postorder): Add FIXME.
(ipa_reverse_postorder): Use cgraph_only_called_directly_or_aliased_p.
* ipa-inline.c (update_caller_keys): Walk aliases.
(inline_small_functions): Fix thinko in previous patch.
* ipa.c (cgraph_externally_visible_p): Do not walk aliases.
(function_and_variable_visibility): Do not walk same body aliases.
* tree-ssa-structalias.c (associate_varinfo_to_alias): New function.
(ipa_pta_execute): Use it.
2011-06-11 Uros Bizjak <ubizjak@gmail.com>
* config/i386/sse.md (vec_dupv4sf): Correct mode of forced register.
......
......@@ -208,6 +208,9 @@ static GTY(()) struct cgraph_node *free_nodes;
Do not GTY((delete)) this list so UIDs gets reliably recycled. */
static GTY(()) struct cgraph_edge *free_edges;
/* Did procss_same_body_aliases run? */
bool same_body_aliases_done;
/* Macros to access the next item in the list of free cgraph nodes and
edges. */
#define NEXT_FREE_NODE(NODE) (NODE)->next
......@@ -542,33 +545,23 @@ cgraph_get_create_node (tree decl)
/* Mark ALIAS as an alias to DECL. DECL_NODE is cgraph node representing
the function body is associated with (not neccesarily cgraph_node (DECL). */
static struct cgraph_node *
cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl)
struct cgraph_node *
cgraph_create_function_alias (tree alias, tree decl)
{
struct cgraph_node key, *alias_node, **slot;
struct cgraph_node *alias_node;
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
gcc_assert (TREE_CODE (alias) == FUNCTION_DECL);
key.decl = alias;
slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
/* If the cgraph_node has been already created, fail. */
if (*slot)
return NULL;
alias_node = cgraph_allocate_node ();
alias_node->decl = alias;
alias_node->same_body_alias = 1;
alias_node->same_body = decl_node;
alias_node->previous = NULL;
if (decl_node->same_body)
decl_node->same_body->previous = alias_node;
alias_node->next = decl_node->same_body;
alias_node = cgraph_get_create_node (alias);
gcc_assert (!alias_node->local.finalized);
alias_node->thunk.alias = decl;
decl_node->same_body = alias_node;
*slot = alias_node;
alias_node->local.finalized = true;
alias_node->alias = 1;
if ((TREE_PUBLIC (alias) && !DECL_COMDAT (alias) && !DECL_EXTERNAL (alias))
|| (DECL_VIRTUAL_P (alias)
&& (DECL_COMDAT (alias) || DECL_EXTERNAL (alias))))
cgraph_mark_reachable_node (alias_node);
return alias_node;
}
......@@ -578,16 +571,24 @@ cgraph_same_body_alias_1 (struct cgraph_node *decl_node, tree alias, tree decl)
and cgraph_get_node (ALIAS) transparently returns cgraph_get_node (DECL). */
struct cgraph_node *
cgraph_same_body_alias (struct cgraph_node *decl_node, tree alias, tree decl)
cgraph_same_body_alias (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, tree alias, tree decl)
{
struct cgraph_node *n;
#ifndef ASM_OUTPUT_DEF
/* If aliases aren't supported by the assembler, fail. */
return NULL;
#endif
/* Langhooks can create same body aliases of symbols not defined.
Those are useless. Drop them on the floor. */
if (cgraph_global_info_ready)
return NULL;
/*gcc_assert (!assembler_name_hash);*/
return cgraph_same_body_alias_1 (decl_node, alias, decl);
n = cgraph_create_function_alias (alias, decl);
n->same_body_alias = true;
if (same_body_aliases_done)
ipa_record_reference (n, NULL, cgraph_get_node (decl), NULL, IPA_REF_ALIAS,
NULL);
return n;
}
/* Add thunk alias into callgraph. The alias declaration is ALIAS and it
......@@ -633,6 +634,7 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED,
|| (DECL_VIRTUAL_P (decl)
&& (DECL_COMDAT (decl) || DECL_EXTERNAL (decl))))
cgraph_mark_reachable_node (node);
return node;
}
......@@ -678,11 +680,7 @@ cgraph_get_node (const_tree decl)
NO_INSERT);
if (slot && *slot)
{
node = *slot;
if (node->same_body_alias)
node = node->same_body;
}
return node;
}
......@@ -745,21 +743,6 @@ cgraph_node_for_asm (tree asmname)
so lets hope for the best. */
if (!*slot)
*slot = node;
if (node->same_body)
{
struct cgraph_node *alias;
for (alias = node->same_body; alias; alias = alias->next)
{
hashval_t hash;
name = DECL_ASSEMBLER_NAME (alias->decl);
hash = decl_assembler_name_hash (name);
slot = htab_find_slot_with_hash (assembler_name_hash, name,
hash, INSERT);
if (!*slot)
*slot = alias;
}
}
}
}
......@@ -770,8 +753,6 @@ cgraph_node_for_asm (tree asmname)
if (slot)
{
node = (struct cgraph_node *) *slot;
if (node->same_body_alias)
node = node->same_body;
return node;
}
return NULL;
......@@ -1432,44 +1413,6 @@ cgraph_release_function_body (struct cgraph_node *node)
DECL_INITIAL (node->decl) = error_mark_node;
}
/* Remove same body alias node. */
void
cgraph_remove_same_body_alias (struct cgraph_node *node)
{
void **slot;
int uid = node->uid;
gcc_assert (node->same_body_alias);
if (node->previous)
node->previous->next = node->next;
else
node->same_body->same_body = node->next;
if (node->next)
node->next->previous = node->previous;
node->next = NULL;
node->previous = NULL;
slot = htab_find_slot (cgraph_hash, node, NO_INSERT);
if (*slot == node)
htab_clear_slot (cgraph_hash, slot);
if (assembler_name_hash)
{
tree name = DECL_ASSEMBLER_NAME (node->decl);
slot = htab_find_slot_with_hash (assembler_name_hash, name,
decl_assembler_name_hash (name),
NO_INSERT);
if (slot && *slot == node)
htab_clear_slot (assembler_name_hash, slot);
}
/* Clear out the node to NULL all pointers and add the node to the free
list. */
memset (node, 0, sizeof(*node));
node->uid = uid;
NEXT_FREE_NODE (node) = free_nodes;
free_nodes = node;
}
/* Remove the node from cgraph. */
void
......@@ -1631,9 +1574,6 @@ cgraph_remove_node (struct cgraph_node *node)
}
}
while (node->same_body)
cgraph_remove_same_body_alias (node->same_body);
if (node->same_comdat_group)
{
struct cgraph_node *prev;
......@@ -1747,6 +1687,14 @@ cgraph_mark_address_taken_node (struct cgraph_node *node)
{
gcc_assert (!node->global.inlined_to);
cgraph_mark_reachable_node (node);
/* FIXME: address_taken flag is used both as a shortcut for testing whether
IPA_REF_ADDR reference exists (and thus it should be set on node
representing alias we take address of) and as a test whether address
of the object was taken (and thus it should be set on node alias is
referring to). We should remove the first use and the remove the
following set. */
node->address_taken = 1;
node = cgraph_function_or_thunk_node (node, NULL);
node->address_taken = 1;
}
......@@ -1902,6 +1850,15 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
(int)node->thunk.virtual_value,
(int)node->thunk.virtual_offset_p);
}
if (node->alias && node->thunk.alias)
{
fprintf (f, " alias of %s",
lang_hooks.decl_printable_name (node->thunk.alias, 2));
if (DECL_ASSEMBLER_NAME_SET_P (node->thunk.alias))
fprintf (f, " (asm: %s)",
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->thunk.alias)));
fprintf (f, "\n");
}
fprintf (f, " called by: ");
......@@ -1952,19 +1909,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
if (indirect_calls_count)
fprintf (f, " has %i outgoing edges for indirect calls.\n",
indirect_calls_count);
if (node->same_body)
{
struct cgraph_node *n;
fprintf (f, " aliases:");
for (n = node->same_body; n; n = n->next)
{
fprintf (f, " %s/%i", cgraph_node_name (n), n->uid);
if (DECL_ASSEMBLER_NAME_SET_P (n->decl))
fprintf (f, " (asm: %s)", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
}
fprintf (f, "\n");
}
}
......@@ -2614,18 +2558,24 @@ cgraph_for_node_thunks_and_aliases (struct cgraph_node *node,
bool include_overwritable)
{
struct cgraph_edge *e;
struct cgraph_node *alias;
int i;
struct ipa_ref *ref;
if (callback (node, data))
return true;
for (alias = node->same_body; alias; alias = alias->next)
if (callback (alias, data))
return true;
for (e = node->callers; e; e = e->next_caller)
if (e->caller->thunk.thunk_p
&& (include_overwritable
|| cgraph_function_body_availability (e->caller) > AVAIL_OVERWRITABLE))
|| cgraph_function_body_availability (e->caller)))
cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable);
for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS)
{
struct cgraph_node *alias = ipa_ref_refering_node (ref);
if (include_overwritable
|| cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
cgraph_for_node_thunks_and_aliases (alias, callback, data, include_overwritable);
}
return false;
}
......@@ -2637,15 +2587,21 @@ bool
cgraph_for_node_and_aliases (struct cgraph_node *node,
bool (*callback) (struct cgraph_node *, void *),
void *data,
bool include_overwritable ATTRIBUTE_UNUSED)
bool include_overwritable)
{
struct cgraph_node *alias;
int i;
struct ipa_ref *ref;
if (callback (node, data))
return true;
for (alias = node->same_body; alias; alias = alias->next)
if (callback (alias, data))
return true;
for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS)
{
struct cgraph_node *alias = ipa_ref_refering_node (ref);
if (include_overwritable
|| cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
cgraph_for_node_and_aliases (alias, callback, data, include_overwritable);
}
return false;
}
......
......@@ -165,9 +165,6 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
struct cgraph_node *prev_sibling_clone;
struct cgraph_node *clones;
struct cgraph_node *clone_of;
/* For normal nodes pointer to the list of alias and thunk nodes,
in alias/thunk nodes pointer to the normal node. */
struct cgraph_node *same_body;
/* Circular list of nodes in the same comdat group if non-NULL. */
struct cgraph_node *same_comdat_group;
/* For functions with many calls sites it holds map from call expression
......@@ -236,8 +233,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
unsigned process : 1;
/* Set for aliases once they got through assemble_alias. */
unsigned alias : 1;
/* Set for alias and thunk nodes, same_body points to the node they are alias
of and they are linked through the next/previous pointers. */
/* Set for aliases created as C++ same body aliases. */
unsigned same_body_alias : 1;
/* How commonly executed the node is. Initialized during branch
probabilities pass. */
......@@ -463,6 +459,7 @@ extern GTY(()) struct cgraph_node *cgraph_new_nodes;
extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
extern GTY(()) int cgraph_order;
extern bool same_body_aliases_done;
/* In cgraph.c */
void dump_cgraph (FILE *);
......@@ -488,7 +485,6 @@ struct cgraph_node * cgraph_get_create_node (tree);
struct cgraph_node * cgraph_same_body_alias (struct cgraph_node *, tree, tree);
struct cgraph_node * cgraph_add_thunk (struct cgraph_node *, tree, tree, bool, HOST_WIDE_INT,
HOST_WIDE_INT, tree, tree);
void cgraph_remove_same_body_alias (struct cgraph_node *);
struct cgraph_node *cgraph_node_for_asm (tree);
struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
void cgraph_set_call_stmt (struct cgraph_edge *, gimple);
......@@ -508,6 +504,7 @@ struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *,
struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
int, bool, VEC(cgraph_edge_p,heap) *,
bool);
struct cgraph_node *cgraph_create_function_alias (tree, tree);
void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
......@@ -577,6 +574,7 @@ void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bi
bitmap, basic_block);
void record_references_in_initializer (tree, bool);
bool cgraph_process_new_functions (void);
void cgraph_process_same_body_aliases (void);
bool cgraph_decide_is_function_needed (struct cgraph_node *, tree);
......@@ -746,7 +744,7 @@ cgraph_next_defined_function (struct cgraph_node *node)
static inline bool
cgraph_function_with_gimple_body_p (struct cgraph_node *node)
{
return node->analyzed && !node->thunk.thunk_p;
return node->analyzed && !node->thunk.thunk_p && !node->alias;
}
/* Return first function with body defined. */
......@@ -934,7 +932,8 @@ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
if (DECL_EXTERNAL (node->decl))
return true;
return (!node->address_taken
&& cgraph_can_remove_if_no_direct_calls_and_refs_p (node));
&& cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
&& !ipa_ref_has_aliases_p (&node->ref_list));
}
/* Return true when function NODE can be removed from callgraph
......@@ -968,6 +967,20 @@ htab_t constant_pool_htab (void);
/* FIXME: inappropriate dependency of cgraph on IPA. */
#include "ipa-ref-inline.h"
/* Return node that alias N is aliasing. */
static inline struct cgraph_node *
cgraph_alias_aliased_node (struct cgraph_node *n)
{
struct ipa_ref *ref;
ipa_ref_list_reference_iterate (&n->ref_list, 0, ref);
gcc_checking_assert (ref->use == IPA_REF_ALIAS);
if (ref->refered_type == IPA_REF_CGRAPH)
return ipa_ref_node (ref);
return NULL;
}
/* Given NODE, walk the alias chain to return the function NODE is alias of.
Walk through thunk, too.
When AVAILABILITY is non-NULL, get minimal availablity in the chain. */
......@@ -979,11 +992,13 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability)
*availability = cgraph_function_body_availability (node);
while (node)
{
if (node->thunk.thunk_p)
if (node->alias && node->analyzed)
node = cgraph_alias_aliased_node (node);
else if (node->thunk.thunk_p)
node = node->callees->callee;
else
return node;
if (availability)
if (node && availability)
{
enum availability a;
a = cgraph_function_body_availability (node);
......@@ -991,6 +1006,8 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability)
*availability = a;
}
}
if (*availability)
*availability = AVAIL_NOT_AVAILABLE;
return NULL;
}
......@@ -1003,7 +1020,22 @@ cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *avai
{
if (availability)
*availability = cgraph_function_body_availability (node);
while (node)
{
if (node->alias && node->analyzed)
node = cgraph_alias_aliased_node (node);
else
return node;
if (node && availability)
{
enum availability a;
a = cgraph_function_body_availability (node);
if (a < *availability)
*availability = a;
}
}
if (*availability)
*availability = AVAIL_NOT_AVAILABLE;
return NULL;
}
......
2011-06-11 Jan Hubicka <jh@suse.cz>
* decl2.c (cp_write_global_declarations): Process aliases; look trhough
same body aliases.
2011-06-10 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/41769
......
......@@ -3672,6 +3672,8 @@ cp_write_global_declarations (void)
if (pch_file)
c_common_write_pch ();
cgraph_process_same_body_aliases ();
/* Handle -fdump-ada-spec[-slim] */
if (dump_enabled_p (TDI_ada))
{
......@@ -3869,6 +3871,8 @@ cp_write_global_declarations (void)
struct cgraph_node *node, *next;
node = cgraph_get_node (decl);
if (node->same_body_alias)
node = cgraph_alias_aliased_node (node);
cgraph_for_node_and_aliases (node, clear_decl_external,
NULL, true);
......
......@@ -3363,9 +3363,8 @@ cp_fix_function_decl_p (tree decl)
/* Don't fix same_body aliases. Although they don't have their own
CFG, they share it with what they alias to. */
if (!node
|| node->decl == decl
|| !node->same_body)
if (!node || !node->alias
|| !VEC_length (ipa_ref_t, node->ref_list.references))
return true;
}
......
......@@ -88,6 +88,7 @@ can_remove_node_now_p (struct cgraph_node *node)
can remove its offline copy, but we would need to keep unanalyzed node in
the callgraph so references can point to it. */
return (!node->address_taken
&& !ipa_ref_has_aliases_p (&node->ref_list)
&& cgraph_can_remove_if_no_direct_calls_p (node)
/* Inlining might enable more devirtualizing, so we want to remove
those only after all devirtualizable virtual calls are processed.
......@@ -192,7 +193,22 @@ inline_call (struct cgraph_edge *e, bool update_original,
/* If aliases are involved, redirect edge to the actual destination and
possibly remove the aliases. */
if (e->callee != callee)
{
struct cgraph_node *alias = e->callee, *next_alias;
cgraph_redirect_edge_callee (e, callee);
while (alias && alias != callee)
{
if (!alias->callers
&& can_remove_node_now_p (alias))
{
next_alias = cgraph_alias_aliased_node (alias);
cgraph_remove_node (alias);
alias = next_alias;
}
else
break;
}
}
clone_inlined_nodes (e, true, update_original, overall_size);
......
......@@ -965,6 +965,8 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
struct cgraph_edge *check_inlinablity_for)
{
struct cgraph_edge *edge;
int i;
struct ipa_ref *ref;
if (!inline_summary (node)->inlinable
|| cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE
......@@ -973,6 +975,13 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
if (!bitmap_set_bit (updated_nodes, node->uid))
return;
for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS)
{
struct cgraph_node *alias = ipa_ref_refering_node (ref);
update_caller_keys (heap, alias, updated_nodes, check_inlinablity_for);
}
for (edge = node->callers; edge; edge = edge->next_caller)
if (edge->inline_failed)
{
......@@ -1451,7 +1460,7 @@ inline_small_functions (void)
where = edge->caller;
while (where->global.inlined_to)
{
if (where->decl == edge->callee->decl)
if (where->decl == callee->decl)
outer_node = where, depth++;
where = where->callers->caller;
}
......
......@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "cgraph.h"
static const char *ipa_ref_use_name[] = {"read","write","addr"};
static const char *ipa_ref_use_name[] = {"read","write","addr","alias"};
/* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE
to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
......@@ -46,6 +46,7 @@ ipa_record_reference (struct cgraph_node *refering_node,
gcc_assert ((!refering_node) ^ (!refering_varpool_node));
gcc_assert ((!refered_node) ^ (!refered_varpool_node));
gcc_assert (!stmt || refering_node);
gcc_assert (use_type != IPA_REF_ALIAS || !stmt);
list = (refering_node ? &refering_node->ref_list
: &refering_varpool_node->ref_list);
......@@ -73,7 +74,7 @@ ipa_record_reference (struct cgraph_node *refering_node,
{
ref->refered.cgraph_node = refered_node;
ref->refered_type = IPA_REF_CGRAPH;
gcc_assert (use_type == IPA_REF_ADDR);
gcc_assert (use_type == IPA_REF_ADDR || use_type == IPA_REF_ALIAS);
}
else
{
......@@ -241,3 +242,15 @@ ipa_ref_cannot_lead_to_return (struct ipa_ref *ref)
{
return cgraph_node_cannot_return (ipa_ref_refering_node (ref));
}
/* Return true if list contains an alias. */
bool
ipa_ref_has_aliases_p (struct ipa_ref_list *ref_list)
{
struct ipa_ref *ref;
int i;
for (i = 0; ipa_ref_list_refering_iterate (ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS)
return true;
return false;
}
......@@ -27,7 +27,8 @@ enum GTY(()) ipa_ref_use
{
IPA_REF_LOAD,
IPA_REF_STORE,
IPA_REF_ADDR
IPA_REF_ADDR,
IPA_REF_ALIAS
};
/* Type of refering or refered type. */
......@@ -89,4 +90,4 @@ void ipa_dump_refering (FILE *, struct ipa_ref_list *);
void ipa_clone_references (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
void ipa_clone_refering (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
bool ipa_ref_cannot_lead_to_return (struct ipa_ref *);
bool ipa_ref_has_aliases_p (struct ipa_ref_list *);
......@@ -234,7 +234,8 @@ ipa_free_postorder_info (void)
}
/* Fill array order with all nodes with output flag set in the reverse
topological order. Return the number of elements in the array. */
topological order. Return the number of elements in the array.
FIXME: While walking, consider aliases, too. */
int
ipa_reverse_postorder (struct cgraph_node **order)
......@@ -260,7 +261,7 @@ ipa_reverse_postorder (struct cgraph_node **order)
&& (pass
|| (!node->address_taken
&& !node->global.inlined_to
&& !cgraph_only_called_directly_p (node))))
&& !cgraph_only_called_directly_or_aliased_p (node))))
{
node2 = node;
if (!node->callers)
......
......@@ -581,9 +581,9 @@ cgraph_comdat_can_be_unshared_p (struct cgraph_node *node)
/* Return true when function NODE should be considered externally visible. */
static bool
cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool aliased)
cgraph_externally_visible_p (struct cgraph_node *node,
bool whole_program, bool aliased)
{
struct cgraph_node *alias;
if (!node->local.finalized)
return false;
if (!DECL_COMDAT (node->decl)
......@@ -630,18 +630,6 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
&& cgraph_comdat_can_be_unshared_p (node))
return false;
/* See if we have linker information about symbol not being used or
if we need to make guess based on the declaration.
Even if the linker clams the symbol is unused, never bring internal
symbols that are declared by user as used or externally visible.
This is needed for i.e. references from asm statements. */
for (alias = node->same_body; alias; alias = alias->next)
if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY)
break;
if (!alias && node->resolution == LDPR_PREVAILING_DEF_IRONLY)
return false;
/* When doing link time optimizations, hidden symbols become local. */
if (in_lto_p
&& (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
......@@ -881,12 +869,9 @@ function_and_variable_visibility (bool whole_program)
if (!node->local.externally_visible && node->analyzed
&& !DECL_EXTERNAL (node->decl))
{
struct cgraph_node *alias;
gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl));
cgraph_make_decl_local (node->decl);
node->resolution = LDPR_PREVAILING_DEF_IRONLY;
for (alias = node->same_body; alias; alias = alias->next)
cgraph_make_decl_local (alias->decl);
if (node->same_comdat_group)
/* cgraph_externally_visible_p has already checked all other nodes
in the group and they will all be made local. We need to
......@@ -900,8 +885,7 @@ function_and_variable_visibility (bool whole_program)
{
struct cgraph_node *decl_node = node;
while (decl_node->thunk.thunk_p)
decl_node = decl_node->callees->callee;
decl_node = cgraph_function_node (decl_node->callees->callee, NULL);
/* Thunks have the same visibility as function they are attached to.
For some reason C++ frontend don't seem to care. I.e. in
......@@ -933,9 +917,9 @@ function_and_variable_visibility (bool whole_program)
if (DECL_EXTERNAL (decl_node->decl))
DECL_EXTERNAL (node->decl) = 1;
}
node->local.local = cgraph_local_node_p (node);
}
for (node = cgraph_nodes; node; node = node->next)
node->local.local = cgraph_local_node_p (node);
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
{
/* weak flag makes no sense on local variables. */
......
......@@ -504,7 +504,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
|| referenced_from_other_partition_p (&node->ref_list, set, vset)), 1);
bp_pack_value (&bp, node->lowered, 1);
bp_pack_value (&bp, in_other_partition, 1);
bp_pack_value (&bp, node->alias, 1);
bp_pack_value (&bp, node->alias && !boundary_p, 1);
bp_pack_value (&bp, node->frequency, 2);
bp_pack_value (&bp, node->only_called_at_startup, 1);
bp_pack_value (&bp, node->only_called_at_exit, 1);
......@@ -523,32 +523,15 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
node->thunk.fixed_offset);
lto_output_uleb128_stream (ob->main_stream,
node->thunk.virtual_value);
lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
node->thunk.alias);
}
if (node->same_body)
{
struct cgraph_node *alias;
unsigned long alias_count = 1;
for (alias = node->same_body; alias->next; alias = alias->next)
alias_count++;
lto_output_uleb128_stream (ob->main_stream, alias_count);
do
if ((node->alias || node->thunk.thunk_p) && !boundary_p)
{
lto_output_int_in_range (ob->main_stream, 0, 1,
node->thunk.alias != NULL);
if (node->thunk.alias != NULL)
lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
alias->decl);
lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
alias->thunk.alias);
gcc_assert (cgraph_get_node (alias->thunk.alias) == node);
lto_output_enum (ob->main_stream, ld_plugin_symbol_resolution,
LDPR_NUM_KNOWN, alias->resolution);
alias = alias->previous;
}
while (alias);
node->thunk.alias);
}
else
lto_output_uleb128_stream (ob->main_stream, 0);
}
/* Output the varpool NODE to OB.
......@@ -997,7 +980,6 @@ input_node (struct lto_file_decl_data *file_data,
struct bitpack_d bp;
unsigned decl_index;
int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND;
unsigned long same_body_count = 0;
int clone_ref;
clone_ref = lto_input_sleb128 (ib);
......@@ -1043,31 +1025,20 @@ input_node (struct lto_file_decl_data *file_data,
int type = lto_input_uleb128 (ib);
HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib);
HOST_WIDE_INT virtual_value = lto_input_uleb128 (ib);
tree real_alias;
decl_index = lto_input_uleb128 (ib);
real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
node->thunk.fixed_offset = fixed_offset;
node->thunk.this_adjusting = (type & 2);
node->thunk.virtual_value = virtual_value;
node->thunk.virtual_offset_p = (type & 4);
node->thunk.alias = real_alias;
}
same_body_count = lto_input_uleb128 (ib);
while (same_body_count-- > 0)
if (node->thunk.thunk_p || node->alias)
{
if (lto_input_int_in_range (ib, "alias nonzero flag", 0, 1))
{
tree alias_decl, real_alias;
struct cgraph_node *alias;
decl_index = lto_input_uleb128 (ib);
alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
decl_index = lto_input_uleb128 (ib);
real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
alias = cgraph_same_body_alias (node, alias_decl, real_alias);
gcc_assert (alias);
alias->resolution = lto_input_enum (ib, ld_plugin_symbol_resolution,
LDPR_NUM_KNOWN);
node->thunk.alias = lto_file_decl_data_get_fn_decl (file_data,
decl_index);
}
}
return node;
}
......
......@@ -2253,6 +2253,7 @@ lto_output (cgraph_node_set set, varpool_node_set vset)
{
node = lto_cgraph_encoder_deref (encoder, i);
if (lto_cgraph_encoder_encode_body_p (encoder, node)
&& !node->alias
&& !node->thunk.thunk_p)
{
#ifdef ENABLE_CHECKING
......@@ -2551,7 +2552,7 @@ produce_symtab (struct output_block *ob,
struct lto_streamer_cache_d *cache = ob->writer_cache;
char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
struct pointer_set_t *seen;
struct cgraph_node *node, *alias;
struct cgraph_node *node;
struct varpool_node *vnode, *valias;
struct lto_output_stream stream;
lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
......@@ -2584,8 +2585,6 @@ produce_symtab (struct output_block *ob,
if (node->alias || node->global.inlined_to)
continue;
write_symbol (cache, &stream, node->decl, seen, false);
for (alias = node->same_body; alias; alias = alias->next)
write_symbol (cache, &stream, alias->decl, seen, true);
}
for (i = 0; i < lto_cgraph_encoder_size (encoder); i++)
{
......@@ -2598,8 +2597,6 @@ produce_symtab (struct output_block *ob,
if (node->alias || node->global.inlined_to)
continue;
write_symbol (cache, &stream, node->decl, seen, false);
for (alias = node->same_body; alias; alias = alias->next)
write_symbol (cache, &stream, alias->decl, seen, true);
}
/* Write all variables. */
......
......@@ -209,7 +209,6 @@ lto_cgraph_replace_node (struct cgraph_node *node,
struct cgraph_node *prevailing_node)
{
struct cgraph_edge *e, *next;
bool no_aliases_please = false;
bool compatible_p;
if (cgraph_dump_file)
......@@ -223,13 +222,6 @@ lto_cgraph_replace_node (struct cgraph_node *node,
(IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)))));
}
if (prevailing_node->same_body_alias)
{
if (prevailing_node->thunk.thunk_p)
no_aliases_please = true;
prevailing_node = prevailing_node->same_body;
}
/* Merge node flags. */
if (node->needed)
cgraph_mark_needed_node (prevailing_node);
......@@ -259,35 +251,7 @@ lto_cgraph_replace_node (struct cgraph_node *node,
/* Redirect incomming references. */
ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
/* If we have aliases, redirect them to the prevailing node. */
if (!node->same_body_alias && node->same_body)
{
struct cgraph_node *alias, *last;
/* We prevail aliases/tunks by a thunk. This is doable but
would need thunk combination. Hopefully no ABI changes will
every be crazy enough. */
gcc_assert (!no_aliases_please);
for (alias = node->same_body; alias; alias = alias->next)
{
last = alias;
gcc_assert (alias->same_body_alias);
alias->same_body = prevailing_node;
}
last->next = prevailing_node->same_body;
/* Node with aliases is prevailed by alias.
We could handle this, but combining thunks together will be tricky.
Hopefully this does not happen. */
if (prevailing_node->same_body)
prevailing_node->same_body->previous = last;
prevailing_node->same_body = node->same_body;
node->same_body = NULL;
}
/* Finally remove the replaced node. */
if (node->same_body_alias)
cgraph_remove_same_body_alias (node);
else
cgraph_remove_node (node);
}
......@@ -472,9 +436,7 @@ lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e)
/* For functions we need a non-discarded body. */
if (TREE_CODE (e->decl) == FUNCTION_DECL)
return (e->node
&& (e->node->analyzed
|| (e->node->same_body_alias && e->node->same_body->analyzed)));
return (e->node && e->node->analyzed);
/* A variable should have a size. */
else if (TREE_CODE (e->decl) == VAR_DECL)
......@@ -816,20 +778,14 @@ lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED)
void
lto_symtab_merge_cgraph_nodes (void)
{
struct cgraph_node *node, *alias, *next;
struct cgraph_node *node;
lto_symtab_maybe_init_hash_table ();
htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL);
for (node = cgraph_nodes; node; node = node->next)
{
if (node->thunk.thunk_p)
if ((node->thunk.thunk_p || node->alias)
&& node->thunk.alias)
node->thunk.alias = lto_symtab_prevailing_decl (node->thunk.alias);
for (alias = node->same_body; alias; alias = next)
{
next = alias->next;
alias->thunk.alias = lto_symtab_prevailing_decl (alias->thunk.alias);
}
}
}
/* Given the decl DECL, return the prevailing decl with the same name. */
......
2011-06-11 Jan Hubicka <jh@suse.cz>
* lto.c (add_cgraph_node_to_partition_1): Break out from ...
(add_cgraph_node_to_partition) ... here; walk aliases.
(lto_1_to_1_map): Remove same body alias code.
(promote_fn): Likewise.
(lto_promote_cross_file_statics): Update comment.
2011-06-07 Diego Novillo <dnovillo@google.com>
* lto.c (uniquify_nodes): Move code to register decls to
......
......@@ -1319,7 +1319,7 @@ add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
for (i = 0; ipa_ref_list_reference_iterate (refs, i, ref); i++)
{
if (ref->refered_type == IPA_REF_CGRAPH
&& DECL_COMDAT (ipa_ref_node (ref)->decl)
&& DECL_COMDAT (cgraph_function_node (ipa_ref_node (ref), NULL)->decl)
&& !cgraph_node_in_set_p (ipa_ref_node (ref), part->cgraph_set))
add_cgraph_node_to_partition (part, ipa_ref_node (ref));
else
......@@ -1330,6 +1330,34 @@ add_references_to_partition (ltrans_partition part, struct ipa_ref_list *refs)
}
}
/* Worker for add_cgraph_node_to_partition. */
static bool
add_cgraph_node_to_partition_1 (struct cgraph_node *node, void *data)
{
ltrans_partition part = (ltrans_partition) data;
/* non-COMDAT aliases of COMDAT functions needs to be output just once. */
if (!DECL_COMDAT (node->decl)
&& !node->global.inlined_to
&& node->aux)
{
gcc_assert (node->thunk.thunk_p || node->alias);
return false;
}
if (node->aux)
{
node->in_other_partition = 1;
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
cgraph_node_name (node), node->uid);
}
node->aux = (void *)((size_t)node->aux + 1);
cgraph_node_set_add (part->cgraph_set, node);
return false;
}
/* Add NODE to partition as well as the inline callees and referred comdats into partition PART. */
static void
......@@ -1337,42 +1365,34 @@ add_cgraph_node_to_partition (ltrans_partition part, struct cgraph_node *node)
{
struct cgraph_edge *e;
cgraph_node_set_iterator csi;
struct cgraph_node *n;
/* We always decide on functions, not associated thunks and aliases. */
node = cgraph_function_node (node, NULL);
/* If NODE is already there, we have nothing to do. */
csi = cgraph_node_set_find (part->cgraph_set, node);
if (!csi_end_p (csi))
return;
cgraph_for_node_thunks_and_aliases (node, add_cgraph_node_to_partition_1, part, true);
part->insns += inline_summary (node)->self_size;
if (node->aux)
{
node->in_other_partition = 1;
if (cgraph_dump_file)
fprintf (cgraph_dump_file, "Node %s/%i now used in multiple partitions\n",
cgraph_node_name (node), node->uid);
}
node->aux = (void *)((size_t)node->aux + 1);
cgraph_node_set_add (part->cgraph_set, node);
/* Thunks always must go along with function they reffer to. */
if (node->thunk.thunk_p)
add_cgraph_node_to_partition (part, node->callees->callee);
for (e = node->callers; e; e = e->next_caller)
if (e->caller->thunk.thunk_p)
add_cgraph_node_to_partition (part, e->caller);
for (e = node->callees; e; e = e->next_callee)
if ((!e->inline_failed || DECL_COMDAT (e->callee->decl))
if ((!e->inline_failed
|| DECL_COMDAT (cgraph_function_node (e->callee, NULL)->decl))
&& !cgraph_node_in_set_p (e->callee, part->cgraph_set))
add_cgraph_node_to_partition (part, e->callee);
add_references_to_partition (part, &node->ref_list);
if (node->same_comdat_group
&& !cgraph_node_in_set_p (node->same_comdat_group, part->cgraph_set))
add_cgraph_node_to_partition (part, node->same_comdat_group);
if (node->same_comdat_group)
for (n = node->same_comdat_group; n != node; n = n->same_comdat_group)
add_cgraph_node_to_partition (part, n);
}
/* Add VNODE to partition as well as comdat references partition PART. */
......@@ -1500,7 +1520,6 @@ lto_1_to_1_map (void)
continue;
file_data = node->local.lto_file_data;
gcc_assert (!node->same_body_alias);
if (file_data)
{
......@@ -1900,17 +1919,6 @@ promote_fn (struct cgraph_node *node)
TREE_PUBLIC (node->decl) = 1;
DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
DECL_VISIBILITY_SPECIFIED (node->decl) = true;
if (node->same_body)
{
struct cgraph_node *alias;
for (alias = node->same_body;
alias; alias = alias->next)
{
TREE_PUBLIC (alias->decl) = 1;
DECL_VISIBILITY (alias->decl) = VISIBILITY_HIDDEN;
DECL_VISIBILITY_SPECIFIED (alias->decl) = true;
}
}
if (cgraph_dump_file)
fprintf (cgraph_dump_file,
"Promoting function as hidden: %s/%i\n",
......@@ -1944,8 +1952,8 @@ lto_promote_cross_file_statics (void)
set = part->cgraph_set;
vset = part->varpool_set;
/* If node has either address taken (and we have no clue from where)
or it is called from other partition, it needs to be globalized. */
/* If node called or referred to from other partition, it needs to be
globalized. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
struct cgraph_node *node = csi_node (csi);
......
......@@ -6675,6 +6675,16 @@ gate_ipa_pta (void)
struct pt_solution ipa_escaped_pt
= { true, false, false, false, false, false, false, NULL };
/* Associate node with varinfo DATA. Worker for
cgraph_for_node_and_aliases. */
static bool
associate_varinfo_to_alias (struct cgraph_node *node, void *data)
{
if (node->alias || node->thunk.thunk_p)
insert_vi_for_tree (node->decl, (varinfo_t)data);
return false;
}
/* Execute the driver for IPA PTA. */
static unsigned int
ipa_pta_execute (void)
......@@ -6690,22 +6700,17 @@ ipa_pta_execute (void)
/* Build the constraints. */
for (node = cgraph_nodes; node; node = node->next)
{
struct cgraph_node *alias;
varinfo_t vi;
/* Nodes without a body are not interesting. Especially do not
visit clones at this point for now - we get duplicate decls
there for inline clones at least. */
if (!gimple_has_body_p (node->decl)
if (!cgraph_function_with_gimple_body_p (node)
|| node->clone_of)
continue;
vi = create_function_info_for (node->decl,
alias_get_name (node->decl));
/* Associate the varinfo node with all aliases. */
for (alias = node->same_body; alias; alias = alias->next)
insert_vi_for_tree (alias->decl, vi);
cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true);
}
/* Create constraints for global variables and their initializers. */
......@@ -6737,7 +6742,7 @@ ipa_pta_execute (void)
tree old_func_decl;
/* Nodes without a body are not interesting. */
if (!gimple_has_body_p (node->decl)
if (!cgraph_function_with_gimple_body_p (node)
|| node->clone_of)
continue;
......@@ -6846,7 +6851,7 @@ ipa_pta_execute (void)
struct cgraph_edge *e;
/* Nodes without a body are not interesting. */
if (!gimple_has_body_p (node->decl)
if (!cgraph_function_with_gimple_body_p (node)
|| node->clone_of)
continue;
......
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