aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2005-06-02 21:41:31 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2005-06-02 19:41:31 +0000
commit6b02a4997be30a1cb81a573ea3abc68802f10b2a (patch)
tree581a728808f9ec389dc440901acdffc5a28d346f /gcc
parent04b0eed045fd952d1e8889dd06f07563ce16160b (diff)
downloadgcc-6b02a4997be30a1cb81a573ea3abc68802f10b2a.zip
gcc-6b02a4997be30a1cb81a573ea3abc68802f10b2a.tar.gz
gcc-6b02a4997be30a1cb81a573ea3abc68802f10b2a.tar.bz2
cgraph.c (cgraph_node): Maintain master clones.
* cgraph.c (cgraph_node): Maintain master clones. (cgraph_remove_node): Likewise. (availability_names): New static variable. (dump_cgraph_node): Dump availability. (dump_cgraph_varpool_node): Likewise. (cgraph_is_master_clone, cgraph_master_clone, cgraph_function_body_availability, cgraph_variable_initializer_availability): New functions. * cgraph.h (availability): New enum. (struct cgraph_node): Add master_clone. (cgraph_is_master_clone, cgraph_master_clone, cgraph_function_body_availability, cgraph_variable_initializer_availability): Declare. * cgraphunit.c (cgraph_expand_function): Setcgraph_function_flags_ready. (cgraph_remove_unreachable_nodes): Remove unreachable nodes. * ipa-inline.c (cgraph_decide_inlining): Do not call cgraph_remove_unreachable_nodes. From-SVN: r100507
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/cgraph.c111
-rw-r--r--gcc/cgraph.h33
-rw-r--r--gcc/cgraphunit.c5
-rw-r--r--gcc/ipa-inline.c6
5 files changed, 164 insertions, 9 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1ee5d8e..407911e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,23 @@
2005-06-02 Jan Hubicka <jh@suse.cz>
+ * cgraph.c (cgraph_node): Maintain master clones.
+ (cgraph_remove_node): Likewise.
+ (availability_names): New static variable.
+ (dump_cgraph_node): Dump availability.
+ (dump_cgraph_varpool_node): Likewise.
+ (cgraph_is_master_clone, cgraph_master_clone,
+ cgraph_function_body_availability,
+ cgraph_variable_initializer_availability): New functions.
+ * cgraph.h (availability): New enum.
+ (struct cgraph_node): Add master_clone.
+ (cgraph_is_master_clone, cgraph_master_clone,
+ cgraph_function_body_availability,
+ cgraph_variable_initializer_availability): Declare.
+ * cgraphunit.c (cgraph_expand_function): Setcgraph_function_flags_ready.
+ (cgraph_remove_unreachable_nodes): Remove unreachable nodes.
+ * ipa-inline.c (cgraph_decide_inlining): Do not call
+ cgraph_remove_unreachable_nodes.
+
* cgraphunit.c (cgraph_function_and_variable_visibility): Fix typo in
previous patch.
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 0471191..6af75e1 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -192,7 +192,12 @@ cgraph_node (tree decl)
slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
if (*slot)
- return *slot;
+ {
+ node = *slot;
+ if (!node->master_clone)
+ node->master_clone = node;
+ return node;
+ }
node = cgraph_create_node ();
node->decl = decl;
@@ -202,6 +207,7 @@ cgraph_node (tree decl)
node->origin = cgraph_node (DECL_CONTEXT (decl));
node->next_nested = node->origin->nested;
node->origin->nested = node;
+ node->master_clone = node;
}
return node;
}
@@ -436,7 +442,14 @@ cgraph_remove_node (struct cgraph_node *node)
{
if (node->next_clone)
{
- *slot = node->next_clone;
+ struct cgraph_node *new_node = node->next_clone;
+ struct cgraph_node *n;
+
+ /* Make the next clone be the master clone */
+ for (n = new_node; n; n = n->next_clone)
+ n->master_clone = new_node;
+
+ *slot = new_node;
node->next_clone->prev_clone = NULL;
}
else
@@ -553,6 +566,10 @@ cgraph_varpool_node_name (struct cgraph_varpool_node *node)
return lang_hooks.decl_printable_name (node->decl, 2);
}
+/* Names used to print out the availability enum. */
+static const char * const availability_names[] =
+ {"unset", "not_available", "overwrittable", "available", "local"};
+
/* Dump given cgraph node. */
void
dump_cgraph_node (FILE *f, struct cgraph_node *node)
@@ -563,6 +580,11 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
fprintf (f, " (inline copy in %s/%i)",
cgraph_node_name (node->global.inlined_to),
node->global.inlined_to->uid);
+ if (cgraph_function_flags_ready)
+ fprintf (f, " availability:%s",
+ availability_names [cgraph_function_body_availability (node)]);
+ if (node->master_clone && node->master_clone->uid != node->uid)
+ fprintf (f, "(%i)", node->master_clone->uid);
if (node->count)
fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x",
(HOST_WIDEST_INT)node->count);
@@ -614,6 +636,11 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
edge->callee->uid);
if (!edge->inline_failed)
fprintf(f, "(inlined) ");
+ if (edge->count)
+ fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ",
+ (HOST_WIDEST_INT)edge->count);
+ if (edge->loop_nest)
+ fprintf (f, "(nested in %i loops) ", edge->loop_nest);
}
fprintf (f, "\n");
}
@@ -635,6 +662,7 @@ void
dump_cgraph_varpool_node (FILE *f, struct cgraph_varpool_node *node)
{
fprintf (f, "%s:", cgraph_varpool_node_name (node));
+ fprintf (f, " availability:%s", availability_names [cgraph_variable_initializer_availability (node)]);
if (DECL_INITIAL (node->decl))
fprintf (f, " initialized");
if (node->needed)
@@ -886,6 +914,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int loop_nest)
new->local = n->local;
new->global = n->global;
new->rtl = n->rtl;
+ new->master_clone = n->master_clone;
new->count = count;
if (n->count)
count_scale = new->count * REG_BR_PROB_BASE / n->count;
@@ -905,6 +934,28 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int loop_nest)
return new;
}
+/* Return true if N is an master_clone, (see cgraph_master_clone). */
+
+bool
+cgraph_is_master_clone (struct cgraph_node *n)
+{
+ return (n == cgraph_master_clone (n));
+}
+
+struct cgraph_node *
+cgraph_master_clone (struct cgraph_node *n)
+{
+ enum availability avail = cgraph_function_body_availability (n);
+
+ if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
+ return NULL;
+
+ if (!n->master_clone)
+ n->master_clone = cgraph_node (n->decl);
+
+ return n->master_clone;
+}
+
/* NODE is no longer nested function; update cgraph accordingly. */
void
cgraph_unnest_node (struct cgraph_node *node)
@@ -917,4 +968,60 @@ cgraph_unnest_node (struct cgraph_node *node)
*node2 = node->next_nested;
node->origin = NULL;
}
+
+/* Return function availability. See cgraph.h for description of individual
+ return values. */
+enum availability
+cgraph_function_body_availability (struct cgraph_node *node)
+{
+ enum availability avail;
+ gcc_assert (cgraph_function_flags_ready);
+ if (!node->local.finalized)
+ avail = AVAIL_NOT_AVAILABLE;
+ else if (node->local.local)
+ avail = AVAIL_LOCAL;
+ else if (node->local.externally_visible)
+ avail = AVAIL_AVAILABLE;
+
+ /* If the function can be overwritten, return OVERWRITABLE. Take
+ care at least of two notable extensions - the COMDAT functions
+ used to share template instantiations in C++ (this is symmetric
+ to code cp_cannot_inline_tree_fn and probably shall be shared and
+ the inlinability hooks completelly elliminated).
+
+ ??? Does the C++ one definition rule allow us to always return
+ AVAIL_AVAILABLE here? That would be good reason to preserve this
+ hook Similarly deal with extern inline functions - this is again
+ neccesary to get C++ shared functions having keyed templates
+ right and in the C extension documentation we probably should
+ document the requirement of both versions of function (extern
+ inline and offline) having same side effect characteristics as
+ good optimization is what this optimization is about. */
+
+ else if (!(*targetm.binds_local_p) (node->decl)
+ && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
+ avail = AVAIL_OVERWRITABLE;
+ else avail = AVAIL_AVAILABLE;
+
+ return avail;
+}
+
+/* Return variable availability. See cgraph.h for description of individual
+ return values. */
+enum availability
+cgraph_variable_initializer_availability (struct cgraph_varpool_node *node)
+{
+ gcc_assert (cgraph_function_flags_ready);
+ if (!node->finalized)
+ return AVAIL_NOT_AVAILABLE;
+ if (!TREE_PUBLIC (node->decl))
+ return AVAIL_AVAILABLE;
+ /* If the variable can be overwritted, return OVERWRITABLE. Takes
+ care of at least two notable extensions - the COMDAT variables
+ used to share template instantiations in C++. */
+ if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
+ return AVAIL_OVERWRITABLE;
+ return AVAIL_AVAILABLE;
+}
+
#include "gt-cgraph.h"
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 96e382a..9406e09 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -24,6 +24,28 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree.h"
#include "basic-block.h"
+enum availability
+{
+ /* Not yet set by cgraph_function_body_availability. */
+ AVAIL_UNSET,
+ /* Function body/variable initializer is unknown. */
+ AVAIL_NOT_AVAILABLE,
+ /* Function body/variable initializer is known but might be replaced
+ by a different one from other compilation unit and thus needs to
+ be dealt with a care. Like AVAIL_NOT_AVAILABLE it can have
+ arbitrary side effects on escaping variables and functions, while
+ like AVAILABLE it might access static variables. */
+ AVAIL_OVERWRITABLE,
+ /* Function body/variable initializer is known and will be used in final
+ program. */
+ AVAIL_AVAILABLE,
+ /* Function body/variable initializer is known and all it's uses are explicitly
+ visible within current unit (ie it's address is never taken and it is not
+ exported to other units).
+ Currently used only for functions. */
+ AVAIL_LOCAL
+};
+
/* Information about the function collected locally.
Available after function is analyzed. */
@@ -110,6 +132,10 @@ struct cgraph_node GTY((chain_next ("%h.next"), chain_prev ("%h.previous")))
/* Pointer to the next clone. */
struct cgraph_node *next_clone;
struct cgraph_node *prev_clone;
+ /* Pointer to a single unique cgraph node for this function. If the
+ function is to be output, this is the copy that will survive. */
+ struct cgraph_node *master_clone;
+
PTR GTY ((skip)) aux;
struct cgraph_local_info local;
@@ -178,7 +204,7 @@ struct cgraph_varpool_node GTY(())
bool analyzed;
/* Set once it has been finalized so we consider it to be output. */
bool finalized;
- /* Set when function is scheduled to be assembled. */
+ /* Set when variable is scheduled to be assembled. */
bool output;
/* Set when function is visible by other units. */
bool externally_visible;
@@ -229,6 +255,11 @@ void cgraph_varpool_enqueue_needed_node (struct cgraph_varpool_node *);
void cgraph_varpool_reset_queue (void);
bool decide_is_variable_needed (struct cgraph_varpool_node *, tree);
+enum availability cgraph_function_body_availability (struct cgraph_node *);
+enum availability cgraph_variable_initializer_availability (struct cgraph_varpool_node *);
+bool cgraph_is_master_clone (struct cgraph_node *);
+struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
+
/* In cgraphunit.c */
bool cgraph_assemble_pending_functions (void);
bool cgraph_varpool_assemble_pending_decls (void);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 7f8a96d..ee859f7 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -967,6 +967,8 @@ cgraph_expand_function (struct cgraph_node *node)
points to the dead function body. */
cgraph_node_remove_callees (node);
}
+
+ cgraph_function_flags_ready = true;
}
/* Return true when CALLER_DECL should be inlined into CALLEE_DECL. */
@@ -1128,6 +1130,9 @@ cgraph_optimize (void)
dump_cgraph (cgraph_dump_file);
}
ipa_passes ();
+ /* This pass remove bodies of extern inline functions we never inlined.
+ Do this later so other IPA passes see what is really going on. */
+ cgraph_remove_unreachable_nodes (false, dump_file);
cgraph_global_info_ready = true;
if (cgraph_dump_file)
{
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index e58ac0f..5a336ff 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -857,12 +857,6 @@ cgraph_decide_inlining (void)
}
}
- /* We will never output extern functions we didn't inline.
- ??? Perhaps we can prevent accounting of growth of external
- inline functions. */
-
- cgraph_remove_unreachable_nodes (false, dump_file);
-
if (dump_file)
fprintf (dump_file,
"\nInlined %i calls, eliminated %i functions, "