decl.c (gnat_to_gnu_entity): Minor tweak.
[gcc.git] / gcc / symtab.c
index 9590fc83dd2c320501e634361a9ddd4b658c386c..156fa3d9f283ea3aeda57494603a278844253809 100644 (file)
@@ -1,5 +1,5 @@
 /* Symbol table.
-   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Copyright (C) 2012-2015 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -23,11 +23,25 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "print-tree.h"
 #include "varasm.h"
+#include "hashtab.h"
+#include "hard-reg-set.h"
+#include "input.h"
 #include "function.h"
 #include "emit-rtl.h"
+#include "predict.h"
 #include "basic-block.h"
 #include "tree-ssa-alias.h"
 #include "internal-fn.h"
@@ -36,7 +50,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "tree-inline.h"
 #include "langhooks.h"
-#include "hashtab.h"
+#include "hash-map.h"
+#include "plugin-api.h"
+#include "ipa-ref.h"
 #include "cgraph.h"
 #include "diagnostic.h"
 #include "timevar.h"
@@ -45,7 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "calls.h"
 
-static const char *ipa_ref_use_name[] = {"read","write","addr","alias"};
+static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
 
 const char * const ld_plugin_symbol_resolution_names[]=
 {
@@ -83,15 +99,6 @@ symbol_table::decl_assembler_name_hash (const_tree asmname)
 }
 
 
-/* Returns a hash code for P.  */
-
-hashval_t
-symbol_table::hash_node_by_assembler_name (const void *p)
-{
-  const symtab_node *n = (const symtab_node *) p;
-  return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->decl));
-}
-
 /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL.  */
 
 bool
@@ -150,14 +157,6 @@ symbol_table::decl_assembler_name_equal (tree decl, const_tree asmname)
 
 /* Returns nonzero if P1 and P2 are equal.  */
 
-int
-symbol_table::eq_assembler_name (const void *p1, const void *p2)
-{
-  const symtab_node *n1 = (const symtab_node *) p1;
-  const_tree name = (const_tree)p2;
-  return (decl_assembler_name_equal (n1->decl, name));
-}
-
 /* Insert NODE to assembler name hash.  */
 
 void
@@ -170,19 +169,23 @@ symbol_table::insert_to_assembler_name_hash (symtab_node *node,
                       && !node->next_sharing_asm_name);
   if (assembler_name_hash)
     {
-      void **aslot;
+      symtab_node **aslot;
       cgraph_node *cnode;
       tree decl = node->decl;
 
       tree name = DECL_ASSEMBLER_NAME (node->decl);
 
-      aslot = htab_find_slot_with_hash (assembler_name_hash, name,
-                                       decl_assembler_name_hash (name),
-                                       INSERT);
+      /* C++ FE can produce decls without associated assembler name and insert
+        them to symtab to hold section or TLS information.  */
+      if (!name)
+       return;
+
+      hashval_t hash = decl_assembler_name_hash (name);
+      aslot = assembler_name_hash->find_slot_with_hash (name, hash, INSERT);
       gcc_assert (*aslot != node);
       node->next_sharing_asm_name = (symtab_node *)*aslot;
       if (*aslot != NULL)
-       ((symtab_node *)*aslot)->previous_sharing_asm_name = node;
+       (*aslot)->previous_sharing_asm_name = node;
       *aslot = node;
 
       /* Update also possible inline clones sharing a decl.  */
@@ -217,13 +220,17 @@ symbol_table::unlink_from_assembler_name_hash (symtab_node *node,
       else
        {
          tree name = DECL_ASSEMBLER_NAME (node->decl);
-          void **slot;
-         slot = htab_find_slot_with_hash (assembler_name_hash, name,
-                                          decl_assembler_name_hash (name),
-                                          NO_INSERT);
+          symtab_node **slot;
+
+         if (!name)
+           return;
+
+         hashval_t hash = decl_assembler_name_hash (name);
+         slot = assembler_name_hash->find_slot_with_hash (name, hash,
+                                                          NO_INSERT);
          gcc_assert (*slot == node);
          if (!node->next_sharing_asm_name)
-           htab_clear_slot (assembler_name_hash, slot);
+           assembler_name_hash->clear_slot (slot);
          else
            *slot = node->next_sharing_asm_name;
        }
@@ -256,9 +263,7 @@ symbol_table::symtab_initialize_asm_name_hash (void)
   symtab_node *node;
   if (!assembler_name_hash)
     {
-      assembler_name_hash =
-       htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name,
-                        NULL);
+      assembler_name_hash = hash_table<asmname_hasher>::create_ggc (10);
       FOR_EACH_SYMBOL (node)
        insert_to_assembler_name_hash (node, false);
     }
@@ -308,34 +313,19 @@ symbol_table::change_decl_assembler_name (tree decl, tree name)
     }
 }
 
-/* Return true when RESOLUTION indicate that linker will use
-   the symbol from non-LTO object files.  */
-
-bool
-resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution)
-{
-  return (resolution == LDPR_PREVAILING_DEF
-         || resolution == LDPR_PREEMPTED_REG
-         || resolution == LDPR_RESOLVED_EXEC
-         || resolution == LDPR_RESOLVED_DYN);
-}
-
 /* Hash sections by their names.  */
 
-static hashval_t
-hash_section_hash_entry (const void *p)
+hashval_t
+section_name_hasher::hash (section_hash_entry *n)
 {
-  const section_hash_entry *n = (const section_hash_entry *) p;
   return htab_hash_string (n->name);
 }
 
 /* Return true if section P1 name equals to P2.  */
 
-static int
-eq_sections (const void *p1, const void *p2)
+bool
+section_name_hasher::equal (section_hash_entry *n1, const char *name)
 {
-  const section_hash_entry *n1 = (const section_hash_entry *) p1;
-  const char *name = (const char *)p2;
   return n1->name == name || !strcmp (n1->name, name);
 }
 
@@ -525,18 +515,18 @@ symtab_node::create_reference (symtab_node *referred_node,
 
   /* IPA_REF_ALIAS is always inserted at the beginning of the list.   */
   if(use_type == IPA_REF_ALIAS)
-  {
-    list2->referring.safe_insert (0, ref);
-    ref->referred_index = 0;
+    {
+      list2->referring.safe_insert (0, ref);
+      ref->referred_index = 0;
 
-    for (unsigned int i = 1; i < list2->referring.length (); i++)
-      list2->referring[i]->referred_index = i;
-  }
+      for (unsigned int i = 1; i < list2->referring.length (); i++)
+       list2->referring[i]->referred_index = i;
+    }
   else
-  {
-    list2->referring.safe_push (ref);
-    ref->referred_index = list2->referring.length () - 1;
-  }
+    {
+      list2->referring.safe_push (ref);
+      ref->referred_index = list2->referring.length () - 1;
+    }
 
   ref->referring = this;
   ref->referred = referred_node;
@@ -741,52 +731,6 @@ symtab_node::dump_referring (FILE *file)
   fprintf (file, "\n");
 }
 
-/* Return true if list contains an alias.  */
-bool
-symtab_node::has_aliases_p (void)
-{
-  ipa_ref *ref = NULL;
-  int i;
-
-  for (i = 0; iterate_referring (i, ref); i++)
-    if (ref->use == IPA_REF_ALIAS)
-      return true;
-  return false;
-}
-
-/* Iterates I-th reference in the list, REF is also set.  */
-
-ipa_ref *
-symtab_node::iterate_reference (unsigned i, ipa_ref *&ref)
-{
-  vec_safe_iterate (ref_list.references, i, &ref);
-
-  return ref;
-}
-
-/* Iterates I-th referring item in the list, REF is also set.  */
-
-ipa_ref *
-symtab_node::iterate_referring (unsigned i, ipa_ref *&ref)
-{
-  ref_list.referring.iterate (i, &ref);
-
-  return ref;
-}
-
-/* Iterates I-th referring alias item in the list, REF is also set.  */
-
-ipa_ref *
-symtab_node::iterate_direct_aliases (unsigned i, ipa_ref *&ref)
-{
-  ref_list.referring.iterate (i, &ref);
-
-  if (ref && ref->use != IPA_REF_ALIAS)
-    return NULL;
-
-  return ref;
-}
-
 static const char * const symtab_type_names[] = {"symbol", "function", "variable"};
 
 /* Dump base fields of symtab nodes to F.  Not to be used directly.  */
@@ -831,6 +775,8 @@ symtab_node::dump_base (FILE *f)
     fprintf (f, " forced_by_abi");
   if (externally_visible)
     fprintf (f, " externally_visible");
+  if (no_reorder)
+    fprintf (f, " no_reorder");
   if (resolution != LDPR_UNKNOWN)
     fprintf (f, " %s",
             ld_plugin_symbol_resolution_names[(int)resolution]);
@@ -934,16 +880,16 @@ symtab_node *
 symtab_node::get_for_asmname (const_tree asmname)
 {
   symtab_node *node;
-  void **slot;
 
   symtab->symtab_initialize_asm_name_hash ();
-  slot = htab_find_slot_with_hash (symtab->assembler_name_hash, asmname,
-                                  symtab->decl_assembler_name_hash (asmname),
-                                  NO_INSERT);
+  hashval_t hash = symtab->decl_assembler_name_hash (asmname);
+  symtab_node **slot
+    = symtab->assembler_name_hash->find_slot_with_hash (asmname, hash,
+                                                       NO_INSERT);
 
   if (slot)
     {
-      node = (symtab_node *) *slot;
+      node = *slot;
       return node;
     }
   return NULL;
@@ -1032,6 +978,11 @@ symtab_node::verify_base (void)
       error ("double linked list of assembler names corrupted");
       error_found = true;
     }
+  if (body_removed && definition)
+    {
+      error ("node has body_removed but is definition");
+      error_found = true;
+    }
   if (analyzed && !definition)
     {
       error ("node is analyzed byt it is not a definition");
@@ -1066,11 +1017,6 @@ symtab_node::verify_base (void)
          error ("same_comdat_group list across different groups");
          error_found = true;
        }
-      if (!n->definition)
-       {
-         error ("Node has same_comdat_group but it is not a definition");
-         error_found = true;
-       }
       if (n->type != type)
        {
          error ("mixing different types of symbol in same comdat groups is not supported");
@@ -1114,7 +1060,8 @@ symtab_node::verify_base (void)
       error_found = true;
     }
   if (get_section () && get_comdat_group ()
-      && !implicit_section)
+      && !implicit_section
+      && !lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
     {
       error ("Both section and comdat group is set");
       error_found = true;
@@ -1183,42 +1130,25 @@ symtab_node::verify_symtab_nodes (void)
                                                  &existed);
          if (!existed)
            *entry = node;
-         else
-           for (s = (*entry)->same_comdat_group; s != NULL && s != node; s = s->same_comdat_group)
+         else if (!DECL_EXTERNAL (node->decl))
+           {
+             for (s = (*entry)->same_comdat_group;
+                  s != NULL && s != node && s != *entry;
+                  s = s->same_comdat_group)
+               ;
              if (!s || s == *entry)
                {
-                 error ("Two symbols with same comdat_group are not linked by the same_comdat_group list.");
+                 error ("Two symbols with same comdat_group are not linked by "
+                        "the same_comdat_group list.");
                  (*entry)->debug ();
                  node->debug ();
                  internal_error ("symtab_node::verify failed");
                }
+           }
        }
     }
 }
 
-/* Return true when NODE is known to be used from other (non-LTO)
-   object file. Known only when doing LTO via linker plugin.  */
-
-bool
-symtab_node::used_from_object_file_p_worker (symtab_node *node)
-{
-  if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))
-    return false;
-  if (resolution_used_from_other_file_p (node->resolution))
-    return true;
-  return false;
-}
-
-
-/* Return true when symtab_node is known to be used from other (non-LTO)
-   object file. Known only when doing LTO via linker plugin.  */
-
-bool
-symtab_node::used_from_object_file_p (void)
-{
-  return symtab_node::used_from_object_file_p_worker (this);
-}
-
 /* Make DECL local.  FIXME: We shouldn't need to mess with rtl this early,
    but other code such as notice_global_symbol generates rtl.  */
 
@@ -1232,7 +1162,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;
@@ -1241,6 +1175,7 @@ symtab_node::make_decl_local (void)
   DECL_VISIBILITY_SPECIFIED (decl) = 0;
   DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
   TREE_PUBLIC (decl) = 0;
+  DECL_DLLIMPORT_P (decl) = 0;
   if (!DECL_RTL_SET_P (decl))
     return;
 
@@ -1260,20 +1195,13 @@ symtab_node::make_decl_local (void)
 
 /* Walk the alias chain to return the symbol NODE is alias of.
    If NODE is not an alias, return NODE.
-   When AVAILABILITY is non-NULL, get minimal availability in the chain.  */
+   Assumes NODE is known to be alias.  */
 
 symtab_node *
-symtab_node::ultimate_alias_target (enum availability *availability)
+symtab_node::ultimate_alias_target_1 (enum availability *availability)
 {
   bool weakref_p = false;
 
-  if (!alias)
-    {
-      if (availability)
-       *availability = get_availability ();
-      return this;
-    }
-
   /* To determine visibility of the target, we follow ELF semantic of aliases.
      Here alias is an alternative assembler name of a given definition. Its
      availability prevails the availability of its target (i.e. static alias of
@@ -1380,7 +1308,7 @@ void
 symtab_node::set_section_for_node (const char *section)
 {
   const char *current = get_section ();
-  void **slot;
+  section_hash_entry **slot;
 
   if (current == section
       || (current && section
@@ -1392,11 +1320,11 @@ symtab_node::set_section_for_node (const char *section)
       x_section->ref_count--;
       if (!x_section->ref_count)
        {
-         slot = htab_find_slot_with_hash (symtab->section_hash, x_section->name,
-                                          htab_hash_string (x_section->name),
-                                          INSERT);
+         hashval_t hash = htab_hash_string (x_section->name);
+         slot = symtab->section_hash->find_slot_with_hash (x_section->name,
+                                                           hash, INSERT);
          ggc_free (x_section);
-         htab_clear_slot (symtab->section_hash, slot);
+         symtab->section_hash->clear_slot (slot);
        }
       x_section = NULL;
     }
@@ -1406,11 +1334,10 @@ symtab_node::set_section_for_node (const char *section)
       return;
     }
   if (!symtab->section_hash)
-    symtab->section_hash = htab_create_ggc (10, hash_section_hash_entry,
-                                   eq_sections, NULL);
-  slot = htab_find_slot_with_hash (symtab->section_hash, section,
-                                  htab_hash_string (section),
-                                  INSERT);
+    symtab->section_hash = hash_table<section_name_hasher>::create_ggc (10);
+  slot = symtab->section_hash->find_slot_with_hash (section,
+                                                   htab_hash_string (section),
+                                                   INSERT);
   if (*slot)
     x_section = (section_hash_entry *)*slot;
   else
@@ -1454,16 +1381,6 @@ symtab_node::get_init_priority ()
   return h ? h->init : DEFAULT_INIT_PRIORITY;
 }
 
-/* Return availability of NODE.  */
-enum availability symtab_node::get_availability (void)
-{
-  if (is_a <cgraph_node *> (this))
-    return dyn_cast <cgraph_node *> (this)->get_availability ();
-  else
-    return dyn_cast <varpool_node *> (this)->get_availability ();;
-}
-
-
 /* Return the finalization priority.  */
 
 priority_type
@@ -1606,34 +1523,20 @@ 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;
-  return true;
-}
-
-/* Call calback on symtab node and aliases associated to this node.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
-   skipped. */
 
-bool
-symtab_node::call_for_symbol_and_aliases (bool (*callback) (symtab_node *,
-                                                         void *),
-                                       void *data, bool include_overwritable)
-{
-  int i;
+  /* All non-weakref aliases of THIS are now in fact aliases of TARGET.  */
   ipa_ref *ref;
-
-  if (callback (this, data))
-    return true;
-  for (i = 0; iterate_referring (i, ref); i++)
-    if (ref->use == IPA_REF_ALIAS)
-      {
-       symtab_node *alias = ref->referring;
-       if (include_overwritable
-           || alias->get_availability () > AVAIL_INTERPOSABLE)
-         if (alias->call_for_symbol_and_aliases (callback, data,
-                                               include_overwritable))
-           return true;
-      }
-  return false;
+  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;
 }
 
 /* Worker searching noninterposable alias.  */
@@ -1655,7 +1558,6 @@ symtab_node::noninterposable_alias (symtab_node *node, void *data)
                 != flags_from_decl_or_type (fn->decl))
          || DECL_ATTRIBUTES (node->decl) != DECL_ATTRIBUTES (fn->decl))
        return false;
-
       *(symtab_node **)data = node;
       return true;
     }
@@ -1687,6 +1589,7 @@ symtab_node::noninterposable_alias (void)
 
   /* Otherwise create a new one.  */
   new_decl = copy_node (node->decl);
+  DECL_DLLIMPORT_P (new_decl) = 0;
   DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias");
   if (TREE_CODE (new_decl) == FUNCTION_DECL)
     DECL_STRUCT_FUNCTION (new_decl) = NULL;
@@ -1764,7 +1667,7 @@ symtab_node::get_partitioning_class (void)
      This include external delcarations.   */
   cgraph_node *cnode = dyn_cast <cgraph_node *> (this);
 
-  if (DECL_ABSTRACT (decl))
+  if (DECL_ABSTRACT_P (decl))
     return SYMBOL_EXTERNAL;
 
   if (cnode && cnode->global.inlined_to)
@@ -1780,18 +1683,22 @@ symtab_node::get_partitioning_class (void)
 
   if (varpool_node *vnode = dyn_cast <varpool_node *> (this))
     {
+      if (alias && definition && !ultimate_alias_target ()->definition)
+       return SYMBOL_EXTERNAL;
       /* Constant pool references use local symbol names that can not
          be promoted global.  We should never put into a constant pool
          objects that can not be duplicated across partitions.  */
       if (DECL_IN_CONSTANT_POOL (decl))
        return SYMBOL_DUPLICATE;
+      if (DECL_HARD_REGISTER (decl))
+       return SYMBOL_DUPLICATE;
       gcc_checking_assert (vnode->definition);
     }
   /* Functions that are cloned may stay in callgraph even if they are unused.
      Handle them as external; compute_ltrans_boundary take care to make
      proper things to happen (i.e. to make them appear in the boundary but
      with body streamed, so clone can me materialized).  */
-  else if (!dyn_cast <cgraph_node *> (this)->definition)
+  else if (!dyn_cast <cgraph_node *> (this)->function_symbol ()->definition)
     return SYMBOL_EXTERNAL;
 
   /* Linker discardable symbols are duplicated to every use unless they are
@@ -1873,3 +1780,242 @@ 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;
+}
+
+/* Worker for call_for_symbol_and_aliases.  */
+
+bool
+symtab_node::call_for_symbol_and_aliases_1 (bool (*callback) (symtab_node *,
+                                                             void *),
+                                           void *data,
+                                           bool include_overwritable)
+{
+  ipa_ref *ref;
+  FOR_EACH_ALIAS (this, ref)
+    {
+      symtab_node *alias = ref->referring;
+      if (include_overwritable
+         || alias->get_availability () > AVAIL_INTERPOSABLE)
+       if (alias->call_for_symbol_and_aliases (callback, data,
+                                             include_overwritable))
+         return true;
+    }
+  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);
+}
+
+/* Return ture if symbol's alignment may be increased.  */
+
+bool
+symtab_node::can_increase_alignment_p (void)
+{
+  symtab_node *target = ultimate_alias_target ();
+
+  /* For now support only variables.  */
+  if (TREE_CODE (decl) != VAR_DECL)
+    return false;
+
+  /* With -fno-toplevel-reorder we may have already output the constant.  */
+  if (TREE_ASM_WRITTEN (target->decl))
+    return false;
+
+  /* If target is already placed in an anchor, we can not touch its
+     alignment.  */
+  if (DECL_RTL_SET_P (target->decl)
+      && MEM_P (DECL_RTL (target->decl))
+      && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (DECL_RTL (target->decl), 0)))
+    return false;
+
+  /* Constant pool entries may be shared.  */
+  if (DECL_IN_CONSTANT_POOL (target->decl))
+    return false;
+
+  /* We cannot change alignment of symbols that may bind to symbols
+     in other translation unit that may contain a definition with lower
+     alignment.  */
+  if (!decl_binds_to_current_def_p (decl))
+    return false;
+
+  /* When compiling partition, be sure the symbol is not output by other
+     partition.  */
+  if (flag_ltrans
+      && (target->in_other_partition
+         || target->get_partitioning_class () == SYMBOL_DUPLICATE))
+    return false;
+
+  /* Do not override the alignment as specified by the ABI when the used
+     attribute is set.  */
+  if (DECL_PRESERVE_P (decl) || DECL_PRESERVE_P (target->decl))
+    return false;
+
+  /* Do not override explicit alignment set by the user when an explicit
+     section name is also used.  This is a common idiom used by many
+     software projects.  */
+  if (DECL_SECTION_NAME (target->decl) != NULL && !target->implicit_section)
+    return false;
+
+  return true;
+}
+
+/* Worker for symtab_node::increase_alignment.  */
+
+static bool
+increase_alignment_1 (symtab_node *n, void *v)
+{
+  unsigned int align = (size_t)v;
+  if (DECL_ALIGN (n->decl) < align
+      && n->can_increase_alignment_p ())
+    {
+      DECL_ALIGN (n->decl) = align;
+      DECL_USER_ALIGN (n->decl) = 1;
+    }
+  return false;
+}
+
+/* Increase alignment of THIS to ALIGN.  */
+
+void
+symtab_node::increase_alignment (unsigned int align)
+{
+  gcc_assert (can_increase_alignment_p () && align < MAX_OFILE_ALIGNMENT);
+  ultimate_alias_target()->call_for_symbol_and_aliases (increase_alignment_1,
+                                                       (void *)(size_t) align,
+                                                       true);
+  gcc_assert (DECL_ALIGN (decl) >= align);
+}
+
+/* Helper for symtab_node::definition_alignment.  */
+
+static bool
+get_alignment_1 (symtab_node *n, void *v)
+{
+  *((unsigned int *)v) = MAX (*((unsigned int *)v), DECL_ALIGN (n->decl));
+  return false;
+}
+
+/* Return desired alignment of the definition.  This is NOT alignment useful
+   to access THIS, because THIS may be interposable and DECL_ALIGN should
+   be used instead.  It however must be guaranteed when output definition
+   of THIS.  */
+
+unsigned int
+symtab_node::definition_alignment ()
+{
+  unsigned int align = 0;
+  gcc_assert (!alias);
+  call_for_symbol_and_aliases (get_alignment_1, &align, true);
+  return align;
+}