aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2016-04-17 18:04:05 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2016-04-17 16:04:05 +0000
commit69a4e898c8f508f0c56c72c791a38bc432e9fa69 (patch)
treedab34f7a272189308734eab631e4f507410d806b
parentb3de2446458bf8c61a8e54d6bd424bafe7ab479e (diff)
downloadgcc-69a4e898c8f508f0c56c72c791a38bc432e9fa69.zip
gcc-69a4e898c8f508f0c56c72c791a38bc432e9fa69.tar.gz
gcc-69a4e898c8f508f0c56c72c791a38bc432e9fa69.tar.bz2
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
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/cgraph.c222
-rw-r--r--gcc/cgraph.h21
3 files changed, 211 insertions, 55 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5dd1b09..1e9ef9b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,26 @@
+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
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index c43adb9..d8cb526 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -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
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 5b2b4bc..71e31a4 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -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