aboutsummaryrefslogtreecommitdiff
path: root/gcc/symtab.c
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2014-12-07 08:35:11 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2014-12-07 07:35:11 +0000
commit3cb251b77933671acc8717ede172be28d839927f (patch)
tree94cb96a4a951949b96e031fdf5a464a3bdc185de /gcc/symtab.c
parent8c8d3b4c128996f8188d76a0fe61e79b8304f0a8 (diff)
downloadgcc-3cb251b77933671acc8717ede172be28d839927f.zip
gcc-3cb251b77933671acc8717ede172be28d839927f.tar.gz
gcc-3cb251b77933671acc8717ede172be28d839927f.tar.bz2
symtab.c (symtab_node::equal_address_to): New function.
* symtab.c (symtab_node::equal_address_to): New function. * cgraph.h (symtab_node::equal_address_to): Declare. * fold-const.c (fold_comparison, fold_binary_loc): Use it. * c-family/c-common.c: Refuse weaks for symbols that can not change visibility. * gcc.dg/addr_equal-1.c: New testcase. From-SVN: r218462
Diffstat (limited to 'gcc/symtab.c')
-rw-r--r--gcc/symtab.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 29839e6..3eceb88 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -1860,3 +1860,90 @@ symtab_node::nonzero_address ()
return true;
return false;
}
+
+/* Return 0 if symbol is known to have different address than S2,
+ Return 1 if symbol is known to have same address as S2,
+ return 2 otherwise. */
+int
+symtab_node::equal_address_to (symtab_node *s2)
+{
+ enum availability avail1, avail2;
+
+ /* A Shortcut: equivalent symbols are always equivalent. */
+ if (this == s2)
+ return 1;
+
+ /* For non-interposable aliases, lookup and compare their actual definitions.
+ Also check if the symbol needs to bind to given definition. */
+ symtab_node *rs1 = ultimate_alias_target (&avail1);
+ symtab_node *rs2 = s2->ultimate_alias_target (&avail2);
+ bool binds_local1 = rs1->analyzed && decl_binds_to_current_def_p (this->decl);
+ bool binds_local2 = rs2->analyzed && decl_binds_to_current_def_p (s2->decl);
+ bool really_binds_local1 = binds_local1;
+ bool really_binds_local2 = binds_local2;
+
+ /* Addresses of vtables and virtual functions can not be used by user
+ code and are used only within speculation. In this case we may make
+ symbol equivalent to its alias even if interposition may break this
+ rule. Doing so will allow us to turn speculative inlining into
+ non-speculative more agressively. */
+ if (DECL_VIRTUAL_P (this->decl) && avail1 >= AVAIL_AVAILABLE)
+ binds_local1 = true;
+ if (DECL_VIRTUAL_P (s2->decl) && avail2 >= AVAIL_AVAILABLE)
+ binds_local2 = true;
+
+ /* If both definitions are available we know that even if they are bound
+ to other unit they must be defined same way and therefore we can use
+ equivalence test. */
+ if (rs1 != rs2 && avail1 >= AVAIL_AVAILABLE && avail2 >= AVAIL_AVAILABLE)
+ binds_local1 = binds_local2 = true;
+
+ if ((binds_local1 ? rs1 : this)
+ == (binds_local2 ? rs2 : s2))
+ {
+ /* We made use of the fact that alias is not weak. */
+ if (binds_local1 && rs1 != this)
+ refuse_visibility_changes = true;
+ if (binds_local2 && rs2 != s2)
+ s2->refuse_visibility_changes = true;
+ return 1;
+ }
+
+ /* If both symbols may resolve to NULL, we can not really prove them different. */
+ if (!nonzero_address () && !s2->nonzero_address ())
+ return 2;
+
+ /* Except for NULL, functions and variables never overlap. */
+ if (TREE_CODE (decl) != TREE_CODE (s2->decl))
+ return 0;
+
+ /* If one of the symbols is unresolved alias, punt. */
+ if (rs1->alias || rs2->alias)
+ return 2;
+
+ /* If we have a non-interposale definition of at least one of the symbols
+ and the other symbol is different, we know other unit can not interpose
+ it to the first symbol; all aliases of the definition needs to be
+ present in the current unit. */
+ if (((really_binds_local1 || really_binds_local2)
+ /* If we have both definitions and they are different, we know they
+ will be different even in units they binds to. */
+ || (binds_local1 && binds_local2))
+ && rs1 != rs2)
+ {
+ /* We make use of the fact that one symbol is not alias of the other
+ and that the definition is non-interposable. */
+ refuse_visibility_changes = true;
+ s2->refuse_visibility_changes = true;
+ rs1->refuse_visibility_changes = true;
+ rs2->refuse_visibility_changes = true;
+ return 0;
+ }
+
+ /* TODO: Alias oracle basically assume that addresses of global variables
+ are different unless they are declared as alias of one to another.
+ We probably should be consistent and use this fact here, too, and update
+ alias oracle to use this predicate. */
+
+ return 2;
+}