summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2015-02-27 02:06:48 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2015-02-27 02:06:48 +0000
commitce7711dff63867c071494efec46da4f8b973f27d (patch)
tree64340fdd45bcc8e11f6dbe5c80f68a86cce6c1fa /gcc
parent27859cd3bf7093f919737bf0cbe9abd8faff9718 (diff)
downloadgcc-ce7711dff63867c071494efec46da4f8b973f27d.tar.gz
PR bootstrap/65150
* ipa-icf.c (symbol_compare_collection::symbol_compare_colleciton): Use address_matters_p. (redirect_all_callers, set_addressable): New functions. (sem_function::merge): Reorganize and fix merging issues. (sem_variable::merge): Likewise. (sem_variable::compare_sections): Remove. * common.opt (fmerge-all-constants, fmerge-constants): Remove Optimization flag. * symtab.c (symtab_node::resolve_alias): When alias has aliases, redirect them. (symtab_node::make_decl_local): Set ADDRESSABLE bit when decl is used. (address_matters_1): New function. (symtab_node::address_matters_p): New function. * cgraph.c (cgraph_edge::verify_corresponds_to_fndecl): Fix check for merged flag. * cgraph.h (address_matters_p): Declare. (symtab_node::address_taken_from_non_vtable_p): Remove. (symtab_node::address_can_be_compared_p): New method. (ipa_ref::address_matters_p): Move here from ipa-ref.c; simplify. * ipa-visibility.c (symtab_node::address_taken_from_non_vtable_p): Remove. (comdat_can_be_unshared_p_1) Use address_matters_p. (update_vtable_references): Fix formating. * ipa-ref.c (ipa_ref::address_matters_p): Move inline. * cgraphunit.c (cgraph_node::create_wrapper): Drop UNINLINABLE flag. * cgraphclones.c: Preserve merged and icf_merged flags. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@221040 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog32
-rw-r--r--gcc/cgraph.c2
-rw-r--r--gcc/cgraph.h49
-rw-r--r--gcc/cgraphclones.c2
-rw-r--r--gcc/cgraphunit.c1
-rw-r--r--gcc/common.opt4
-rw-r--r--gcc/ipa-icf.c449
-rw-r--r--gcc/ipa-ref.c20
-rw-r--r--gcc/ipa-visibility.c42
-rw-r--r--gcc/symtab.c47
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/g++.dg/ipa/ipa-icf-4.C2
-rw-r--r--gcc/testsuite/g++.dg/warn/Wsuggest-final.C3
-rw-r--r--gcc/testsuite/gcc.dg/ipa/iinline-5.c2
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-cp-1.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-cp-2.c22
-rw-r--r--gcc/testsuite/gcc.dg/pr28685-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr64454.c2
18 files changed, 490 insertions, 223 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e0bafa794e4..e4346a0ae93 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,35 @@
+2015-02-26 Jan Hubicka <hubicka@ucw.cz>
+ Martin Liska <mliska@suse.cz>
+
+ PR bootstrap/65150
+ * ipa-icf.c (symbol_compare_collection::symbol_compare_colleciton):
+ Use address_matters_p.
+ (redirect_all_callers, set_addressable): New functions.
+ (sem_function::merge): Reorganize and fix merging issues.
+ (sem_variable::merge): Likewise.
+ (sem_variable::compare_sections): Remove.
+ * common.opt (fmerge-all-constants, fmerge-constants): Remove
+ Optimization flag.
+ * symtab.c (symtab_node::resolve_alias): When alias has aliases,
+ redirect them.
+ (symtab_node::make_decl_local): Set ADDRESSABLE bit when
+ decl is used.
+ (address_matters_1): New function.
+ (symtab_node::address_matters_p): New function.
+ * cgraph.c (cgraph_edge::verify_corresponds_to_fndecl): Fix
+ check for merged flag.
+ * cgraph.h (address_matters_p): Declare.
+ (symtab_node::address_taken_from_non_vtable_p): Remove.
+ (symtab_node::address_can_be_compared_p): New method.
+ (ipa_ref::address_matters_p): Move here from ipa-ref.c; simplify.
+ * ipa-visibility.c (symtab_node::address_taken_from_non_vtable_p):
+ Remove.
+ (comdat_can_be_unshared_p_1) Use address_matters_p.
+ (update_vtable_references): Fix formating.
+ * ipa-ref.c (ipa_ref::address_matters_p): Move inline.
+ * cgraphunit.c (cgraph_node::create_wrapper): Drop UNINLINABLE flag.
+ * cgraphclones.c: Preserve merged and icf_merged flags.
+
2015-02-26 Sandra Loosemore <sandra@codesourcery.com>
* doc/extend.texi (Function Attributes): Fix spelling and typos.
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 1ad08dc7631..5555439215e 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -2630,7 +2630,7 @@ cgraph_edge::verify_corresponds_to_fndecl (tree decl)
if (!node
|| node->body_removed
|| node->in_other_partition
- || node->icf_merged
+ || callee->icf_merged
|| callee->in_other_partition)
return false;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index ec3cccda866..ff437cf18b8 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -326,9 +326,6 @@ public:
/* Return true if ONE and TWO are part of the same COMDAT group. */
inline bool in_same_comdat_group_p (symtab_node *target);
- /* Return true when there is a reference to node and it is not vtable. */
- bool address_taken_from_non_vtable_p (void);
-
/* Return true if symbol is known to be nonzero. */
bool nonzero_address ();
@@ -337,6 +334,15 @@ public:
return 2 otherwise. */
int equal_address_to (symtab_node *s2);
+ /* Return true if symbol's address may possibly be compared to other
+ symbol's address. */
+ bool address_matters_p ();
+
+ /* Return true if NODE's address can be compared. This use properties
+ of NODE only and does not look if the address is actually taken in
+ interesting way. For that use ADDRESS_MATTERS_P instead. */
+ bool address_can_be_compared_p (void);
+
/* Return symbol table node associated with DECL, if any,
and NULL otherwise. */
static inline symtab_node *get (const_tree decl)
@@ -3022,6 +3028,43 @@ varpool_node::call_for_symbol_and_aliases (bool (*callback) (varpool_node *,
return false;
}
+/* Return true if NODE's address can be compared. */
+
+inline bool
+symtab_node::address_can_be_compared_p ()
+{
+ /* Address of virtual tables and functions is never compared. */
+ if (DECL_VIRTUAL_P (decl))
+ return false;
+ /* Address of C++ cdtors is never compared. */
+ if (is_a <cgraph_node *> (this)
+ && (DECL_CXX_CONSTRUCTOR_P (decl)
+ || DECL_CXX_DESTRUCTOR_P (decl)))
+ return false;
+ /* Constant pool symbols addresses are never compared.
+ flag_merge_constants permits us to assume the same on readonly vars. */
+ if (is_a <varpool_node *> (this)
+ && (DECL_IN_CONSTANT_POOL (decl)
+ || (flag_merge_constants >= 2
+ && TREE_READONLY (decl) && !TREE_THIS_VOLATILE (decl))))
+ return false;
+ return true;
+}
+
+/* Return true if refernece may be used in address compare. */
+
+inline bool
+ipa_ref::address_matters_p ()
+{
+ if (use != IPA_REF_ADDR)
+ return false;
+ /* Addresses taken from virtual tables are never compared. */
+ if (is_a <varpool_node *> (referring)
+ && DECL_VIRTUAL_P (referring->decl))
+ return false;
+ return referred->address_can_be_compared_p ();
+}
+
/* Build polymorphic call context for indirect call E. */
inline
diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
index d0a5f707136..c74017615fd 100644
--- a/gcc/cgraphclones.c
+++ b/gcc/cgraphclones.c
@@ -471,6 +471,8 @@ cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
new_node->frequency = frequency;
new_node->tp_first_run = tp_first_run;
new_node->tm_clone = tm_clone;
+ new_node->icf_merged = icf_merged;
+ new_node->merged = merged;
new_node->clone.tree_map = NULL;
new_node->clone.args_to_skip = args_to_skip;
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 942826d3682..9f6878a19e3 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -2468,6 +2468,7 @@ cgraph_node::create_wrapper (cgraph_node *target)
release_body (true);
reset ();
+ DECL_UNINLINABLE (decl) = false;
DECL_RESULT (decl) = decl_result;
DECL_INITIAL (decl) = NULL;
allocate_struct_function (decl, false);
diff --git a/gcc/common.opt b/gcc/common.opt
index 4fa12f5fa38..b49ac46610c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1644,11 +1644,11 @@ Report on permanent memory allocation in WPA only
; string constants and constants from constant pool, if 2 also constant
; variables.
fmerge-all-constants
-Common Report Var(flag_merge_constants,2) Init(1) Optimization
+Common Report Var(flag_merge_constants,2) Init(1)
Attempt to merge identical constants and constant variables
fmerge-constants
-Common Report Var(flag_merge_constants,1) Optimization
+Common Report Var(flag_merge_constants,1)
Attempt to merge identical constants across compilation units
fmerge-debug-strings
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 1d6cbebdf9c..5d50b6f639b 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -147,7 +147,7 @@ symbol_compare_collection::symbol_compare_collection (symtab_node *node)
if (ref->referred->get_availability () <= AVAIL_INTERPOSABLE)
{
- if (ref->use == IPA_REF_ADDR)
+ if (ref->address_matters_p ())
m_references.safe_push (ref->referred);
else
m_interposables.safe_push (ref->referred);
@@ -632,8 +632,56 @@ set_local (cgraph_node *node, void *data)
return false;
}
+/* TREE_ADDRESSABLE of NODE to true if DATA is non-NULL.
+ Helper for call_for_symbol_thunks_and_aliases. */
+
+static bool
+set_addressable (varpool_node *node, void *)
+{
+ TREE_ADDRESSABLE (node->decl) = 1;
+ return false;
+}
+
+/* Redirect all callers of N and its aliases to TO. Remove aliases if
+ possible. Return number of redirections made. */
+
+static int
+redirect_all_callers (cgraph_node *n, cgraph_node *to)
+{
+ int nredirected = 0;
+ ipa_ref *ref;
+
+ while (n->callers)
+ {
+ cgraph_edge *e = n->callers;
+ e->redirect_callee (to);
+ nredirected++;
+ }
+ for (unsigned i = 0; n->iterate_direct_aliases (i, ref);)
+ {
+ bool removed = false;
+ cgraph_node *n_alias = dyn_cast <cgraph_node *> (ref->referring);
+
+ if ((DECL_COMDAT_GROUP (n->decl)
+ && (DECL_COMDAT_GROUP (n->decl)
+ == DECL_COMDAT_GROUP (n_alias->decl)))
+ || (n_alias->get_availability () > AVAIL_INTERPOSABLE
+ && n->get_availability () > AVAIL_INTERPOSABLE))
+ {
+ nredirected += redirect_all_callers (n_alias, to);
+ if (n_alias->can_remove_if_no_direct_calls_p ()
+ && !n_alias->has_aliases_p ())
+ n_alias->remove ();
+ }
+ if (!removed)
+ i++;
+ }
+ return nredirected;
+}
+
/* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
be applied. */
+
bool
sem_function::merge (sem_item *alias_item)
{
@@ -642,16 +690,29 @@ sem_function::merge (sem_item *alias_item)
sem_function *alias_func = static_cast<sem_function *> (alias_item);
cgraph_node *original = get_node ();
- cgraph_node *local_original = original;
+ cgraph_node *local_original = NULL;
cgraph_node *alias = alias_func->get_node ();
- bool original_address_matters;
- bool alias_address_matters;
- bool create_thunk = false;
+ bool create_wrapper = false;
bool create_alias = false;
bool redirect_callers = false;
+ bool remove = false;
+
bool original_discardable = false;
+ bool original_address_matters = original->address_matters_p ();
+ bool alias_address_matters = alias->address_matters_p ();
+
+ if (DECL_NO_INLINE_WARNING_P (original->decl)
+ != DECL_NO_INLINE_WARNING_P (alias->decl))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Not unifying; "
+ "DECL_NO_INLINE_WARNING mismatch.\n\n");
+ return false;
+ }
+
/* Do not attempt to mix functions from different user sections;
we do not know what user intends with those. */
if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
@@ -660,123 +721,173 @@ sem_function::merge (sem_item *alias_item)
{
if (dump_file)
fprintf (dump_file,
- "Not unifying; original and alias are in different sections.\n\n");
+ "Not unifying; "
+ "original and alias are in different sections.\n\n");
return false;
}
/* See if original is in a section that can be discarded if the main
- symbol is not used. */
- if (DECL_EXTERNAL (original->decl))
- original_discardable = true;
- if (original->resolution == LDPR_PREEMPTED_REG
- || original->resolution == LDPR_PREEMPTED_IR)
- original_discardable = true;
- if (original->can_be_discarded_p ())
+ symbol is not used.
+
+ Also consider case where we have resolution info and we know that
+ original's definition is not going to be used. In this case we can not
+ create alias to original. */
+ if (original->can_be_discarded_p ()
+ || (node->resolution != LDPR_UNKNOWN
+ && !decl_binds_to_current_def_p (node->decl)))
original_discardable = true;
- /* See if original and/or alias address can be compared for equality. */
- original_address_matters
- = (!DECL_VIRTUAL_P (original->decl)
- && (original->externally_visible
- || original->address_taken_from_non_vtable_p ()));
- alias_address_matters
- = (!DECL_VIRTUAL_P (alias->decl)
- && (alias->externally_visible
- || alias->address_taken_from_non_vtable_p ()));
-
- /* If alias and original can be compared for address equality, we need
- to create a thunk. Also we can not create extra aliases into discardable
- section (or we risk link failures when section is discarded). */
- if ((original_address_matters
- && alias_address_matters)
+ /* Creating a symtab alias is the optimal way to merge.
+ It however can not be used in the following cases:
+
+ 1) if ORIGINAL and ALIAS may be possibly compared for address equality.
+ 2) if ORIGINAL is in a section that may be discarded by linker or if
+ it is an external functions where we can not create an alias
+ (ORIGINAL_DISCARDABLE)
+ 3) if target do not support symbol aliases.
+
+ If we can not produce alias, we will turn ALIAS into WRAPPER of ORIGINAL
+ and/or redirect all callers from ALIAS to ORIGINAL. */
+ if ((original_address_matters && alias_address_matters)
|| original_discardable
- || DECL_COMDAT_GROUP (alias->decl)
|| !sem_item::target_supports_symbol_aliases_p ())
{
- create_thunk = !stdarg_p (TREE_TYPE (alias->decl));
- create_alias = false;
- /* When both alias and original are not overwritable, we can save
- the extra thunk wrapper for direct calls. */
+ /* First see if we can produce wrapper. */
+
+ /* Do not turn function in one comdat group into wrapper to another
+ comdat group. Other compiler producing the body of the
+ another comdat group may make opossite decision and with unfortunate
+ linker choices this may close a loop. */
+ if (DECL_COMDAT_GROUP (alias->decl)
+ && (DECL_COMDAT_GROUP (alias->decl)
+ != DECL_COMDAT_GROUP (original->decl)))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Wrapper cannot be created because of COMDAT\n");
+ }
+ else if (DECL_STATIC_CHAIN (alias->decl))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Can not create wrapper of nested functions.\n");
+ }
+ /* TODO: We can also deal with variadic functions never calling
+ VA_START. */
+ else if (stdarg_p (TREE_TYPE (alias->decl)))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "can not create wrapper of stdarg function.\n");
+ }
+ else if (inline_summaries
+ && inline_summaries->get (alias)->self_size <= 2)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Wrapper creation is not "
+ "profitable (function is too small).\n");
+ }
+ /* If user paid attention to mark function noinline, assume it is
+ somewhat special and do not try to turn it into a wrapper that can
+ not be undone by inliner. */
+ else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (alias->decl)))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Wrappers are not created for noinline.\n");
+ }
+ else
+ create_wrapper = true;
+
+ /* We can redirect local calls in the case both alias and orignal
+ are not interposable. */
redirect_callers
- = (!original_discardable
- && !DECL_COMDAT_GROUP (alias->decl)
- && alias->get_availability () > AVAIL_INTERPOSABLE
- && original->get_availability () > AVAIL_INTERPOSABLE
- && !alias->instrumented_version);
- }
- else
- {
- create_alias = true;
- create_thunk = false;
- redirect_callers = false;
- }
+ = alias->get_availability () > AVAIL_INTERPOSABLE
+ && original->get_availability () > AVAIL_INTERPOSABLE
+ && !alias->instrumented_version;
- /* We want thunk to always jump to the local function body
- unless the body is comdat and may be optimized out. */
- if ((create_thunk || redirect_callers)
- && (!original_discardable
+ if (!redirect_callers && !create_wrapper)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not unifying; can not redirect callers nor "
+ "produce wrapper\n\n");
+ return false;
+ }
+
+ /* Work out the symbol the wrapper should call.
+ If ORIGINAL is interposable, we need to call a local alias.
+ Also produce local alias (if possible) as an optimization. */
+ if (!original_discardable
|| (DECL_COMDAT_GROUP (original->decl)
&& (DECL_COMDAT_GROUP (original->decl)
- == DECL_COMDAT_GROUP (alias->decl)))))
- local_original
- = dyn_cast <cgraph_node *> (original->noninterposable_alias ());
-
- if (!local_original)
- {
- if (dump_file)
- fprintf (dump_file, "Noninterposable alias cannot be created.\n\n");
-
- return false;
- }
+ == DECL_COMDAT_GROUP (alias->decl))))
+ {
+ local_original
+ = dyn_cast <cgraph_node *> (original->noninterposable_alias ());
+ if (!local_original
+ && original->get_availability () > AVAIL_INTERPOSABLE)
+ local_original = original;
+ /* If original is COMDAT local, we can not really redirect external
+ callers to it. */
+ if (original->comdat_local_p ())
+ redirect_callers = false;
+ }
+ /* If we can not use local alias, fallback to the original
+ when possible. */
+ else if (original->get_availability () > AVAIL_INTERPOSABLE)
+ local_original = original;
+ if (!local_original)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not unifying; "
+ "can not produce local alias.\n\n");
+ return false;
+ }
- if (!decl_binds_to_current_def_p (alias->decl))
- {
- if (dump_file)
- fprintf (dump_file, "Declaration does not bind to currect definition.\n\n");
- return false;
+ if (!redirect_callers && !create_wrapper)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not unifying; "
+ "can not redirect callers nor produce a wrapper\n\n");
+ return false;
+ }
+ if (!create_wrapper
+ && !alias->can_remove_if_no_direct_calls_p ())
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not unifying; can not make wrapper and "
+ "function has other uses than direct calls\n\n");
+ return false;
+ }
}
+ else
+ create_alias = true;
if (redirect_callers)
{
- /* If alias is non-overwritable then
- all direct calls are safe to be redirected to the original. */
- bool redirected = false;
- while (alias->callers)
- {
- cgraph_edge *e = alias->callers;
- e->redirect_callee (local_original);
- push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
+ int nredirected = redirect_all_callers (alias, local_original);
- if (e->call_stmt)
- e->redirect_call_stmt_to_callee ();
+ if (nredirected)
+ {
+ alias->icf_merged = true;
+ local_original->icf_merged = true;
- pop_cfun ();
- redirected = true;
+ if (dump_file && nredirected)
+ fprintf (dump_file, "%i local calls have been "
+ "redirected.\n", nredirected);
}
- alias->icf_merged = true;
- if (local_original->lto_file_data
- && alias->lto_file_data
- && local_original->lto_file_data != alias->lto_file_data)
- local_original->merged = true;
-
- /* The alias function is removed if symbol address
- does not matter. */
- if (!alias_address_matters)
- alias->remove ();
-
- if (dump_file && redirected)
- fprintf (dump_file, "Callgraph local calls have been redirected.\n\n");
+ /* If all callers was redirected, do not produce wrapper. */
+ if (alias->can_remove_if_no_direct_calls_p ()
+ && !alias->has_aliases_p ())
+ {
+ create_wrapper = false;
+ remove = true;
+ }
+ gcc_assert (!create_alias);
}
- /* If the condtion above is not met, we are lucky and can turn the
- function into real alias. */
else if (create_alias)
{
alias->icf_merged = true;
- if (local_original->lto_file_data
- && alias->lto_file_data
- && local_original->lto_file_data != alias->lto_file_data)
- local_original->merged = true;
/* Remove the function's body. */
ipa_merge_profiles (original, alias);
@@ -791,39 +902,38 @@ sem_function::merge (sem_item *alias_item)
(set_local, (void *)(size_t) original->local_p (), true);
if (dump_file)
- fprintf (dump_file, "Callgraph alias has been created.\n\n");
+ fprintf (dump_file, "Unified; Function alias has been created.\n\n");
}
- else if (create_thunk)
+ if (create_wrapper)
{
- if (DECL_COMDAT_GROUP (alias->decl))
- {
- if (dump_file)
- fprintf (dump_file, "Callgraph thunk cannot be created because of COMDAT\n");
+ gcc_assert (!create_alias);
+ alias->icf_merged = true;
+ local_original->icf_merged = true;
- return 0;
- }
+ ipa_merge_profiles (local_original, alias, true);
+ alias->create_wrapper (local_original);
- if (DECL_STATIC_CHAIN (alias->decl))
- {
- if (dump_file)
- fprintf (dump_file, "Thunk creation is risky for static-chain functions.\n\n");
+ if (dump_file)
+ fprintf (dump_file, "Unified; Wrapper has been created.\n\n");
+ }
+ gcc_assert (alias->icf_merged || remove);
+ original->icf_merged = true;
- return 0;
- }
+ /* Inform the inliner about cross-module merging. */
+ if ((original->lto_file_data || alias->lto_file_data)
+ && original->lto_file_data != alias->lto_file_data)
+ local_original->merged = original->merged = true;
+ if (remove)
+ {
+ ipa_merge_profiles (original, alias);
+ alias->release_body ();
+ alias->reset ();
+ alias->body_removed = true;
alias->icf_merged = true;
- if (local_original->lto_file_data
- && alias->lto_file_data
- && local_original->lto_file_data != alias->lto_file_data)
- local_original->merged = true;
- ipa_merge_profiles (local_original, alias, true);
- alias->create_wrapper (local_original);
-
if (dump_file)
- fprintf (dump_file, "Callgraph thunk has been created.\n\n");
+ fprintf (dump_file, "Unified; Function body was removed.\n");
}
- else if (dump_file)
- fprintf (dump_file, "Callgraph merge operation cannot be performed.\n\n");
return true;
}
@@ -1319,7 +1429,8 @@ sem_variable::merge (sem_item *alias_item)
if (!sem_item::target_supports_symbol_aliases_p ())
{
if (dump_file)
- fprintf (dump_file, "Symbol aliases are not supported by target\n\n");
+ fprintf (dump_file, "Not unifying; "
+ "Symbol aliases are not supported by target\n\n");
return false;
}
@@ -1329,73 +1440,93 @@ sem_variable::merge (sem_item *alias_item)
varpool_node *alias = alias_var->get_node ();
bool original_discardable = false;
+ bool original_address_matters = original->address_matters_p ();
+ bool alias_address_matters = alias->address_matters_p ();
+
/* See if original is in a section that can be discarded if the main
- symbol is not used. */
- if (DECL_EXTERNAL (original->decl))
- original_discardable = true;
- if (original->resolution == LDPR_PREEMPTED_REG
- || original->resolution == LDPR_PREEMPTED_IR)
- original_discardable = true;
- if (original->can_be_discarded_p ())
+ symbol is not used.
+ Also consider case where we have resolution info and we know that
+ original's definition is not going to be used. In this case we can not
+ create alias to original. */
+ if (original->can_be_discarded_p ()
+ || (node->resolution != LDPR_UNKNOWN
+ && !decl_binds_to_current_def_p (node->decl)))
original_discardable = true;
gcc_assert (!TREE_ASM_WRITTEN (alias->decl));
- if (original_discardable || DECL_EXTERNAL (alias_var->decl) ||
- !compare_sections (alias_var))
+ /* Constant pool machinery is not quite ready for aliases.
+ TODO: varasm code contains logic for merging DECL_IN_CONSTANT_POOL.
+ For LTO merging does not happen that is an important missing feature.
+ We can enable merging with LTO if the DECL_IN_CONSTANT_POOL
+ flag is dropped and non-local symbol name is assigned. */
+ if (DECL_IN_CONSTANT_POOL (alias->decl)
+ || DECL_IN_CONSTANT_POOL (original->decl))
{
if (dump_file)
- fprintf (dump_file, "Varpool alias cannot be created\n\n");
+ fprintf (dump_file,
+ "Not unifying; constant pool variables.\n\n");
+ return false;
+ }
+ /* Do not attempt to mix functions from different user sections;
+ we do not know what user intends with those. */
+ if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
+ || (DECL_SECTION_NAME (alias->decl) && !alias->implicit_section))
+ && DECL_SECTION_NAME (original->decl) != DECL_SECTION_NAME (alias->decl))
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Not unifying; "
+ "original and alias are in different sections.\n\n");
return false;
}
- else
+
+ /* We can not merge if address comparsion metters. */
+ if (original_address_matters && alias_address_matters
+ && flag_merge_constants < 2)
{
- // alias cycle creation check
- varpool_node *n = original;
+ if (dump_file)
+ fprintf (dump_file,
+ "Not unifying; "
+ "adress of original and alias may be compared.\n\n");
+ return false;
+ }
- while (n->alias)
- {
- n = n->get_alias_target ();
- if (n == alias)
- {
- if (dump_file)
- fprintf (dump_file, "Varpool alias cannot be created (alias cycle).\n\n");
+ if (original_discardable
+ && (!DECL_COMDAT_GROUP (original->decl)
+ || (DECL_COMDAT_GROUP (original->decl)
+ != DECL_COMDAT_GROUP (alias->decl))))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not unifying; alias cannot be created; "
+ "target is discardable\n\n");
- return false;
- }
- }
+ return false;
+ }
+ else
+ {
+ gcc_assert (!original->alias);
+ gcc_assert (!alias->alias);
alias->analyzed = false;
DECL_INITIAL (alias->decl) = NULL;
alias->need_bounds_init = false;
alias->remove_all_references ();
+ if (TREE_ADDRESSABLE (alias->decl))
+ original->call_for_symbol_and_aliases (set_addressable, NULL, true);
varpool_node::create_alias (alias_var->decl, decl);
alias->resolve_alias (original);
if (dump_file)
- fprintf (dump_file, "Varpool alias has been created.\n\n");
+ fprintf (dump_file, "Unified; Variable alias has been created.\n\n");
return true;
}
}
-bool
-sem_variable::compare_sections (sem_variable *alias)
-{
- const char *source = node->get_section ();
- const char *target = alias->node->get_section();
-
- if (source == NULL && target == NULL)
- return true;
- else if(!source || !target)
- return false;
- else
- return strcmp (source, target) == 0;
-}
-
/* Dump symbol to FILE. */
void
diff --git a/gcc/ipa-ref.c b/gcc/ipa-ref.c
index f9af352f2f9..91c2f89af25 100644
--- a/gcc/ipa-ref.c
+++ b/gcc/ipa-ref.c
@@ -124,23 +124,3 @@ ipa_ref::referred_ref_list (void)
{
return &referred->ref_list;
}
-
-/* Return true if refernece may be used in address compare. */
-bool
-ipa_ref::address_matters_p ()
-{
- if (use != IPA_REF_ADDR)
- return false;
- /* Addresses taken from virtual tables are never compared. */
- if (is_a <varpool_node *> (referring)
- && DECL_VIRTUAL_P (referring->decl))
- return false;
- /* Address of virtual tables and functions is never compared. */
- if (DECL_VIRTUAL_P (referred->decl))
- return false;
- /* Address of C++ cdtors is never compared. */
- if (is_a <cgraph_node *> (referred)
- && (DECL_CXX_CONSTRUCTOR_P (referred->decl) || DECL_CXX_DESTRUCTOR_P (referred->decl)))
- return false;
- return true;
-}
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index 9247e2976e7..7614cfbee4b 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -129,27 +129,6 @@ cgraph_node::local_p (void)
}
-/* Return true when there is a reference to node and it is not vtable. */
-
-bool
-symtab_node::address_taken_from_non_vtable_p (void)
-{
- int i;
- struct ipa_ref *ref = NULL;
-
- for (i = 0; iterate_referring (i, ref); i++)
- if (ref->use == IPA_REF_ADDR)
- {
- varpool_node *node;
- if (is_a <cgraph_node *> (ref->referring))
- return true;
- node = dyn_cast <varpool_node *> (ref->referring);
- if (!DECL_VIRTUAL_P (node->decl))
- return true;
- }
- return false;
-}
-
/* A helper for comdat_can_be_unshared_p. */
static bool
@@ -157,16 +136,14 @@ comdat_can_be_unshared_p_1 (symtab_node *node)
{
if (!node->externally_visible)
return true;
- /* When address is taken, we don't know if equality comparison won't
- break eventually. Exception are virutal functions, C++
- constructors/destructors and vtables, where this is not possible by
- language standard. */
- if (!DECL_VIRTUAL_P (node->decl)
- && (TREE_CODE (node->decl) != FUNCTION_DECL
- || (!DECL_CXX_CONSTRUCTOR_P (node->decl)
- && !DECL_CXX_DESTRUCTOR_P (node->decl)))
- && node->address_taken_from_non_vtable_p ())
- return false;
+ if (node->address_can_be_compared_p ())
+ {
+ struct ipa_ref *ref;
+
+ for (unsigned int i = 0; node->iterate_referring (i, ref); i++)
+ if (ref->address_matters_p ())
+ return false;
+ }
/* If the symbol is used in some weird way, better to not touch it. */
if (node->force_output)
@@ -387,7 +364,8 @@ can_replace_by_local_alias_in_vtable (symtab_node *node)
/* walk_tree callback that rewrites initializer references. */
static tree
-update_vtable_references (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+update_vtable_references (tree *tp, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
{
if (TREE_CODE (*tp) == VAR_DECL
|| TREE_CODE (*tp) == FUNCTION_DECL)
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 957457b25e5..a46ebd49efa 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -1156,7 +1156,11 @@ symtab_node::make_decl_local (void)
return;
if (TREE_CODE (decl) == VAR_DECL)
- DECL_COMMON (decl) = 0;
+ {
+ DECL_COMMON (decl) = 0;
+ /* ADDRESSABLE flag is not defined for public symbols. */
+ TREE_ADDRESSABLE (decl) = 1;
+ }
else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
DECL_COMDAT (decl) = 0;
@@ -1513,6 +1517,19 @@ symtab_node::resolve_alias (symtab_node *target)
/* If alias has address taken, so does the target. */
if (address_taken)
target->ultimate_alias_target ()->address_taken = true;
+
+ /* All non-weakref aliases of THIS are now in fact aliases of TARGET. */
+ ipa_ref *ref;
+ for (unsigned i = 0; iterate_direct_aliases (i, ref);)
+ {
+ struct symtab_node *alias_alias = ref->referring;
+ if (!alias_alias->weakref)
+ {
+ alias_alias->remove_all_references ();
+ alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
+ }
+ else i++;
+ }
return true;
}
@@ -1863,3 +1880,31 @@ symtab_node::call_for_symbol_and_aliases_1 (bool (*callback) (symtab_node *,
}
return false;
}
+
+/* Return ture if address of N is possibly compared. */
+
+static bool
+address_matters_1 (symtab_node *n, void *)
+{
+ struct ipa_ref *ref;
+
+ if (!n->address_can_be_compared_p ())
+ return false;
+ if (n->externally_visible || n->force_output)
+ return true;
+
+ for (unsigned int i = 0; n->iterate_referring (i, ref); i++)
+ if (ref->address_matters_p ())
+ return true;
+ return false;
+}
+
+/* Return true if symbol's address may possibly be compared to other
+ symbol's address. */
+
+bool
+symtab_node::address_matters_p ()
+{
+ gcc_assert (!alias);
+ return call_for_symbol_and_aliases (address_matters_1, NULL, true);
+}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 93fc50f2a91..3566d034365 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2015-02-26 Jan Hubicka <hubicka@ucw.cz>
+ Martin Liska <mliska@suse.cz>
+
+ PR bootstrap/65150
+ * gcc.dg/pr64454.c: Disable ICF.
+ * gcc.dg/pr28685-1.c: Disable ICF
+ * gcc.dg/ipa/iinline-5.c: Disable ICF.
+ * g++.dg/warn/Wsuggest-final.C: Force methods to be different.
+ * g++.dg/ipa/ipa-icf-4.C: Update template.
+
2015-02-26 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/65216
diff --git a/gcc/testsuite/g++.dg/ipa/ipa-icf-4.C b/gcc/testsuite/g++.dg/ipa/ipa-icf-4.C
index 912e06b9b43..2cd7a2eed3a 100644
--- a/gcc/testsuite/g++.dg/ipa/ipa-icf-4.C
+++ b/gcc/testsuite/g++.dg/ipa/ipa-icf-4.C
@@ -43,6 +43,6 @@ int main()
return 123;
}
-/* { dg-final { scan-ipa-dump "\(Varpool alias has been created\)|\(Symbol aliases are not supported by target\)" "icf" } } */
+/* { dg-final { scan-ipa-dump "\(Unified; Variable alias has been created\)|\(Symbol aliases are not supported by target\)" "icf" } } */
/* { dg-final { scan-ipa-dump "Equal symbols: 6" "icf" } } */
/* { dg-final { cleanup-ipa-dump "icf" } } */
diff --git a/gcc/testsuite/g++.dg/warn/Wsuggest-final.C b/gcc/testsuite/g++.dg/warn/Wsuggest-final.C
index 5371063559d..f1d419e144a 100644
--- a/gcc/testsuite/g++.dg/warn/Wsuggest-final.C
+++ b/gcc/testsuite/g++.dg/warn/Wsuggest-final.C
@@ -1,8 +1,9 @@
// { dg-do compile }
// { dg-options "-O2 -Wsuggest-final-types -Wsuggest-final-methods" }
+int c;
struct A { // { dg-warning "final would enable devirtualization of 4 calls" }
virtual void a() {} // { dg-warning "final would enable devirtualization of 2 calls" }
- virtual void b() {} // { dg-warning "final would enable devirtualization of 2 calls" }
+ virtual void b() {c++;} // { dg-warning "final would enable devirtualization of 2 calls" }
};
void
t(struct A *a)
diff --git a/gcc/testsuite/gcc.dg/ipa/iinline-5.c b/gcc/testsuite/gcc.dg/ipa/iinline-5.c
index 8fb47caffcc..b83b8c25a92 100644
--- a/gcc/testsuite/gcc.dg/ipa/iinline-5.c
+++ b/gcc/testsuite/gcc.dg/ipa/iinline-5.c
@@ -1,7 +1,7 @@
/* Verify that simple indirect calls are inlined even without early
inlining.. */
/* { dg-do run } */
-/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-icf" } */
extern void abort (void);
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-cp-1.c b/gcc/testsuite/gcc.dg/ipa/ipa-cp-1.c
new file mode 100644
index 00000000000..b1ec4d4bb66
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-cp-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp" } */
+int n;
+
+static void
+__attribute__ ((noinline))
+test(void *a)
+{
+ __builtin_memset (a,0,n);
+}
+
+int
+main()
+{
+ int aa;
+ short bb;
+ test (&aa);
+ test (&bb);
+ return 0;
+}
+/* { dg-final { scan-ipa-dump "Alignment 2" "cp" } } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-cp-2.c b/gcc/testsuite/gcc.dg/ipa/ipa-cp-2.c
new file mode 100644
index 00000000000..0dbbcf1c0e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-cp-2.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp" } */
+int n;
+
+static void
+__attribute__ ((noinline))
+test(void *a)
+{
+ __builtin_memset (a,0,n);
+}
+
+static __attribute__ ((aligned(16))) int aa[10];
+
+int
+main()
+{
+ test (&aa[1]);
+ test (&aa[3]);
+ return 0;
+}
+/* { dg-final { scan-ipa-dump "Alignment 8, misalignment 4" "cp" } } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/pr28685-1.c b/gcc/testsuite/gcc.dg/pr28685-1.c
index 1d9d97ed615..1eb8c2d457b 100644
--- a/gcc/testsuite/gcc.dg/pr28685-1.c
+++ b/gcc/testsuite/gcc.dg/pr28685-1.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-ipa-icf" } */
/* Should produce <=. */
int test1 (int a, int b)
diff --git a/gcc/testsuite/gcc.dg/pr64454.c b/gcc/testsuite/gcc.dg/pr64454.c
index 33018d3bb18..35542349c70 100644
--- a/gcc/testsuite/gcc.dg/pr64454.c
+++ b/gcc/testsuite/gcc.dg/pr64454.c
@@ -1,6 +1,6 @@
/* PR tree-optimization/64454 */
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-options "-O2 -fdump-tree-vrp1 -fno-ipa-icf" } */
unsigned
f1 (unsigned x)