summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/cgraph.c63
-rw-r--r--gcc/cgraph.h2
-rw-r--r--gcc/ipa-pure-const.c19
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ipa/nothrow-1.C27
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" } } */