Commit a2b056a3 by Jan Hubicka Committed by Jan Hubicka

re PR c++/70018 (Possible issue around IPO and C++ comdats discovered as pure/const)


	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.

	* g++.dg/ipa/nothrow-1.C: New testcase.

From-SVN: r235318
parent 9b7924dd
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
......
......@@ -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;
......
......@@ -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.
......
......@@ -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;
......
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
......
/* { 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" } } */
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