Commit 2505c5ed by Jan Hubicka Committed by Jan Hubicka

cgraph.c (cgraph_make_edge, [...]): Set nothrow flag.

	* cgraph.c (cgraph_make_edge, dump_cgraph_node, cgraph_set_call_stmt):
	Set nothrow flag.
	* cgraph.h (struct function): Reduce loop_nest to 30 bits; add
	can_throw_external flag.
	* ipa-reference.c (ipa_utils_reduced_inorder): Update call.
	* ipa-pure-const.c (ignore_edge): New function.
	(propagate): Compute order for NOTHROW computation; set NOTHROWs
	only over can_throw_external edges.
	(local_pure_const): Add nothrow flag.
	* ipa-utils.c (searchc): Add ignore_edge callback.
	(ipa_utils_reduced_inorder): Add ignore_edge callback.
	* ipa-utils.h (ipa_utils_reduced_inorder): Update prototype.
	(set_nothrow_function_flags): Update cgraph.
	* tree-cfg.c (verify_stmt): Relax nothrow checking when in IPA mode.

From-SVN: r146322
parent c7f9c0b9
2009-04-18 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_make_edge, dump_cgraph_node, cgraph_set_call_stmt):
Set nothrow flag.
* cgraph.h (struct function): Reduce loop_nest to 30 bits; add
can_throw_external flag.
* ipa-reference.c (ipa_utils_reduced_inorder): Update call.
* ipa-pure-const.c (ignore_edge): New function.
(propagate): Compute order for NOTHROW computation; set NOTHROWs
only over can_throw_external edges.
(local_pure_const): Add nothrow flag.
* ipa-utils.c (searchc): Add ignore_edge callback.
(ipa_utils_reduced_inorder): Add ignore_edge callback.
* ipa-utils.h (ipa_utils_reduced_inorder): Update prototype.
(set_nothrow_function_flags): Update cgraph.
* tree-cfg.c (verify_stmt): Relax nothrow checking when in IPA mode.
2009-04-18 Richard Guenther <rguenther@suse.de> 2009-04-18 Richard Guenther <rguenther@suse.de>
PR middle-end/39804 PR middle-end/39804
......
...@@ -640,6 +640,7 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt) ...@@ -640,6 +640,7 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt)
htab_hash_pointer (e->call_stmt)); htab_hash_pointer (e->call_stmt));
} }
e->call_stmt = new_stmt; e->call_stmt = new_stmt;
e->can_throw_external = stmt_can_throw_external (new_stmt);
if (e->caller->call_site_hash) if (e->caller->call_site_hash)
{ {
void **slot; void **slot;
...@@ -704,6 +705,7 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, ...@@ -704,6 +705,7 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
edge->caller = caller; edge->caller = caller;
edge->callee = callee; edge->callee = callee;
edge->call_stmt = call_stmt; edge->call_stmt = call_stmt;
edge->can_throw_external = stmt_can_throw_external (call_stmt);
edge->prev_caller = NULL; edge->prev_caller = NULL;
edge->next_caller = callee->callers; edge->next_caller = callee->callers;
if (callee->callers) if (callee->callers)
...@@ -1215,6 +1217,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) ...@@ -1215,6 +1217,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
fprintf(f, "(inlined) "); fprintf(f, "(inlined) ");
if (edge->indirect_call) if (edge->indirect_call)
fprintf(f, "(indirect) "); fprintf(f, "(indirect) ");
if (edge->can_throw_external)
fprintf(f, "(can throw external) ");
} }
fprintf (f, "\n calls: "); fprintf (f, "\n calls: ");
......
...@@ -216,9 +216,11 @@ struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_call ...@@ -216,9 +216,11 @@ struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_call
per function call. The range is 0 to CGRAPH_FREQ_MAX. */ per function call. The range is 0 to CGRAPH_FREQ_MAX. */
int frequency; int frequency;
/* Depth of loop nest, 1 means no loop nest. */ /* Depth of loop nest, 1 means no loop nest. */
unsigned int loop_nest : 31; unsigned int loop_nest : 30;
/* Whether this edge describes a call that was originally indirect. */ /* Whether this edge describes a call that was originally indirect. */
unsigned int indirect_call : 1; unsigned int indirect_call : 1;
/* Can this call throw externally? */
unsigned int can_throw_external : 1;
/* Unique id of the edge. */ /* Unique id of the edge. */
int uid; int uid;
}; };
......
...@@ -2846,6 +2846,10 @@ set_nothrow_function_flags (void) ...@@ -2846,6 +2846,10 @@ set_nothrow_function_flags (void)
(current_function_decl)) (current_function_decl))
>= AVAIL_AVAILABLE)) >= AVAIL_AVAILABLE))
{ {
struct cgraph_node *node = cgraph_node (current_function_decl);
struct cgraph_edge *e;
for (e = node->callers; e; e = e->next_caller)
e->can_throw_external = false;
TREE_NOTHROW (current_function_decl) = 1; TREE_NOTHROW (current_function_decl) = 1;
if (dump_file) if (dump_file)
......
...@@ -637,6 +637,12 @@ generate_summary (void) ...@@ -637,6 +637,12 @@ generate_summary (void)
visited_nodes = NULL; visited_nodes = NULL;
} }
static bool
ignore_edge (struct cgraph_edge *e)
{
return (!e->can_throw_external);
}
/* Produce the global information by preforming a transitive closure /* Produce the global information by preforming a transitive closure
on the local information that was produced by generate_summary. on the local information that was produced by generate_summary.
Note that there is no function_transform pass since this only Note that there is no function_transform pass since this only
...@@ -656,7 +662,7 @@ propagate (void) ...@@ -656,7 +662,7 @@ propagate (void)
cgraph_remove_function_insertion_hook (function_insertion_hook_holder); cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
cgraph_remove_node_duplication_hook (node_duplication_hook_holder); cgraph_remove_node_duplication_hook (node_duplication_hook_holder);
cgraph_remove_node_removal_hook (node_removal_hook_holder); cgraph_remove_node_removal_hook (node_removal_hook_holder);
order_pos = ipa_utils_reduced_inorder (order, true, false); order_pos = ipa_utils_reduced_inorder (order, true, false, NULL);
if (dump_file) if (dump_file)
{ {
dump_cgraph (dump_file); dump_cgraph (dump_file);
...@@ -671,7 +677,6 @@ propagate (void) ...@@ -671,7 +677,6 @@ propagate (void)
{ {
enum pure_const_state_e pure_const_state = IPA_CONST; enum pure_const_state_e pure_const_state = IPA_CONST;
bool looping = false; bool looping = false;
bool can_throw = false;
int count = 0; int count = 0;
node = order[i]; node = order[i];
...@@ -684,13 +689,10 @@ propagate (void) ...@@ -684,13 +689,10 @@ propagate (void)
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;
if (w_l->can_throw)
can_throw = true;
if (w_l->looping) if (w_l->looping)
looping = true; looping = true;
if (pure_const_state == IPA_NEITHER if (pure_const_state == IPA_NEITHER)
&& can_throw)
break; break;
count++; count++;
...@@ -707,16 +709,10 @@ propagate (void) ...@@ -707,16 +709,10 @@ propagate (void)
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 (pure_const_state < y_l->pure_const_state)
pure_const_state = y_l->pure_const_state; pure_const_state = y_l->pure_const_state;
if (pure_const_state == IPA_NEITHER if (pure_const_state == IPA_NEITHER)
&& can_throw)
break; break;
if (y_l->looping) if (y_l->looping)
looping = true; looping = true;
if (y_l->can_throw && !TREE_NOTHROW (w->decl)
/* FIXME: We should check that the throw can get external.
We also should handle only loops formed by can throw external
edges. */)
can_throw = true;
} }
} }
w_info = (struct ipa_dfs_info *) w->aux; w_info = (struct ipa_dfs_info *) w->aux;
...@@ -766,12 +762,80 @@ propagate (void) ...@@ -766,12 +762,80 @@ propagate (void)
default: default:
break; break;
} }
w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
}
/* Cleanup. */
for (node = cgraph_nodes; node; node = node->next)
{
/* Get rid of the aux information. */
if (node->aux)
{
w_info = (struct ipa_dfs_info *) node->aux;
free (node->aux);
node->aux = NULL;
}
}
order_pos = ipa_utils_reduced_inorder (order, true, false, ignore_edge);
if (dump_file)
{
dump_cgraph (dump_file);
ipa_utils_print_order(dump_file, "reduced for nothrow", order, order_pos);
}
/* Propagate the local information thru the call graph to produce
the global information. All the nodes within a cycle will have
the same info so we collapse cycles first. Then we can do the
propagation in one pass from the leaves to the roots. */
for (i = 0; i < order_pos; i++ )
{
bool can_throw = false;
node = order[i];
/* Find the worst state for any node in the cycle. */
w = node;
while (w)
{
struct cgraph_edge *e;
funct_state w_l = get_function_state (w);
if (w_l->can_throw)
can_throw = true;
if (can_throw)
break;
for (e = w->callees; e; e = e->next_callee)
{
struct cgraph_node *y = e->callee;
if (cgraph_function_body_availability (y) > AVAIL_OVERWRITABLE)
{
funct_state y_l = get_function_state (y);
if (can_throw)
break;
if (y_l->can_throw && !TREE_NOTHROW (w->decl)
&& e->can_throw_external)
can_throw = true;
}
}
w_info = (struct ipa_dfs_info *) w->aux;
w = w_info->next_cycle;
}
/* Copy back the region's pure_const_state which is shared by
all nodes in the region. */
w = node;
while (w)
{
if (!can_throw && !TREE_NOTHROW (w->decl)) if (!can_throw && !TREE_NOTHROW (w->decl))
{ {
/* FIXME: TREE_NOTHROW is not set because passmanager will execute struct cgraph_edge *e;
verify_ssa and verify_cfg on every function. Before fixup_cfg is done, TREE_NOTHROW (w->decl) = true;
those functions are going to have NOTHROW calls in EH regions reulting for (e = w->callers; e; e = e->next_caller)
in ICE. */ e->can_throw_external = false;
if (dump_file) if (dump_file)
fprintf (dump_file, "Function found to be nothrow: %s\n", fprintf (dump_file, "Function found to be nothrow: %s\n",
cgraph_node_name (w)); cgraph_node_name (w));
...@@ -918,7 +982,12 @@ local_pure_const (void) ...@@ -918,7 +982,12 @@ local_pure_const (void)
} }
if (!l->can_throw && !TREE_NOTHROW (current_function_decl)) if (!l->can_throw && !TREE_NOTHROW (current_function_decl))
{ {
TREE_NOTHROW (current_function_decl) = 1; struct cgraph_edge *e;
TREE_NOTHROW (current_function_decl) = true;
for (e = cgraph_node (current_function_decl)->callers;
e; e = e->next_caller)
e->can_throw_external = false;
changed = true; changed = true;
if (dump_file) if (dump_file)
fprintf (dump_file, "Function found to be nothrow: %s\n", fprintf (dump_file, "Function found to be nothrow: %s\n",
......
...@@ -995,7 +995,7 @@ propagate (void) ...@@ -995,7 +995,7 @@ propagate (void)
struct cgraph_node *w; struct cgraph_node *w;
struct cgraph_node **order = struct cgraph_node **order =
XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
int order_pos = ipa_utils_reduced_inorder (order, false, true); int order_pos = ipa_utils_reduced_inorder (order, false, true, NULL);
int i; int i;
cgraph_remove_function_insertion_hook (function_insertion_hook_holder); cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
...@@ -1006,7 +1006,7 @@ propagate (void) ...@@ -1006,7 +1006,7 @@ propagate (void)
the global information. All the nodes within a cycle will have the global information. All the nodes within a cycle will have
the same info so we collapse cycles first. Then we can do the the same info so we collapse cycles first. Then we can do the
propagation in one pass from the leaves to the roots. */ propagation in one pass from the leaves to the roots. */
order_pos = ipa_utils_reduced_inorder (order, true, true); order_pos = ipa_utils_reduced_inorder (order, true, true, NULL);
if (dump_file) if (dump_file)
ipa_utils_print_order(dump_file, "reduced", order, order_pos); ipa_utils_print_order(dump_file, "reduced", order, order_pos);
......
...@@ -81,7 +81,8 @@ struct searchc_env { ...@@ -81,7 +81,8 @@ struct searchc_env {
searching from. */ searching from. */
static void static void
searchc (struct searchc_env* env, struct cgraph_node *v) searchc (struct searchc_env* env, struct cgraph_node *v,
bool (*ignore_edge) (struct cgraph_edge *))
{ {
struct cgraph_edge *edge; struct cgraph_edge *edge;
struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->aux; struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->aux;
...@@ -101,12 +102,15 @@ searchc (struct searchc_env* env, struct cgraph_node *v) ...@@ -101,12 +102,15 @@ searchc (struct searchc_env* env, struct cgraph_node *v)
struct ipa_dfs_info * w_info; struct ipa_dfs_info * w_info;
struct cgraph_node *w = edge->callee; struct cgraph_node *w = edge->callee;
if (ignore_edge && ignore_edge (edge))
continue;
if (w->aux && cgraph_function_body_availability (edge->callee) > AVAIL_OVERWRITABLE) if (w->aux && cgraph_function_body_availability (edge->callee) > AVAIL_OVERWRITABLE)
{ {
w_info = (struct ipa_dfs_info *) w->aux; w_info = (struct ipa_dfs_info *) w->aux;
if (w_info->new_node) if (w_info->new_node)
{ {
searchc (env, w); searchc (env, w, ignore_edge);
v_info->low_link = v_info->low_link =
(v_info->low_link < w_info->low_link) ? (v_info->low_link < w_info->low_link) ?
v_info->low_link : w_info->low_link; v_info->low_link : w_info->low_link;
...@@ -152,7 +156,8 @@ searchc (struct searchc_env* env, struct cgraph_node *v) ...@@ -152,7 +156,8 @@ searchc (struct searchc_env* env, struct cgraph_node *v)
int int
ipa_utils_reduced_inorder (struct cgraph_node **order, ipa_utils_reduced_inorder (struct cgraph_node **order,
bool reduce, bool allow_overwritable) bool reduce, bool allow_overwritable,
bool (*ignore_edge) (struct cgraph_edge *))
{ {
struct cgraph_node *node; struct cgraph_node *node;
struct searchc_env env; struct searchc_env env;
...@@ -193,7 +198,7 @@ ipa_utils_reduced_inorder (struct cgraph_node **order, ...@@ -193,7 +198,7 @@ ipa_utils_reduced_inorder (struct cgraph_node **order,
while (result) while (result)
{ {
node = (struct cgraph_node *)result->value; node = (struct cgraph_node *)result->value;
searchc (&env, node); searchc (&env, node, ignore_edge);
result = splay_tree_min (env.nodes_marked_new); result = splay_tree_min (env.nodes_marked_new);
} }
splay_tree_delete (env.nodes_marked_new); splay_tree_delete (env.nodes_marked_new);
......
...@@ -39,7 +39,8 @@ struct ipa_dfs_info { ...@@ -39,7 +39,8 @@ struct ipa_dfs_info {
/* In ipa-utils.c */ /* In ipa-utils.c */
void ipa_utils_print_order (FILE*, const char *, struct cgraph_node**, int); void ipa_utils_print_order (FILE*, const char *, struct cgraph_node**, int);
int ipa_utils_reduced_inorder (struct cgraph_node **, bool, bool); int ipa_utils_reduced_inorder (struct cgraph_node **, bool, bool,
bool (*ignore_edge) (struct cgraph_edge *));
tree get_base_var (tree); tree get_base_var (tree);
......
...@@ -4156,7 +4156,10 @@ verify_stmt (gimple_stmt_iterator *gsi) ...@@ -4156,7 +4156,10 @@ verify_stmt (gimple_stmt_iterator *gsi)
to match. */ to match. */
if (lookup_stmt_eh_region (stmt) >= 0) if (lookup_stmt_eh_region (stmt) >= 0)
{ {
if (!stmt_could_throw_p (stmt)) /* During IPA passes, ipa-pure-const sets nothrow flags on calls
and they are updated on statements only after fixup_cfg
is executed at beggining of expansion stage. */
if (!stmt_could_throw_p (stmt) && cgraph_state != CGRAPH_STATE_IPA_SSA)
{ {
error ("statement marked for throw, but doesn%'t"); error ("statement marked for throw, but doesn%'t");
goto fail; goto fail;
......
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