diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/cgraph.c | 63 | ||||
-rw-r--r-- | gcc/cgraph.h | 2 | ||||
-rw-r--r-- | gcc/ipa-pure-const.c | 19 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ipa/nothrow-1.C | 27 |
6 files changed, 110 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d24599f7dcc..d58b38f0449 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2016-04-20 Jan Hubicka <jh@suse.cz> + + PR ipa/70018 + * cgraph.c (cgraph_set_nothrow_flag_1): Rename to ... + (set_nothrow_flag_1): ... this; handle interposition correctly; + recurse on aliases and thunks. + (cgraph_node::set_nothrow_flag): New. + * ipa-pure-const.c (ignore_edge_for_nothrow): Ignore calls to + functions compiled with non-call exceptions that binds to current + def. + (propagate_nothrow): Be safe WRT interposition. + * cgraph.h (set_nothrow_flag): Update prototype. + 2016-04-18 Jan Hubicka <jh@suse.cz> * tree-ssa-loop-unswitch.c (tree_unswitch_single_loop): Use also diff --git a/gcc/cgraph.c b/gcc/cgraph.c index d8cb5269510..d93a93988f1 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2358,27 +2358,65 @@ cgraph_node::make_local (void) /* Worker to set nothrow flag. */ -static bool -cgraph_set_nothrow_flag_1 (cgraph_node *node, void *data) +static void +set_nothrow_flag_1 (cgraph_node *node, bool nothrow, bool non_call, + bool *changed) { cgraph_edge *e; - TREE_NOTHROW (node->decl) = data != NULL; - - if (data != NULL) - for (e = node->callers; e; e = e->next_caller) - e->can_throw_external = false; - return false; + if (nothrow && !TREE_NOTHROW (node->decl)) + { + /* With non-call exceptions we can't say for sure if other function body + was not possibly optimized to stil throw. */ + if (!non_call || node->binds_to_current_def_p ()) + { + TREE_NOTHROW (node->decl) = true; + *changed = true; + for (e = node->callers; e; e = e->next_caller) + e->can_throw_external = false; + } + } + else if (!nothrow && TREE_NOTHROW (node->decl)) + { + TREE_NOTHROW (node->decl) = false; + *changed = true; + } + ipa_ref *ref; + FOR_EACH_ALIAS (node, ref) + { + cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring); + if (!nothrow || alias->get_availability () > AVAIL_INTERPOSABLE) + set_nothrow_flag_1 (alias, nothrow, non_call, changed); + } + for (cgraph_edge *e = node->callers; e; e = e->next_caller) + if (e->caller->thunk.thunk_p + && (!nothrow || e->caller->get_availability () > AVAIL_INTERPOSABLE)) + set_nothrow_flag_1 (e->caller, nothrow, non_call, changed); } /* Set TREE_NOTHROW on NODE's decl and on aliases of NODE if any to NOTHROW. */ -void +bool cgraph_node::set_nothrow_flag (bool nothrow) { - call_for_symbol_thunks_and_aliases (cgraph_set_nothrow_flag_1, - (void *)(size_t)nothrow, nothrow == true); + bool changed = false; + bool non_call = opt_for_fn (decl, flag_non_call_exceptions); + + if (!nothrow || get_availability () > AVAIL_INTERPOSABLE) + set_nothrow_flag_1 (this, nothrow, non_call, &changed); + else + { + ipa_ref *ref; + + FOR_EACH_ALIAS (this, ref) + { + cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring); + if (!nothrow || alias->get_availability () > AVAIL_INTERPOSABLE) + set_nothrow_flag_1 (alias, nothrow, non_call, &changed); + } + } + return changed; } /* Worker to set_const_flag. */ @@ -2517,8 +2555,7 @@ cgraph_node::set_const_flag (bool set_const, bool looping) /* Info used by set_pure_flag_1. */ -struct -set_pure_flag_info +struct set_pure_flag_info { bool pure; bool looping; diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 71e31a4f1e3..5ce032e1e57 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1111,7 +1111,7 @@ public: /* Set TREE_NOTHROW on cgraph_node's decl and on aliases of the node if any to NOTHROW. */ - void set_nothrow_flag (bool nothrow); + bool set_nothrow_flag (bool nothrow); /* If SET_CONST is true, mark function, aliases and thunks to be ECF_CONST. If SET_CONST if false, clear the flag. diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index da8fd4d409b..7647a58fb26 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -1163,7 +1163,10 @@ ignore_edge_for_nothrow (struct cgraph_edge *e) enum availability avail; cgraph_node *n = e->callee->function_or_virtual_thunk_symbol (&avail, e->caller); - return (avail <= AVAIL_INTERPOSABLE || TREE_NOTHROW (n->decl)); + if (avail <= AVAIL_INTERPOSABLE || TREE_NOTHROW (n->decl)) + return true; + return opt_for_fn (e->callee->decl, flag_non_call_exceptions) + && !e->callee->binds_to_current_def_p (e->caller); } /* Return true if NODE is self recursive function. @@ -1589,14 +1592,20 @@ propagate_nothrow (void) continue; struct cgraph_node *y = e->callee-> - function_or_virtual_thunk_symbol (&avail, - e->caller); + function_or_virtual_thunk_symbol (&avail, + e->caller); /* We can use info about the callee only if we know it can - not be interposed. */ + not be interposed. + When callee is compiled with non-call exceptions we also + must check that the declaration is bound to current + body as other semantically equivalent body may still + throw. */ if (avail <= AVAIL_INTERPOSABLE || (!TREE_NOTHROW (y->decl) - && get_function_state (y)->can_throw)) + && (get_function_state (y)->can_throw + || (opt_for_fn (y->decl, flag_non_call_exceptions) + && !e->callee->binds_to_current_def_p (w))))) can_throw = true; } for (ie = w->indirect_calls; ie && !can_throw; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c767cd59ae7..eb47876726e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-04-20 Jan Hubicka <jh@suse.cz> + + PR ipa/70018 + * g++.dg/ipa/nothrow-1.C: New testcase. + 2016-04-20 Nathan Sidwell <nathan@acm.org> PR c++/55635 diff --git a/gcc/testsuite/g++.dg/ipa/nothrow-1.C b/gcc/testsuite/g++.dg/ipa/nothrow-1.C new file mode 100644 index 00000000000..df2fbae2acc --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/nothrow-1.C @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fnon-call-exceptions -fdump-tree-optimized" } */ +int *ptr; +static int barvar; + +/* We can not detect A to be const because it may be interposed by unoptimized + body. */ +inline +__attribute__ ((noinline)) +int a(void) +{ + return *ptr == *ptr; +} +main() +{ + int aa; + ptr = &barvar; + try { + aa=!a(); + } catch (...) + { + return 1; + } + ptr = 0; + return aa; +} +/* { dg-final { scan-tree-dump "__cxa_begin_catch" "optimized" } } */ |