Commit 69a4e898 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.h (cgraph_node::set_const_flag,
	cgraph_node::set_pure_flag): Update prototype to return bool;
	update comment.
	* cgraph.c (cgraph_node::call_for_symbol_thunks_and_aliases): Thunks
	of interposable symbol are interposable, too.
	(cgraph_set_const_flag_1): Rename to ...
	(set_const_flag_1): ... this one; change to self recursive function
	instead of call_for_symbol_thunks_and_aliases. Handle correctly
	clearnig the flag in all variants and also virtual thunks of const
	functions are pure; track if any change was done.
	(cgraph_node::set_const_flag): Update.
	(struct set_pure_flag_info): New struct.
	(cgraph_set_pure_flag_1): Rename to ...
	(set_pure_flag_1): ... this one; take set_pure_flag_info parameter
	rather than pointer encoded flags; track if any changes was done;
	handle correctly clearning flag and setting flag of aliases already
	declared const.
	(cgraph_node::set_pure_flag): Update.
	(cgraph_node::set_nothrow_flag): Handle correctly clearning the flag.

From-SVN: r235081
parent b3de2446
2016-04-17 Jan Hubicka <jh@suse.cz>
PR ipa/70018
* cgraph.h (cgraph_node::set_const_flag,
cgraph_node::set_pure_flag): Update prototype to return bool;
update comment.
* cgraph.c (cgraph_node::call_for_symbol_thunks_and_aliases): Thunks
of interposable symbol are interposable, too.
(cgraph_set_const_flag_1): Rename to ...
(set_const_flag_1): ... this one; change to self recursive function
instead of call_for_symbol_thunks_and_aliases. Handle correctly
clearnig the flag in all variants and also virtual thunks of const
functions are pure; track if any change was done.
(cgraph_node::set_const_flag): Update.
(struct set_pure_flag_info): New struct.
(cgraph_set_pure_flag_1): Rename to ...
(set_pure_flag_1): ... this one; take set_pure_flag_info parameter
rather than pointer encoded flags; track if any changes was done;
handle correctly clearning flag and setting flag of aliases already
declared const.
(cgraph_node::set_pure_flag): Update.
(cgraph_node::set_nothrow_flag): Handle correctly clearning the flag.
2016-04-17 Tom de Vries <tom@codesourcery.com>
PR other/70433
......
......@@ -2308,6 +2308,8 @@ cgraph_node::call_for_symbol_thunks_and_aliases (bool (*callback)
exclude_virtual_thunks))
return true;
}
if (get_availability () <= AVAIL_INTERPOSABLE)
return false;
for (e = callers; e; e = e->next_caller)
if (e->caller->thunk.thunk_p
&& (include_overwritable
......@@ -2376,95 +2378,215 @@ void
cgraph_node::set_nothrow_flag (bool nothrow)
{
call_for_symbol_thunks_and_aliases (cgraph_set_nothrow_flag_1,
(void *)(size_t)nothrow, false);
(void *)(size_t)nothrow, nothrow == true);
}
/* Worker to set const flag. */
/* Worker to set_const_flag. */
static bool
cgraph_set_const_flag_1 (cgraph_node *node, void *data)
static void
set_const_flag_1 (cgraph_node *node, bool set_const, bool looping,
bool *changed)
{
/* Static constructors and destructors without a side effect can be
optimized out. */
if (data && !((size_t)data & 2))
if (set_const && !looping)
{
if (DECL_STATIC_CONSTRUCTOR (node->decl))
DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
{
DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
*changed = true;
}
if (DECL_STATIC_DESTRUCTOR (node->decl))
DECL_STATIC_DESTRUCTOR (node->decl) = 0;
{
DECL_STATIC_DESTRUCTOR (node->decl) = 0;
*changed = true;
}
}
if (!set_const)
{
if (TREE_READONLY (node->decl))
{
TREE_READONLY (node->decl) = 0;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
*changed = true;
}
}
else
{
/* Consider function:
/* Consider function:
bool a(int *p)
{
return *p==*p;
}
bool a(int *p)
{
return *p==*p;
}
During early optimization we will turn this into:
During early optimization we will turn this into:
bool a(int *p)
{
return true;
}
bool a(int *p)
{
return true;
}
Now if this function will be detected as CONST however when interposed
it may end up being just pure. We always must assume the worst
scenario here. */
if (TREE_READONLY (node->decl))
{
if (!looping && DECL_LOOPING_CONST_OR_PURE_P (node->decl))
{
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
*changed = true;
}
}
else if (node->binds_to_current_def_p ())
{
TREE_READONLY (node->decl) = true;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
DECL_PURE_P (node->decl) = false;
*changed = true;
}
else
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Dropping state to PURE because function does "
"not bind to current def.\n");
if (!DECL_PURE_P (node->decl))
{
DECL_PURE_P (node->decl) = true;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping;
*changed = true;
}
else if (!looping && DECL_LOOPING_CONST_OR_PURE_P (node->decl))
{
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
*changed = true;
}
}
}
Now if this function will be detected as CONST however when interposed it
may end up being just pure. We always must assume the worst scenario here.
*/
if (TREE_READONLY (node->decl))
;
else if (node->binds_to_current_def_p ())
TREE_READONLY (node->decl) = data != NULL;
else
ipa_ref *ref;
FOR_EACH_ALIAS (node, ref)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Dropping state to PURE because function does "
"not bind to current def.\n");
DECL_PURE_P (node->decl) = data != NULL;
cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
if (!set_const || alias->get_availability () > AVAIL_INTERPOSABLE)
set_const_flag_1 (alias, set_const, looping, changed);
}
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0;
return false;
for (cgraph_edge *e = node->callers; e; e = e->next_caller)
if (e->caller->thunk.thunk_p
&& (!set_const || e->caller->get_availability () > AVAIL_INTERPOSABLE))
{
/* Virtual thunks access virtual offset in the vtable, so they can
only be pure, never const. */
if (set_const
&& (e->caller->thunk.virtual_offset_p
|| !node->binds_to_current_def_p (e->caller)))
*changed |= e->caller->set_pure_flag (true, looping);
else
set_const_flag_1 (e->caller, set_const, looping, changed);
}
}
/* Set TREE_READONLY on cgraph_node's decl and on aliases of the node
if any to READONLY. */
/* If SET_CONST is true, mark function, aliases and thunks to be ECF_CONST.
If SET_CONST if false, clear the flag.
void
cgraph_node::set_const_flag (bool readonly, bool looping)
When setting the flag be careful about possible interposition and
do not set the flag for functions that can be interposet and set pure
flag for functions that can bind to other definition.
Return true if any change was done. */
bool
cgraph_node::set_const_flag (bool set_const, bool looping)
{
call_for_symbol_thunks_and_aliases (cgraph_set_const_flag_1,
(void *)(size_t)(readonly + (int)looping * 2),
false, true);
bool changed = false;
if (!set_const || get_availability () > AVAIL_INTERPOSABLE)
set_const_flag_1 (this, set_const, looping, &changed);
else
{
ipa_ref *ref;
FOR_EACH_ALIAS (this, ref)
{
cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
if (!set_const || alias->get_availability () > AVAIL_INTERPOSABLE)
set_const_flag_1 (alias, set_const, looping, &changed);
}
}
return changed;
}
/* Worker to set pure flag. */
/* Info used by set_pure_flag_1. */
struct
set_pure_flag_info
{
bool pure;
bool looping;
bool changed;
};
/* Worker to set_pure_flag. */
static bool
cgraph_set_pure_flag_1 (cgraph_node *node, void *data)
set_pure_flag_1 (cgraph_node *node, void *data)
{
struct set_pure_flag_info *info = (struct set_pure_flag_info *)data;
/* Static constructors and destructors without a side effect can be
optimized out. */
if (data && !((size_t)data & 2))
if (info->pure && !info->looping)
{
if (DECL_STATIC_CONSTRUCTOR (node->decl))
DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
{
DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
info->changed = true;
}
if (DECL_STATIC_DESTRUCTOR (node->decl))
DECL_STATIC_DESTRUCTOR (node->decl) = 0;
{
DECL_STATIC_DESTRUCTOR (node->decl) = 0;
info->changed = true;
}
}
if (info->pure)
{
if (!DECL_PURE_P (node->decl) && !TREE_READONLY (node->decl))
{
DECL_PURE_P (node->decl) = true;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = info->looping;
info->changed = true;
}
else if (DECL_LOOPING_CONST_OR_PURE_P (node->decl)
&& !info->looping)
{
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
info->changed = true;
}
}
else
{
if (DECL_PURE_P (node->decl))
{
DECL_PURE_P (node->decl) = false;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = false;
info->changed = true;
}
}
DECL_PURE_P (node->decl) = data != NULL;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0;
return false;
}
/* Set DECL_PURE_P on cgraph_node's decl and on aliases of the node
if any to PURE. */
if any to PURE.
void
When setting the flag, be careful about possible interposition.
Return true if any change was done. */
bool
cgraph_node::set_pure_flag (bool pure, bool looping)
{
call_for_symbol_thunks_and_aliases (cgraph_set_pure_flag_1,
(void *)(size_t)(pure + (int)looping * 2),
false, true);
struct set_pure_flag_info info = {pure, looping, false};
if (!pure)
looping = false;
call_for_symbol_thunks_and_aliases (set_pure_flag_1, &info, !pure, true);
return info.changed;
}
/* Return true when cgraph_node can not return or throw and thus
......
......@@ -1113,13 +1113,24 @@ public:
if any to NOTHROW. */
void set_nothrow_flag (bool nothrow);
/* Set TREE_READONLY on cgraph_node's decl and on aliases of the node
if any to READONLY. */
void set_const_flag (bool readonly, bool looping);
/* If SET_CONST is true, mark function, aliases and thunks to be ECF_CONST.
If SET_CONST if false, clear the flag.
When setting the flag be careful about possible interposition and
do not set the flag for functions that can be interposet and set pure
flag for functions that can bind to other definition.
Return true if any change was done. */
bool set_const_flag (bool set_const, bool looping);
/* Set DECL_PURE_P on cgraph_node's decl and on aliases of the node
if any to PURE. */
void set_pure_flag (bool pure, bool looping);
if any to PURE.
When setting the flag, be careful about possible interposition.
Return true if any change was done. */
bool set_pure_flag (bool pure, bool looping);
/* Call callback on function and aliases associated to the function.
When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
......
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