aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-pure-const.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ipa-pure-const.c')
-rw-r--r--gcc/ipa-pure-const.c122
1 files changed, 64 insertions, 58 deletions
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 7647a58fb26..a9570e4aa6c 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -258,6 +258,13 @@ set_function_state (struct cgraph_node *node, funct_state s)
if (!funct_state_vec.exists ()
|| funct_state_vec.length () <= (unsigned int)node->uid)
funct_state_vec.safe_grow_cleared (node->uid + 1);
+
+ /* If funct_state_vec already contains a funct_state, we have to release
+ it before it's going to be ovewritten. */
+ if (funct_state_vec[node->uid] != NULL
+ && funct_state_vec[node->uid] != &varying_state)
+ free (funct_state_vec[node->uid]);
+
funct_state_vec[node->uid] = s;
}
@@ -616,8 +623,10 @@ check_call (funct_state local, gcall *call, bool ipa)
/* Either callee is unknown or we are doing local analysis.
Look to see if there are any bits available for the callee (such as by
declaration or because it is builtin) and process solely on the basis of
- those bits. */
- else if (!ipa)
+ those bits. Handle internal calls always, those calls don't have
+ corresponding cgraph edges and thus aren't processed during
+ the propagation. */
+ else if (!ipa || gimple_call_internal_p (call))
{
enum pure_const_state_e call_state;
bool call_looping;
@@ -925,8 +934,6 @@ end:
static void
add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
- if (node->get_availability () < AVAIL_INTERPOSABLE)
- return;
/* There are some shared nodes, in particular the initializers on
static declarations. We do not need to scan them more than once
since all we would be interested in are the addressof
@@ -956,12 +963,7 @@ static void
remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
if (has_function_state (node))
- {
- funct_state l = get_function_state (node);
- if (l != &varying_state)
- free (l);
- set_function_state (node, NULL);
- }
+ set_function_state (node, NULL);
}
@@ -1220,6 +1222,7 @@ propagate_pure_const (void)
int i;
struct ipa_dfs_info * w_info;
bool remove_p = false;
+ bool has_cdtor;
order_pos = ipa_reduced_postorder (order, true, false,
ignore_edge_for_pure_const);
@@ -1272,26 +1275,6 @@ propagate_pure_const (void)
if (pure_const_state == IPA_NEITHER)
break;
- /* For interposable nodes we can not assume anything.
- FIXME: It should be safe to remove this conditional and allow
- interposable functions with non-interposable aliases next
- stage 1. */
- if (w->get_availability () == AVAIL_INTERPOSABLE)
- {
- worse_state (&pure_const_state, &looping,
- w_l->state_previously_known,
- w_l->looping_previously_known,
- NULL, NULL);
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file,
- " Interposable. state %s looping %i\n",
- pure_const_names[w_l->state_previously_known],
- w_l->looping_previously_known);
- }
- break;
- }
-
count++;
/* We consider recursive cycles as possibly infinite.
@@ -1504,9 +1487,22 @@ propagate_pure_const (void)
this_looping ? "looping " : "",
w->name ());
}
- remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
- NULL, true);
- w->set_const_flag (true, this_looping);
+ /* Turning constructor or destructor to non-looping const/pure
+ enables us to possibly remove the function completely. */
+ if (this_looping)
+ has_cdtor = false;
+ else
+ has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
+ NULL, true);
+ if (w->set_const_flag (true, this_looping))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Declaration updated to be %sconst: %s\n",
+ this_looping ? "looping " : "",
+ w->name ());
+ remove_p |= has_cdtor;
+ }
break;
case IPA_PURE:
@@ -1518,9 +1514,20 @@ propagate_pure_const (void)
this_looping ? "looping " : "",
w->name ());
}
- remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
- NULL, true);
- w->set_pure_flag (true, this_looping);
+ if (this_looping)
+ has_cdtor = false;
+ else
+ has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
+ NULL, true);
+ if (w->set_pure_flag (true, this_looping))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Declaration updated to be %spure: %s\n",
+ this_looping ? "looping " : "",
+ w->name ());
+ remove_p |= has_cdtor;
+ }
break;
default:
@@ -1721,11 +1728,14 @@ skip_function_for_local_pure_const (struct cgraph_node *node)
fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
return true;
}
- if (node->get_availability () <= AVAIL_INTERPOSABLE)
+ /* Save some work and do not analyze functions which are interposable and
+ do not have any non-interposable aliases. */
+ if (node->get_availability () <= AVAIL_INTERPOSABLE
+ && !node->has_aliases_p ())
{
if (dump_file)
fprintf (dump_file,
- "Function is not available or interposable; not analyzing.\n");
+ "Function is interposable; not analyzing.\n");
return true;
}
return false;
@@ -1804,11 +1814,6 @@ pass_local_pure_const::execute (function *fun)
if (!TREE_READONLY (current_function_decl))
{
warn_function_const (current_function_decl, !l->looping);
- if (!skip)
- {
- node->set_const_flag (true, l->looping);
- changed = true;
- }
if (dump_file)
fprintf (dump_file, "Function found to be %sconst: %s\n",
l->looping ? "looping " : "",
@@ -1817,25 +1822,23 @@ pass_local_pure_const::execute (function *fun)
else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
&& !l->looping)
{
- if (!skip)
- {
- node->set_const_flag (true, false);
- changed = true;
- }
if (dump_file)
fprintf (dump_file, "Function found to be non-looping: %s\n",
current_function_name ());
}
+ if (!skip && node->set_const_flag (true, l->looping))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Declaration updated to be %sconst: %s\n",
+ l->looping ? "looping " : "",
+ current_function_name ());
+ changed = true;
+ }
break;
case IPA_PURE:
if (!DECL_PURE_P (current_function_decl))
{
- if (!skip)
- {
- node->set_pure_flag (true, l->looping);
- changed = true;
- }
warn_function_pure (current_function_decl, !l->looping);
if (dump_file)
fprintf (dump_file, "Function found to be %spure: %s\n",
@@ -1845,15 +1848,18 @@ pass_local_pure_const::execute (function *fun)
else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
&& !l->looping)
{
- if (!skip)
- {
- node->set_pure_flag (true, false);
- changed = true;
- }
if (dump_file)
fprintf (dump_file, "Function found to be non-looping: %s\n",
current_function_name ());
}
+ if (!skip && node->set_pure_flag (true, l->looping))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Declaration updated to be %spure: %s\n",
+ l->looping ? "looping " : "",
+ current_function_name ());
+ changed = true;
+ }
break;
default: