Commit d56026c2 by Jan Hubicka Committed by Jan Hubicka

cgraph.h (cgraph_node_cannot_return, [...]): New functions.

	* cgraph.h (cgraph_node_cannot_return,
	cgraph_edge_cannot_lead_to_return): New functions.
	* cgraph.c (cgraph_node_cannot_return,
	cgraph_edge_cannot_lead_to_return): Use them.
	* ipa-pure-const.c (pure_const_names): New static var.
	(check_call): Handle calls not leading to return.
	(pure_const_read_summary): Dump info read.
	(propagate): Dump info about propagation process; ignore side
	effects of functions not leading to exit; fix handling of
	pure functions.

From-SVN: r160051
parent 17f01631
2010-05-30 Jan Hubicka <jh@suse.cz> 2010-05-30 Jan Hubicka <jh@suse.cz>
* cgraph.h (cgraph_node_cannot_return,
cgraph_edge_cannot_lead_to_return): New functions.
* cgraph.c (cgraph_node_cannot_return,
cgraph_edge_cannot_lead_to_return): Use them.
* ipa-pure-const.c (pure_const_names): New static var.
(check_call): Handle calls not leading to return.
(pure_const_read_summary): Dump info read.
(propagate): Dump info about propagation process; ignore side
effects of functions not leading to exit; fix handling of
pure functions.
2010-05-30 Jan Hubicka <jh@suse.cz>
* config/i386/i386.c (pro_epilogue_adjust_stack): Use EBP * config/i386/i386.c (pro_epilogue_adjust_stack): Use EBP
for tail call epilogues. for tail call epilogues.
......
...@@ -2584,4 +2584,39 @@ cgraph_propagate_frequency (struct cgraph_node *node) ...@@ -2584,4 +2584,39 @@ cgraph_propagate_frequency (struct cgraph_node *node)
return false; return false;
} }
/* Return true when NODE can not return or throw and thus
it is safe to ignore its side effects for IPA analysis. */
bool
cgraph_node_cannot_return (struct cgraph_node *node)
{
int flags = flags_from_decl_or_type (node->decl);
if (!flag_exceptions)
return (flags & ECF_NORETURN) != 0;
else
return ((flags & (ECF_NORETURN | ECF_NOTHROW))
== (ECF_NORETURN | ECF_NOTHROW));
}
/* Return true when call of E can not lead to return from caller
and thus it is safe to ignore its side effects for IPA analysis
when computing side effects of the caller.
FIXME: We could actually mark all edges that have no reaching
patch to EXIT_BLOCK_PTR or throw to get better results. */
bool
cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e)
{
if (e->indirect_unknown_callee)
{
int flags = e->indirect_info->ecf_flags;
if (!flag_exceptions)
return (flags & ECF_NORETURN) != 0;
else
return ((flags & (ECF_NORETURN | ECF_NOTHROW))
== (ECF_NORETURN | ECF_NOTHROW));
}
else
return cgraph_node_cannot_return (e->callee);
}
#include "gt-cgraph.h" #include "gt-cgraph.h"
...@@ -594,6 +594,8 @@ void cgraph_set_readonly_flag (struct cgraph_node *, bool); ...@@ -594,6 +594,8 @@ void cgraph_set_readonly_flag (struct cgraph_node *, bool);
void cgraph_set_pure_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_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_edge_cannot_lead_to_return (struct cgraph_edge *);
/* In cgraphunit.c */ /* In cgraphunit.c */
void cgraph_finalize_function (tree, bool); void cgraph_finalize_function (tree, bool);
......
...@@ -72,6 +72,8 @@ enum pure_const_state_e ...@@ -72,6 +72,8 @@ enum pure_const_state_e
IPA_NEITHER IPA_NEITHER
}; };
const char *pure_const_names[3] = {"const", "pure", "neither"};
/* Holder for the const_state. There is one of these per function /* Holder for the const_state. There is one of these per function
decl. */ decl. */
struct funct_state_d struct funct_state_d
...@@ -445,6 +447,16 @@ check_call (funct_state local, gimple call, bool ipa) ...@@ -445,6 +447,16 @@ check_call (funct_state local, gimple call, bool ipa)
if (local->pure_const_state == IPA_CONST) if (local->pure_const_state == IPA_CONST)
local->pure_const_state = IPA_PURE; local->pure_const_state = IPA_PURE;
} }
else if ((flags & (ECF_NORETURN | ECF_NOTHROW))
== (ECF_NORETURN | ECF_NOTHROW)
|| (!flag_exceptions && (flags & ECF_NORETURN)))
{
if (dump_file)
fprintf (dump_file, " noreturn nothrow call is looping pure\n");
if (local->pure_const_state == IPA_CONST)
local->pure_const_state = IPA_PURE;
local->looping = true;
}
else else
{ {
if (dump_file) if (dump_file)
...@@ -872,6 +884,29 @@ pure_const_read_summary (void) ...@@ -872,6 +884,29 @@ pure_const_read_summary (void)
fs->looping_previously_known = bp_unpack_value (bp, 1); fs->looping_previously_known = bp_unpack_value (bp, 1);
fs->looping = bp_unpack_value (bp, 1); fs->looping = bp_unpack_value (bp, 1);
fs->can_throw = bp_unpack_value (bp, 1); fs->can_throw = bp_unpack_value (bp, 1);
if (dump_file)
{
int flags = flags_from_decl_or_type (node->decl);
fprintf (dump_file, "Read info for %s/%i ",
cgraph_node_name (node),
node->uid);
if (flags & ECF_CONST)
fprintf (dump_file, " const");
if (flags & ECF_PURE)
fprintf (dump_file, " pure");
if (flags & ECF_NOTHROW)
fprintf (dump_file, " nothrow");
fprintf (dump_file, "\n pure const state: %s\n",
pure_const_names[fs->pure_const_state]);
fprintf (dump_file, " previously known state: %s\n",
pure_const_names[fs->looping_previously_known]);
if (fs->looping)
fprintf (dump_file," function is locally looping\n");
if (fs->looping_previously_known)
fprintf (dump_file," function is previously known looping\n");
if (fs->can_throw)
fprintf (dump_file," function is locally throwing\n");
}
bitpack_delete (bp); bitpack_delete (bp);
} }
...@@ -938,12 +973,21 @@ propagate (void) ...@@ -938,12 +973,21 @@ propagate (void)
int count = 0; int count = 0;
node = order[i]; node = order[i];
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Starting cycle\n");
/* Find the worst state for any node in the cycle. */ /* Find the worst state for any node in the cycle. */
w = node; w = node;
while (w) while (w)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
funct_state w_l = get_function_state (w); funct_state w_l = get_function_state (w);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Visiting %s/%i state:%s looping %i\n",
cgraph_node_name (w),
w->uid,
pure_const_names[w_l->pure_const_state],
w_l->looping);
if (pure_const_state < w_l->pure_const_state) if (pure_const_state < w_l->pure_const_state)
pure_const_state = w_l->pure_const_state; pure_const_state = w_l->pure_const_state;
...@@ -954,6 +998,13 @@ propagate (void) ...@@ -954,6 +998,13 @@ propagate (void)
looping |= w_l->looping_previously_known; looping |= w_l->looping_previously_known;
if (pure_const_state < w_l->state_previously_known) if (pure_const_state < w_l->state_previously_known)
pure_const_state = w_l->state_previously_known; pure_const_state = w_l->state_previously_known;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
" Overwritable. state %s looping %i\n",
pure_const_names[w_l->state_previously_known],
w_l->looping_previously_known);
}
} }
if (pure_const_state == IPA_NEITHER) if (pure_const_state == IPA_NEITHER)
...@@ -967,35 +1018,92 @@ propagate (void) ...@@ -967,35 +1018,92 @@ propagate (void)
for (e = w->callees; e; e = e->next_callee) for (e = w->callees; e; e = e->next_callee)
{ {
struct cgraph_node *y = e->callee; struct cgraph_node *y = e->callee;
enum pure_const_state_e edge_state = IPA_CONST;
bool edge_looping = false;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
" Call to %s/%i",
cgraph_node_name (e->callee),
e->callee->uid);
}
if (cgraph_function_body_availability (y) > AVAIL_OVERWRITABLE) if (cgraph_function_body_availability (y) > AVAIL_OVERWRITABLE)
{ {
funct_state y_l = get_function_state (y); funct_state y_l = get_function_state (y);
if (pure_const_state < y_l->pure_const_state) if (dump_file && (dump_flags & TDF_DETAILS))
pure_const_state = y_l->pure_const_state; {
if (pure_const_state == IPA_NEITHER) fprintf (dump_file,
break; " state:%s looping:%i\n",
if (y_l->looping) pure_const_names[y_l->pure_const_state],
looping = true; y_l->looping);
}
else if (y_l->pure_const_state > ECF_PURE
&& cgraph_edge_cannot_lead_to_return (e))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
" Ignoring side effects -> pure, looping\n");
}
edge_state = IPA_PURE;
edge_looping = true;
}
else
{
edge_state = y_l->pure_const_state;
edge_looping = y_l->looping;
}
} }
else else
{ {
int flags = flags_from_decl_or_type (y->decl); int flags = flags_from_decl_or_type (y->decl);
if (flags & ECF_LOOPING_CONST_OR_PURE) if (flags & ECF_LOOPING_CONST_OR_PURE)
looping = true; {
edge_looping = true;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " unavailable looping");
}
if (flags & ECF_CONST) if (flags & ECF_CONST)
; {
else if ((flags & ECF_PURE) && pure_const_state == IPA_CONST) if (dump_file && (dump_flags & TDF_DETAILS))
pure_const_state = IPA_PURE; fprintf (dump_file, " const\n");
}
else if (flags & ECF_PURE)
{
edge_state = IPA_PURE;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " pure\n");
}
else if (cgraph_edge_cannot_lead_to_return (e))
{
edge_state = IPA_PURE;
edge_looping = true;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " ignoring side effects->pure looping\n");
}
else else
pure_const_state = IPA_NEITHER, looping = true; {
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " neihter\n");
edge_state = IPA_NEITHER;
edge_looping = true;
}
} }
pure_const_state = MAX (pure_const_state, MIN (edge_state,
w_l->state_previously_known));
looping = MAX (looping, MIN (edge_looping, edge_state));
if (pure_const_state == IPA_NEITHER)
break;
} }
w_info = (struct ipa_dfs_info *) w->aux; w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle; w = w_info->next_cycle;
} }
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Result %s looping %i\n",
pure_const_names [pure_const_state],
looping);
/* Copy back the region's pure_const_state which is shared by /* Copy back the region's pure_const_state which is shared by
all nodes in the region. */ all nodes in the region. */
......
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