vec: add exact argument for various grow functions.
[gcc.git] / gcc / ipa-icf.c
index a52448b401463789bda451726313672153bbd673..d2b4e78138926804e24b5e5ef0b59eefd56938c4 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural Identical Code Folding pass
-   Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Copyright (C) 2014-2020 Free Software Foundation, Inc.
 
    Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz>
 
@@ -53,50 +53,37 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "config.h"
 #include "system.h"
-#include <list>
 #include "coretypes.h"
-#include "alias.h"
 #include "backend.h"
+#include "target.h"
+#include "rtl.h"
 #include "tree.h"
 #include "gimple.h"
-#include "rtl.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
 #include "ssa.h"
-#include "options.h"
+#include "cgraph.h"
+#include "coverage.h"
+#include "gimple-pretty-print.h"
+#include "data-streamer.h"
 #include "fold-const.h"
-#include "internal-fn.h"
-#include "flags.h"
-#include "insn-config.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
 #include "calls.h"
-#include "emit-rtl.h"
 #include "varasm.h"
-#include "stmt.h"
-#include "expr.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
-#include "tree-dfa.h"
-#include "tree-pass.h"
-#include "gimple-pretty-print.h"
-#include "cgraph.h"
-#include "alloc-pool.h"
 #include "symbol-summary.h"
 #include "ipa-prop.h"
-#include "ipa-inline.h"
-#include "cfgloop.h"
+#include "ipa-fnsummary.h"
 #include "except.h"
-#include "coverage.h"
 #include "attribs.h"
 #include "print-tree.h"
-#include "target.h"
-#include "lto-streamer.h"
-#include "data-streamer.h"
 #include "ipa-utils.h"
 #include "ipa-icf-gimple.h"
+#include "fibonacci_heap.h"
 #include "ipa-icf.h"
 #include "stor-layout.h"
 #include "dbgcnt.h"
+#include "tree-vector-builder.h"
 
 using namespace ipa_icf_gimple;
 
@@ -145,27 +132,21 @@ symbol_compare_collection::symbol_compare_collection (symtab_node *node)
 
 /* Constructor for key value pair, where _ITEM is key and _INDEX is a target.  */
 
-sem_usage_pair::sem_usage_pair (sem_item *_item, unsigned int _index):
-  item (_item), index (_index)
+sem_usage_pair::sem_usage_pair (sem_item *_item, unsigned int _index)
+: item (_item), index (_index)
 {
 }
 
-/* Semantic item constructor for a node of _TYPE, where STACK is used
-   for bitmap memory allocation.  */
-
-sem_item::sem_item (sem_item_type _type,
-                   bitmap_obstack *stack): type(_type), hash(0)
+sem_item::sem_item (sem_item_type _type, bitmap_obstack *stack)
+: type (_type), referenced_by_count (0), m_hash (-1), m_hash_set (false)
 {
   setup (stack);
 }
 
-/* Semantic item constructor for a node of _TYPE, where STACK is used
-   for bitmap memory allocation. The item is based on symtab node _NODE
-   with computed _HASH.  */
-
 sem_item::sem_item (sem_item_type _type, symtab_node *_node,
-                   hashval_t _hash, bitmap_obstack *stack): type(_type),
-  node (_node), hash (_hash)
+                   bitmap_obstack *stack)
+: type (_type), node (_node), referenced_by_count (0), m_hash (-1),
+  m_hash_set (false)
 {
   decl = node->decl;
   setup (stack);
@@ -174,13 +155,18 @@ sem_item::sem_item (sem_item_type _type, symtab_node *_node,
 /* Add reference to a semantic TARGET.  */
 
 void
-sem_item::add_reference (sem_item *target)
+sem_item::add_reference (ref_map *refs,
+                        sem_item *target)
 {
-  refs.safe_push (target);
-  unsigned index = refs.length ();
-  target->usages.safe_push (new sem_usage_pair(this, index));
+  unsigned index = reference_count++;
+  bool existed;
+
+  vec<sem_item *> &v
+    = refs->get_or_insert (new sem_usage_pair (target, index), &existed);
+  v.safe_push (this);
   bitmap_set_bit (target->usage_index_bitmap, index);
   refs_set.add (target->node);
+  ++target->referenced_by_count;
 }
 
 /* Initialize internal data structures. Bitmap STACK is used for
@@ -191,20 +177,14 @@ sem_item::setup (bitmap_obstack *stack)
 {
   gcc_checking_assert (node);
 
-  refs.create (0);
+  reference_count = 0;
   tree_refs.create (0);
-  usages.create (0);
   usage_index_bitmap = BITMAP_ALLOC (stack);
 }
 
 sem_item::~sem_item ()
 {
-  for (unsigned i = 0; i < usages.length (); i++)
-    delete usages[i];
-
-  refs.release ();
   tree_refs.release ();
-  usages.release ();
 
   BITMAP_FREE (usage_index_bitmap);
 }
@@ -216,16 +196,9 @@ sem_item::dump (void)
 {
   if (dump_file)
     {
-      fprintf (dump_file, "[%s] %s (%u) (tree:%p)\n", type == FUNC ? "func" : "var",
-              node->name(), node->order, (void *) node->decl);
+      fprintf (dump_file, "[%s] %s (tree:%p)\n", type == FUNC ? "func" : "var",
+              node->dump_name (), (void *) node->decl);
       fprintf (dump_file, "  hash: %u\n", get_hash ());
-      fprintf (dump_file, "  references: ");
-
-      for (unsigned i = 0; i < refs.length (); i++)
-       fprintf (dump_file, "%s%s ", refs[i]->node->name (),
-                i < refs.length() - 1 ? "," : "");
-
-      fprintf (dump_file, "\n");
     }
 }
 
@@ -241,21 +214,25 @@ sem_item::target_supports_symbol_aliases_p (void)
 #endif
 }
 
+void sem_item::set_hash (hashval_t hash)
+{
+  m_hash = hash;
+  m_hash_set = true;
+}
+
+hash_map<const_tree, hashval_t> sem_item::m_type_hash_cache;
+
 /* Semantic function constructor that uses STACK as bitmap memory stack.  */
 
-sem_function::sem_function (bitmap_obstack *stack): sem_item (FUNC, stack),
-  m_checker (NULL), m_compared_func (NULL)
+sem_function::sem_function (bitmap_obstack *stack)
+: sem_item (FUNC, stack), m_checker (NULL), m_compared_func (NULL)
 {
   bb_sizes.create (0);
   bb_sorted.create (0);
 }
 
-/*  Constructor based on callgraph node _NODE with computed hash _HASH.
-    Bitmap STACK is used for memory allocation.  */
-sem_function::sem_function (cgraph_node *node, hashval_t hash,
-                           bitmap_obstack *stack):
-  sem_item (FUNC, node, hash, stack),
-  m_checker (NULL), m_compared_func (NULL)
+sem_function::sem_function (cgraph_node *node, bitmap_obstack *stack)
+: sem_item (FUNC, node, stack), m_checker (NULL), m_compared_func (NULL)
 {
   bb_sizes.create (0);
   bb_sorted.create (0);
@@ -288,7 +265,7 @@ sem_function::get_bb_hash (const sem_bb *basic_block)
 hashval_t
 sem_function::get_hash (void)
 {
-  if(!hash)
+  if (!m_hash_set)
     {
       inchash::hash hstate;
       hstate.add_int (177454); /* Random number for function type.  */
@@ -303,78 +280,27 @@ sem_function::get_hash (void)
       for (unsigned i = 0; i < bb_sizes.length (); i++)
        hstate.add_int (bb_sizes[i]);
 
-
       /* Add common features of declaration itself.  */
       if (DECL_FUNCTION_SPECIFIC_TARGET (decl))
-        hstate.add_wide_int
+        hstate.add_hwi
         (cl_target_option_hash
           (TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (decl))));
       if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))
+       hstate.add_hwi
         (cl_optimization_hash
           (TREE_OPTIMIZATION (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))));
       hstate.add_flag (DECL_CXX_CONSTRUCTOR_P (decl));
       hstate.add_flag (DECL_CXX_DESTRUCTOR_P (decl));
 
-      hash = hstate.end ();
-    }
-
-  return hash;
-}
-
-/* Return ture if A1 and A2 represent equivalent function attribute lists.
-   Based on comp_type_attributes.  */
-
-bool
-sem_item::compare_attributes (const_tree a1, const_tree a2)
-{
-  const_tree a;
-  if (a1 == a2)
-    return true;
-  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
-    {
-      const struct attribute_spec *as;
-      const_tree attr;
-
-      as = lookup_attribute_spec (get_attribute_name (a));
-      /* TODO: We can introduce as->affects_decl_identity
-        and as->affects_decl_reference_identity if attribute mismatch
-        gets a common reason to give up on merging.  It may not be worth
-        the effort.
-        For example returns_nonnull affects only references, while
-        optimize attribute can be ignored because it is already lowered
-        into flags representation and compared separately.  */
-      if (!as)
-        continue;
-
-      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
-      if (!attr || !attribute_value_equal (a, attr))
-        break;
+      set_hash (hstate.end ());
     }
-  if (!a)
-    {
-      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
-       {
-         const struct attribute_spec *as;
 
-         as = lookup_attribute_spec (get_attribute_name (a));
-         if (!as)
-           continue;
-
-         if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
-           break;
-         /* We don't need to compare trees again, as we did this
-            already in first loop.  */
-       }
-      if (!a)
-        return true;
-    }
-  /* TODO: As in comp_type_attributes we may want to introduce target hook.  */
-  return false;
+  return m_hash;
 }
 
 /* Compare properties of symbols N1 and N2 that does not affect semantics of
    symbol itself but affects semantics of its references from USED_BY (which
-   may be NULL if it is unknown).  If comparsion is false, symbols
+   may be NULL if it is unknown).  If comparison is false, symbols
    can still be merged but any symbols referring them can't.
 
    If ADDRESS is true, do extra checking needed for IPA_REF_ADDR.
@@ -418,9 +344,13 @@ sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
            return return_false_with_msg ("inline attributes are different");
        }
 
-      if (DECL_IS_OPERATOR_NEW (n1->decl)
-         != DECL_IS_OPERATOR_NEW (n2->decl))
+      if (DECL_IS_OPERATOR_NEW_P (n1->decl)
+         != DECL_IS_OPERATOR_NEW_P (n2->decl))
        return return_false_with_msg ("operator new flags are different");
+
+      if (DECL_IS_REPLACEABLE_OPERATOR (n1->decl)
+         != DECL_IS_REPLACEABLE_OPERATOR (n2->decl))
+       return return_false_with_msg ("replaceable operator flags are different");
     }
 
   /* Merging two definitions with a reference to equivalent vtables, but
@@ -435,7 +365,7 @@ sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
          && (!used_by || !is_a <cgraph_node *> (used_by) || address
              || opt_for_fn (used_by->decl, flag_devirtualize)))
        return return_false_with_msg
-                ("references to virtual tables can not be merged");
+                ("references to virtual tables cannot be merged");
 
       if (address && DECL_ALIGN (n1->decl) != DECL_ALIGN (n2->decl))
        return return_false_with_msg ("alignment mismatch");
@@ -445,8 +375,8 @@ sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
         variables just compare attributes for references - the codegen
         for constructors is affected only by those attributes that we lower
         to explicit representation (such as DECL_ALIGN or DECL_SECTION).  */
-      if (!compare_attributes (DECL_ATTRIBUTES (n1->decl),
-                              DECL_ATTRIBUTES (n2->decl)))
+      if (!attribute_list_equal (DECL_ATTRIBUTES (n1->decl),
+                                DECL_ATTRIBUTES (n2->decl)))
        return return_false_with_msg ("different var decl attributes");
       if (comp_type_attributes (TREE_TYPE (n1->decl),
                                TREE_TYPE (n2->decl)) != 1)
@@ -483,7 +413,7 @@ sem_item::hash_referenced_symbol_properties (symtab_node *ref,
          hstate.add_flag (DECL_DISREGARD_INLINE_LIMITS (ref->decl));
          hstate.add_flag (DECL_DECLARED_INLINE_P (ref->decl));
        }
-      hstate.add_flag (DECL_IS_OPERATOR_NEW (ref->decl));
+      hstate.add_flag (DECL_IS_OPERATOR_NEW_P (ref->decl));
     }
   else if (is_a <varpool_node *> (ref))
     {
@@ -522,8 +452,8 @@ sem_item::compare_symbol_references (
   n1 = n1->ultimate_alias_target (&avail1);
   n2 = n2->ultimate_alias_target (&avail2);
 
-  if (avail1 >= AVAIL_INTERPOSABLE && ignored_nodes.get (n1)
-      && avail2 >= AVAIL_INTERPOSABLE && ignored_nodes.get (n2))
+  if (avail1 > AVAIL_INTERPOSABLE && ignored_nodes.get (n1)
+      && avail2 > AVAIL_INTERPOSABLE && ignored_nodes.get (n2))
     return true;
 
   return return_false_with_msg ("different references");
@@ -554,13 +484,12 @@ bool
 sem_function::param_used_p (unsigned int i)
 {
   if (ipa_node_params_sum == NULL)
-    return false;
+    return true;
 
-  struct ipa_node_params *parms_info = IPA_NODE_REF (get_node ());
+  class ipa_node_params *parms_info = IPA_NODE_REF (get_node ());
 
-  if (parms_info->descriptors.is_empty ()
-      || parms_info->descriptors.length () <= i)
-     return true;
+  if (!parms_info || vec_safe_length (parms_info->descriptors) <= i)
+    return true;
 
   return ipa_is_param_used (IPA_NODE_REF (get_node ()), i);
 }
@@ -610,13 +539,12 @@ sem_function::equals_wpa (sem_item *item,
         return return_false_with_msg ("thunk fixed_offset mismatch");
       if (cnode->thunk.virtual_value != cnode2->thunk.virtual_value)
         return return_false_with_msg ("thunk virtual_value mismatch");
+      if (cnode->thunk.indirect_offset != cnode2->thunk.indirect_offset)
+        return return_false_with_msg ("thunk indirect_offset mismatch");
       if (cnode->thunk.this_adjusting != cnode2->thunk.this_adjusting)
         return return_false_with_msg ("thunk this_adjusting mismatch");
       if (cnode->thunk.virtual_offset_p != cnode2->thunk.virtual_offset_p)
         return return_false_with_msg ("thunk virtual_offset_p mismatch");
-      if (cnode->thunk.add_pointer_bounds_args
-         != cnode2->thunk.add_pointer_bounds_args)
-        return return_false_with_msg ("thunk add_pointer_bounds_args mismatch");
     }
 
   /* Compare special function DECL attributes.  */
@@ -626,7 +554,7 @@ sem_function::equals_wpa (sem_item *item,
 
   if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl)
        != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl))
-    return return_false_with_msg ("intrument function entry exit "
+    return return_false_with_msg ("instrument function entry exit "
                                  "attributes are different");
 
   if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
@@ -652,7 +580,7 @@ sem_function::equals_wpa (sem_item *item,
       && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
     {
       if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE)
-        return return_false_with_msg ("DECL_CXX_CONSTURCTOR type mismatch");
+        return return_false_with_msg ("DECL_CXX_CONSTRUCTOR type mismatch");
       else if (!func_checker::compatible_polymorphic_types_p
                 (TYPE_METHOD_BASETYPE (TREE_TYPE (decl)),
                  TYPE_METHOD_BASETYPE (TREE_TYPE (item->decl)), false))
@@ -677,7 +605,7 @@ sem_function::equals_wpa (sem_item *item,
   cl_optimization *opt1 = opts_for_fn (decl);
   cl_optimization *opt2 = opts_for_fn (item->decl);
 
-  if (opt1 != opt2 && memcmp (opt1, opt2, sizeof(cl_optimization)))
+  if (opt1 != opt2 && !cl_optimization_option_eq (opt1, opt2))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
@@ -731,8 +659,8 @@ sem_function::equals_wpa (sem_item *item,
   if (comp_type_attributes (TREE_TYPE (decl),
                            TREE_TYPE (item->decl)) != 1)
     return return_false_with_msg ("different type attributes");
-  if (!compare_attributes (DECL_ATTRIBUTES (decl),
-                          DECL_ATTRIBUTES (item->decl)))
+  if (!attribute_list_equal (DECL_ATTRIBUTES (decl),
+                            DECL_ATTRIBUTES (item->decl)))
     return return_false_with_msg ("different decl attributes");
 
   /* The type of THIS pointer type memory location for
@@ -802,7 +730,7 @@ sem_function::equals_wpa (sem_item *item,
 }
 
 /* Update hash by address sensitive references. We iterate over all
-   sensitive references (address_matters_p) and we hash ultime alias
+   sensitive references (address_matters_p) and we hash ultimate alias
    target of these nodes, which can improve a semantic item hash.
 
    Also hash in referenced symbols properties.  This can be done at any time
@@ -814,7 +742,7 @@ sem_item::update_hash_by_addr_refs (hash_map <symtab_node *,
                                    sem_item *> &m_symtab_node_map)
 {
   ipa_ref* ref;
-  inchash::hash hstate (hash);
+  inchash::hash hstate (get_hash ());
 
   for (unsigned i = 0; node->iterate_reference (i, ref); i++)
     {
@@ -837,7 +765,7 @@ sem_item::update_hash_by_addr_refs (hash_map <symtab_node *,
        }
     }
 
-  hash = hstate.end ();
+  set_hash (hstate.end ());
 }
 
 /* Update hash by computed local hash values taken from different
@@ -849,13 +777,13 @@ sem_item::update_hash_by_local_refs (hash_map <symtab_node *,
                                     sem_item *> &m_symtab_node_map)
 {
   ipa_ref* ref;
-  inchash::hash state (hash);
+  inchash::hash state (get_hash ());
 
   for (unsigned j = 0; node->iterate_reference (j, ref); j++)
     {
       sem_item **result = m_symtab_node_map.get (ref->referring);
       if (result)
-       state.merge_hash ((*result)->hash);
+       state.merge_hash ((*result)->get_hash ());
     }
 
   if (type == FUNC)
@@ -865,7 +793,7 @@ sem_item::update_hash_by_local_refs (hash_map <symtab_node *,
        {
          sem_item **result = m_symtab_node_map.get (e->caller);
          if (result)
-           state.merge_hash ((*result)->hash);
+           state.merge_hash ((*result)->get_hash ());
        }
     }
 
@@ -889,13 +817,9 @@ sem_function::equals (sem_item *item,
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file,
-            "Equals called for:%s:%s (%u:%u) (%s:%s) with result: %s\n\n",
-            xstrdup_for_dump (node->name()),
-            xstrdup_for_dump (item->node->name ()),
-            node->order,
-            item->node->order,
-            xstrdup_for_dump (node->asm_name ()),
-            xstrdup_for_dump (item->node->asm_name ()),
+            "Equals called for: %s:%s with result: %s\n\n",
+            node->dump_name (),
+            item->node->dump_name (),
             eq ? "true" : "false");
 
   return eq;
@@ -925,7 +849,6 @@ sem_function::equals_private (sem_item *item)
     return return_false ();
 
   m_checker = new func_checker (decl, m_compared_func->decl,
-                               compare_polymorphic_p (),
                                false,
                                &refs_set,
                                &m_compared_func->refs_set);
@@ -960,9 +883,7 @@ sem_function::equals_private (sem_item *item)
   /* Checking all basic blocks.  */
   for (unsigned i = 0; i < bb_sorted.length (); ++i)
     if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
-      return return_false();
-
-  dump_message ("All BBs are equal\n");
+      return return_false ();
 
   auto_vec <int> bb_dict;
 
@@ -1008,7 +929,7 @@ sem_function::equals_private (sem_item *item)
 static bool
 set_local (cgraph_node *node, void *data)
 {
-  node->local.local = data != NULL;
+  node->local = data != NULL;
   return false;
 }
 
@@ -1106,20 +1027,23 @@ sem_function::merge (sem_item *alias_item)
   bool original_address_matters = original->address_matters_p ();
   bool alias_address_matters = alias->address_matters_p ();
 
+  AUTO_DUMP_SCOPE ("merge",
+                  dump_user_location_t::from_function_decl (decl));
+
   if (DECL_EXTERNAL (alias->decl))
     {
-      if (dump_file)
-       fprintf (dump_file, "Not unifying; alias is external.\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; alias is external.\n");
       return false;
     }
 
   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");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; DECL_NO_INLINE_WARNING mismatch.\n");
       return false;
     }
 
@@ -1129,10 +1053,20 @@ sem_function::merge (sem_item *alias_item)
        || (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");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; "
+                    "original and alias are in different sections.\n");
+      return false;
+    }
+
+  if (!original->in_same_comdat_group_p (alias)
+      || original->comdat_local_p ())
+    {
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; alias nor wrapper cannot be created; "
+                    "across comdat group boundary\n");
       return false;
     }
 
@@ -1142,23 +1076,23 @@ sem_function::merge (sem_item *alias_item)
   if (original->can_be_discarded_p ())
     original_discardable = true;
   /* 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
+     original's definition is not going to be used.  In this case we cannot
      create alias to original.  */
   if (node->resolution != LDPR_UNKNOWN
       && !decl_binds_to_current_def_p (node->decl))
     original_discardable = original_discarded = true;
 
   /* Creating a symtab alias is the optimal way to merge.
-     It however can not be used in the following cases:
+     It however cannot 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
+       it is an external functions where we cannot create an alias
        (ORIGINAL_DISCARDABLE)
      3) if target do not support symbol aliases.
      4) original and alias lie in different comdat groups.
 
-     If we can not produce alias, we will turn ALIAS into WRAPPER of ORIGINAL
+     If we cannot 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
@@ -1177,62 +1111,64 @@ sem_function::merge (sem_item *alias_item)
       if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias,
                                                           alias->address_taken))
         {
-         if (dump_file)
-           fprintf (dump_file,
-                    "Wrapper cannot be created because referenced symbol "
-                    "properties mismatch\n");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Wrapper cannot be created because referenced symbol "
+                        "properties mismatch\n");
         }
       /* 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
+        another comdat group may make opposite decision and with unfortunate
         linker choices this may close a loop.  */
       else if (DECL_COMDAT_GROUP (original->decl)
               && 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");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Wrapper cannot be created because of COMDAT\n");
        }
-      else if (DECL_STATIC_CHAIN (alias->decl))
+      else if (DECL_STATIC_CHAIN (alias->decl)
+              || DECL_STATIC_CHAIN (original->decl))
         {
-         if (dump_file)
-           fprintf (dump_file,
-                    "Can not create wrapper of nested functions.\n");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Cannot create wrapper of nested function.\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");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "cannot create wrapper of stdarg function.\n");
        }
-      else if (inline_summaries
-              && inline_summaries->get (alias)->self_size <= 2)
+      else if (ipa_fn_summaries
+              && ipa_size_summaries->get (alias) != NULL
+              && ipa_size_summaries->get (alias)->self_size <= 2)
        {
-         if (dump_file)
-           fprintf (dump_file, "Wrapper creation is not "
-                    "profitable (function is too small).\n");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION, "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.  */
+        somewhat special and do not try to turn it into a wrapper that
+        cannot 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");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Wrappers are not created for noinline.\n");
        }
       else
         create_wrapper = true;
 
-      /* We can redirect local calls in the case both alias and orignal
+      /* We can redirect local calls in the case both alias and original
         are not interposable.  */
       redirect_callers
        = alias->get_availability () > AVAIL_INTERPOSABLE
-         && original->get_availability () > AVAIL_INTERPOSABLE
-         && !alias->instrumented_version;
+         && original->get_availability () > AVAIL_INTERPOSABLE;
       /* TODO: We can redirect, but we need to produce alias of ORIGINAL
         with proper properties.  */
       if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias,
@@ -1241,9 +1177,10 @@ sem_function::merge (sem_item *alias_item)
 
       if (!redirect_callers && !create_wrapper)
        {
-         if (dump_file)
-           fprintf (dump_file, "Not unifying; can not redirect callers nor "
-                    "produce wrapper\n\n");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Not unifying; cannot redirect callers nor "
+                        "produce wrapper\n");
          return false;
        }
 
@@ -1251,7 +1188,7 @@ sem_function::merge (sem_item *alias_item)
         If ORIGINAL is interposable, we need to call a local alias.
         Also produce local alias (if possible) as an optimization.
 
-        Local aliases can not be created inside comdat groups because that
+        Local aliases cannot be created inside comdat groups because that
         prevents inlining.  */
       if (!original_discardable && !original->get_comdat_group ())
        {
@@ -1261,28 +1198,29 @@ sem_function::merge (sem_item *alias_item)
              && original->get_availability () > AVAIL_INTERPOSABLE)
            local_original = original;
        }
-      /* If we can not use local alias, fallback to the original
+      /* If we cannot use local alias, fallback to the original
         when possible.  */
       else if (original->get_availability () > AVAIL_INTERPOSABLE)
        local_original = original;
 
-      /* If original is COMDAT local, we can not really redirect calls outside
+      /* If original is COMDAT local, we cannot really redirect calls outside
         of its comdat group to it.  */
       if (original->comdat_local_p ())
         redirect_callers = false;
       if (!local_original)
        {
-         if (dump_file)
-           fprintf (dump_file, "Not unifying; "
-                    "can not produce local alias.\n\n");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Not unifying; cannot produce local alias.\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");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Not unifying; "
+                        "cannot redirect callers nor produce a wrapper\n");
          return false;
        }
       if (!create_wrapper
@@ -1290,9 +1228,10 @@ sem_function::merge (sem_item *alias_item)
                                                  NULL, true)
          && !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");
+         if (dump_enabled_p ())
+           dump_printf (MSG_MISSED_OPTIMIZATION,
+                        "Not unifying; cannot make wrapper and "
+                        "function has other uses than direct calls\n");
          return false;
        }
     }
@@ -1308,13 +1247,15 @@ sem_function::merge (sem_item *alias_item)
          alias->icf_merged = true;
          local_original->icf_merged = true;
 
-         if (dump_file && nredirected)
-           fprintf (dump_file, "%i local calls have been "
-                    "redirected.\n", nredirected);
+         if (dump_enabled_p ())
+           dump_printf (MSG_NOTE,
+                        "%i local calls have been "
+                        "redirected.\n", nredirected);
        }
 
       /* If all callers was redirected, do not produce wrapper.  */
       if (alias->can_remove_if_no_direct_calls_p ()
+         && !DECL_VIRTUAL_P (alias->decl)
          && !alias->has_aliases_p ())
        {
          create_wrapper = false;
@@ -1328,6 +1269,7 @@ sem_function::merge (sem_item *alias_item)
 
       /* Remove the function's body.  */
       ipa_merge_profiles (original, alias);
+      symtab->call_cgraph_removal_hooks (alias);
       alias->release_body (true);
       alias->reset ();
       /* Notice global symbol possibly produced RTL.  */
@@ -1341,20 +1283,25 @@ sem_function::merge (sem_item *alias_item)
       original->call_for_symbol_thunks_and_aliases
         (set_local, (void *)(size_t) original->local_p (), true);
 
-      if (dump_file)
-       fprintf (dump_file, "Unified; Function alias has been created.\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_OPTIMIZED_LOCATIONS,
+                    "Unified; Function alias has been created.\n");
     }
   if (create_wrapper)
     {
       gcc_assert (!create_alias);
       alias->icf_merged = true;
+      symtab->call_cgraph_removal_hooks (alias);
       local_original->icf_merged = true;
 
-      ipa_merge_profiles (local_original, alias, true);
+      /* FIXME update local_original counts.  */
+      ipa_merge_profiles (original, alias, true);
       alias->create_wrapper (local_original);
+      symtab->call_cgraph_insertion_hooks (alias);
 
-      if (dump_file)
-       fprintf (dump_file, "Unified; Wrapper has been created.\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_OPTIMIZED_LOCATIONS,
+                    "Unified; Wrapper has been created.\n");
     }
 
   /* It's possible that redirection can hit thunks that block
@@ -1362,10 +1309,17 @@ sem_function::merge (sem_item *alias_item)
   gcc_assert (alias->icf_merged || remove || redirect_callers);
   original->icf_merged = true;
 
-  /* 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;
+  /* We use merged flag to track cases where COMDAT function is known to be
+     compatible its callers.  If we merged in non-COMDAT, we need to give up
+     on this optimization.  */
+  if (original->merged_comdat && !alias->merged_comdat)
+    {
+      if (dump_enabled_p ())
+       dump_printf (MSG_NOTE, "Dropping merged_comdat flag.\n");
+      if (local_original)
+        local_original->merged_comdat = false;
+      original->merged_comdat = false;
+    }
 
   if (remove)
     {
@@ -1374,8 +1328,9 @@ sem_function::merge (sem_item *alias_item)
       alias->reset ();
       alias->body_removed = true;
       alias->icf_merged = true;
-      if (dump_file)
-       fprintf (dump_file, "Unified; Function body was removed.\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_OPTIMIZED_LOCATIONS,
+                    "Unified; Function body was removed.\n");
     }
 
   return true;
@@ -1384,8 +1339,9 @@ sem_function::merge (sem_item *alias_item)
 /* Semantic item initialization function.  */
 
 void
-sem_function::init (void)
+sem_function::init (ipa_icf_gimple::func_checker *checker)
 {
+  m_checker = checker;
   if (in_lto_p)
     get_node ()->get_untransformed_body ();
 
@@ -1426,7 +1382,7 @@ sem_function::init (void)
        for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
             gsi_next (&gsi))
          {
-           gimple stmt = gsi_stmt (gsi);
+           gimple *stmt = gsi_stmt (gsi);
 
            if (gimple_code (stmt) != GIMPLE_DEBUG
                && gimple_code (stmt) != GIMPLE_PREDICT)
@@ -1436,6 +1392,7 @@ sem_function::init (void)
              }
          }
 
+       hstate.commit_flag ();
        gcode_hash = hstate.end ();
        bb_sizes.safe_push (nondbg_stmt_count);
 
@@ -1451,172 +1408,20 @@ sem_function::init (void)
     {
       cfg_checksum = 0;
       inchash::hash hstate;
-      hstate.add_wide_int (cnode->thunk.fixed_offset);
-      hstate.add_wide_int (cnode->thunk.virtual_value);
+      hstate.add_hwi (cnode->thunk.fixed_offset);
+      hstate.add_hwi (cnode->thunk.virtual_value);
       hstate.add_flag (cnode->thunk.this_adjusting);
       hstate.add_flag (cnode->thunk.virtual_offset_p);
-      hstate.add_flag (cnode->thunk.add_pointer_bounds_args);
       gcode_hash = hstate.end ();
     }
-}
-
-/* Accumulate to HSTATE a hash of expression EXP.
-   Identical to inchash::add_expr, but guaranteed to be stable across LTO
-   and DECL equality classes.  */
-
-void
-sem_item::add_expr (const_tree exp, inchash::hash &hstate)
-{
-  if (exp == NULL_TREE)
-    {
-      hstate.merge_hash (0);
-      return;
-    }
-
-  /* Handled component can be matched in a cureful way proving equivalence
-     even if they syntactically differ.  Just skip them.  */
-  STRIP_NOPS (exp);
-  while (handled_component_p (exp))
-    exp = TREE_OPERAND (exp, 0);
-
-  enum tree_code code = TREE_CODE (exp);
-  hstate.add_int (code);
-
-  switch (code)
-    {
-    /* Use inchash::add_expr for everything that is LTO stable.  */
-    case VOID_CST:
-    case INTEGER_CST:
-    case REAL_CST:
-    case FIXED_CST:
-    case STRING_CST:
-    case COMPLEX_CST:
-    case VECTOR_CST:
-      inchash::add_expr (exp, hstate);
-      break;
-    case CONSTRUCTOR:
-      {
-       unsigned HOST_WIDE_INT idx;
-       tree value;
-
-       hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
-
-       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
-         if (value)
-           add_expr (value, hstate);
-       break;
-      }
-    case ADDR_EXPR:
-    case FDESC_EXPR:
-      add_expr (get_base_address (TREE_OPERAND (exp, 0)), hstate);
-      break;
-    case SSA_NAME:
-    case VAR_DECL:
-    case CONST_DECL:
-    case PARM_DECL:
-      hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
-      break;
-    case MEM_REF:
-    case POINTER_PLUS_EXPR:
-    case MINUS_EXPR:
-    case RANGE_EXPR:
-      add_expr (TREE_OPERAND (exp, 0), hstate);
-      add_expr (TREE_OPERAND (exp, 1), hstate);
-      break;
-    case PLUS_EXPR:
-      {
-       inchash::hash one, two;
-       add_expr (TREE_OPERAND (exp, 0), one);
-       add_expr (TREE_OPERAND (exp, 1), two);
-       hstate.add_commutative (one, two);
-      }
-      break;
-    CASE_CONVERT:
-      hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
-      return add_expr (TREE_OPERAND (exp, 0), hstate);
-    default:
-      break;
-    }
-}
-
-/* Accumulate to HSTATE a hash of type t.
-   TYpes that may end up being compatible after LTO type merging needs to have
-   the same hash.  */
-
-void
-sem_item::add_type (const_tree type, inchash::hash &hstate)
-{
-  if (type == NULL_TREE)
-    {
-      hstate.merge_hash (0);
-      return;
-    }
-
-  type = TYPE_MAIN_VARIANT (type);
-  if (TYPE_CANONICAL (type))
-    type = TYPE_CANONICAL (type);
-
-  if (!AGGREGATE_TYPE_P (type))
-    hstate.add_int (TYPE_MODE (type));
-
-  if (TREE_CODE (type) == COMPLEX_TYPE)
-    {
-      hstate.add_int (COMPLEX_TYPE);
-      sem_item::add_type (TREE_TYPE (type), hstate);
-    }
-  else if (INTEGRAL_TYPE_P (type))
-    {
-      hstate.add_int (INTEGER_TYPE);
-      hstate.add_flag (TYPE_UNSIGNED (type));
-      hstate.add_int (TYPE_PRECISION (type));
-    }
-  else if (VECTOR_TYPE_P (type))
-    {
-      hstate.add_int (VECTOR_TYPE);
-      hstate.add_int (TYPE_PRECISION (type));
-      sem_item::add_type (TREE_TYPE (type), hstate);
-    }
-  else if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-      hstate.add_int (ARRAY_TYPE);
-      /* Do not hash size, so complete and incomplete types can match.  */
-      sem_item::add_type (TREE_TYPE (type), hstate);
-    }
-  else if (RECORD_OR_UNION_TYPE_P (type))
-    {
-      hashval_t *val = optimizer->m_type_hash_cache.get (type);
-
-      if (!val)
-       {
-         inchash::hash hstate2;
-         unsigned nf;
-         tree f;
-         hashval_t hash;
-
-         hstate2.add_int (RECORD_TYPE);
-         gcc_assert (COMPLETE_TYPE_P (type));
-
-         for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f))
-           if (TREE_CODE (f) == FIELD_DECL)
-             {
-               add_type (TREE_TYPE (f), hstate2);
-               nf++;
-             }
 
-         hstate2.add_int (nf);
-         hash = hstate2.end ();
-         hstate.add_wide_int (hash);
-         optimizer->m_type_hash_cache.put (type, hash);
-       }
-      else
-        hstate.add_wide_int (*val);
-    }
+  m_checker = NULL;
 }
 
 /* Improve accumulated hash for HSTATE based on a gimple statement STMT.  */
 
 void
-sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
+sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
 {
   enum gimple_code code = gimple_code (stmt);
 
@@ -1625,29 +1430,21 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
   switch (code)
     {
     case GIMPLE_SWITCH:
-      add_expr (gimple_switch_index (as_a <gswitch *> (stmt)), hstate);
+      m_checker->hash_operand (gimple_switch_index (as_a <gswitch *> (stmt)),
+                            hstate, 0);
       break;
     case GIMPLE_ASSIGN:
       hstate.add_int (gimple_assign_rhs_code (stmt));
       if (commutative_tree_code (gimple_assign_rhs_code (stmt))
          || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
        {
-         inchash::hash one, two;
-
-         add_expr (gimple_assign_rhs1 (stmt), one);
-         add_type (TREE_TYPE (gimple_assign_rhs1 (stmt)), one);
-         add_expr (gimple_assign_rhs2 (stmt), two);
-         hstate.add_commutative (one, two);
+         m_checker->hash_operand (gimple_assign_rhs1 (stmt), hstate, 0);
+         m_checker->hash_operand (gimple_assign_rhs2 (stmt), hstate, 0);
          if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
-           {
-             add_expr (gimple_assign_rhs3 (stmt), hstate);
-             add_type (TREE_TYPE (gimple_assign_rhs3 (stmt)), hstate);
-           }
-         add_expr (gimple_assign_lhs (stmt), hstate);
-         add_type (TREE_TYPE (gimple_assign_lhs (stmt)), two);
-         break;
+           m_checker->hash_operand (gimple_assign_rhs3 (stmt), hstate, 0);
+         m_checker->hash_operand (gimple_assign_lhs (stmt), hstate, 0);
        }
-      /* ... fall through ... */
+      /* fall through */
     case GIMPLE_CALL:
     case GIMPLE_ASM:
     case GIMPLE_COND:
@@ -1655,11 +1452,12 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
     case GIMPLE_RETURN:
       /* All these statements are equivalent if their operands are.  */
       for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
-       {
-         add_expr (gimple_op (stmt, i), hstate);
-         if (gimple_op (stmt, i))
-           add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
-       }
+       m_checker->hash_operand (gimple_op (stmt, i), hstate, 0);
+      /* Consider nocf_check attribute in hash as it affects code
+        generation.  */
+      if (code == GIMPLE_CALL
+         && flag_cf_protection & CF_BRANCH)
+       hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
     default:
       break;
     }
@@ -1690,7 +1488,8 @@ sem_function::compare_polymorphic_p (void)
    semantic function item.  */
 
 sem_function *
-sem_function::parse (cgraph_node *node, bitmap_obstack *stack)
+sem_function::parse (cgraph_node *node, bitmap_obstack *stack,
+                    func_checker *checker)
 {
   tree fndecl = node->decl;
   function *func = DECL_STRUCT_FUNCTION (fndecl);
@@ -1701,9 +1500,17 @@ sem_function::parse (cgraph_node *node, bitmap_obstack *stack)
   if (lookup_attribute_by_prefix ("omp ", DECL_ATTRIBUTES (node->decl)) != NULL)
     return NULL;
 
-  sem_function *f = new sem_function (node, 0, stack);
+  if (lookup_attribute_by_prefix ("oacc ",
+                                 DECL_ATTRIBUTES (node->decl)) != NULL)
+    return NULL;
+
+  /* PR ipa/70306.  */
+  if (DECL_STATIC_CONSTRUCTOR (node->decl)
+      || DECL_STATIC_DESTRUCTOR (node->decl))
+    return NULL;
 
-  f->init ();
+  sem_function *f = new sem_function (node, stack);
+  f->init (checker);
 
   return f;
 }
@@ -1723,13 +1530,10 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
   gcc_assert (bb1 != NULL);
   gcc_assert (bb2 != NULL);
 
-  si2 = gsi_start_phis (bb2);
-  for (si1 = gsi_start_phis (bb1); !gsi_end_p (si1);
-       gsi_next (&si1))
+  si2 = gsi_start_nonvirtual_phis (bb2);
+  for (si1 = gsi_start_nonvirtual_phis (bb1); !gsi_end_p (si1);
+       gsi_next_nonvirtual_phi (&si1))
     {
-      gsi_next_nonvirtual_phi (&si1);
-      gsi_next_nonvirtual_phi (&si2);
-
       if (gsi_end_p (si1) && gsi_end_p (si2))
        break;
 
@@ -1766,23 +1570,12 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
            return return_false ();
        }
 
-      gsi_next (&si2);
+      gsi_next_nonvirtual_phi (&si2);
     }
 
   return true;
 }
 
-/* Returns true if tree T can be compared as a handled component.  */
-
-bool
-sem_function::icf_handled_component_p (tree t)
-{
-  tree_code tc = TREE_CODE (t);
-
-  return (handled_component_p (t)
-         || tc == ADDR_EXPR || tc == MEM_REF || tc == OBJ_TYPE_REF);
-}
-
 /* Basic blocks dictionary BB_DICT returns true if SOURCE index BB
    corresponds to TARGET.  */
 
@@ -1793,7 +1586,7 @@ sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target)
   target++;
 
   if (bb_dict->length () <= (unsigned)source)
-    bb_dict->safe_grow_cleared (source + 1);
+    bb_dict->safe_grow_cleared (source + 1, true);
 
   if ((*bb_dict)[source] == 0)
     {
@@ -1804,19 +1597,12 @@ sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target)
     return (*bb_dict)[source] == target;
 }
 
-
-/* Semantic variable constructor that uses STACK as bitmap memory stack.  */
-
 sem_variable::sem_variable (bitmap_obstack *stack): sem_item (VAR, stack)
 {
 }
 
-/*  Constructor based on varpool node _NODE with computed hash _HASH.
-    Bitmap STACK is used for memory allocation.  */
-
-sem_variable::sem_variable (varpool_node *node, hashval_t _hash,
-                           bitmap_obstack *stack): sem_item(VAR,
-                                 node, _hash, stack)
+sem_variable::sem_variable (varpool_node *node, bitmap_obstack *stack)
+: sem_item (VAR, node, stack)
 {
   gcc_checking_assert (node);
   gcc_checking_assert (get_node ());
@@ -1898,12 +1684,9 @@ sem_variable::equals (sem_item *item,
                              DECL_INITIAL (item->node->decl));
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file,
-            "Equals called for vars:%s:%s (%u:%u) (%s:%s) with result: %s\n\n",
-            xstrdup_for_dump (node->name()),
-            xstrdup_for_dump (item->node->name ()),
-            node->order, item->node->order,
-            xstrdup_for_dump (node->asm_name ()),
-            xstrdup_for_dump (item->node->asm_name ()), ret ? "true" : "false");
+            "Equals called for vars: %s:%s with result: %s\n\n",
+            node->dump_name (), item->node->dump_name (),
+            ret ? "true" : "false");
 
   return ret;
 }
@@ -1978,8 +1761,8 @@ sem_variable::equals (tree t1, tree t2)
 
        /* Type of the offset on MEM_REF does not matter.  */
        return return_with_debug (sem_variable::equals (x1, x2)
-                                 && wi::to_offset  (y1)
-                                    == wi::to_offset  (y2));
+                                 && known_eq (wi::to_poly_offset (y1),
+                                              wi::to_poly_offset (y2)));
       }
     case ADDR_EXPR:
     case FDESC_EXPR:
@@ -2031,21 +1814,21 @@ sem_variable::equals (tree t1, tree t2)
       /* Real constants are the same only if the same width of type.  */
       if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
         return return_false_with_msg ("REAL_CST precision mismatch");
-      return return_with_debug (REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1),
-                                                      TREE_REAL_CST (t2)));
+      return return_with_debug (real_identical (&TREE_REAL_CST (t1),
+                                               &TREE_REAL_CST (t2)));
     case VECTOR_CST:
       {
-       unsigned i;
+       if (maybe_ne (VECTOR_CST_NELTS (t1), VECTOR_CST_NELTS (t2)))
+         return return_false_with_msg ("VECTOR_CST nelts mismatch");
 
-        if (VECTOR_CST_NELTS (t1) != VECTOR_CST_NELTS (t2))
-          return return_false_with_msg ("VECTOR_CST nelts mismatch");
+       unsigned int count
+         = tree_vector_builder::binary_encoded_nelts (t1, t2);
+       for (unsigned int i = 0; i < count; ++i)
+         if (!sem_variable::equals (VECTOR_CST_ENCODED_ELT (t1, i),
+                                    VECTOR_CST_ENCODED_ELT (t2, i)))
+           return false;
 
-       for (i = 0; i < VECTOR_CST_NELTS (t1); ++i)
-         if (!sem_variable::equals (VECTOR_CST_ELT (t1, i),
-                                    VECTOR_CST_ELT (t2, i)))
-           return 0;
-
-       return 1;
+       return true;
       }
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
@@ -2095,41 +1878,46 @@ sem_variable::equals (tree t1, tree t2)
 /* Parser function that visits a varpool NODE.  */
 
 sem_variable *
-sem_variable::parse (varpool_node *node, bitmap_obstack *stack)
+sem_variable::parse (varpool_node *node, bitmap_obstack *stack,
+                    func_checker *checker)
 {
   if (TREE_THIS_VOLATILE (node->decl) || DECL_HARD_REGISTER (node->decl)
       || node->alias)
     return NULL;
 
-  sem_variable *v = new sem_variable (node, 0, stack);
-
-  v->init ();
+  sem_variable *v = new sem_variable (node, stack);
+  v->init (checker);
 
   return v;
 }
 
-/* References independent hash function.  */
+/* Semantic variable initialization function.  */
 
-hashval_t
-sem_variable::get_hash (void)
+void
+sem_variable::init (ipa_icf_gimple::func_checker *checker)
 {
-  if (hash)
-    return hash;
+  decl = get_node ()->decl;
 
   /* All WPA streamed in symbols should have their hashes computed at compile
      time.  At this point, the constructor may not be in memory at all.
      DECL_INITIAL (decl) would be error_mark_node in that case.  */
-  gcc_assert (!node->lto_file_data);
-  tree ctor = DECL_INITIAL (decl);
-  inchash::hash hstate;
+  if (!m_hash_set)
+    {
+      gcc_assert (!node->lto_file_data);
+      inchash::hash hstate;
+      hstate.add_int (456346417);
+      checker->hash_operand (DECL_INITIAL (decl), hstate, 0);
+      set_hash (hstate.end ());
+    }
+}
 
-  hstate.add_int (456346417);
-  if (DECL_SIZE (decl) && tree_fits_shwi_p (DECL_SIZE (decl)))
-    hstate.add_wide_int (tree_to_shwi (DECL_SIZE (decl)));
-  add_expr (ctor, hstate);
-  hash = hstate.end ();
+/* References independent hash function.  */
 
-  return hash;
+hashval_t
+sem_variable::get_hash (void)
+{
+  gcc_checking_assert (m_hash_set);
+  return m_hash;
 }
 
 /* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
@@ -2140,18 +1928,21 @@ sem_variable::merge (sem_item *alias_item)
 {
   gcc_assert (alias_item->type == VAR);
 
+  AUTO_DUMP_SCOPE ("merge",
+                  dump_user_location_t::from_function_decl (decl));
   if (!sem_item::target_supports_symbol_aliases_p ())
     {
-      if (dump_file)
-       fprintf (dump_file, "Not unifying; "
-                "Symbol aliases are not supported by target\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION, "Not unifying; "
+                    "Symbol aliases are not supported by target\n");
       return false;
     }
 
   if (DECL_EXTERNAL (alias_item->decl))
     {
-      if (dump_file)
-       fprintf (dump_file, "Not unifying; alias is external.\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; alias is external.\n");
       return false;
     }
 
@@ -2161,13 +1952,12 @@ 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.
      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
+     original's definition is not going to be used.  In this case we cannot
      create alias to original.  */
   if (original->can_be_discarded_p ()
       || (node->resolution != LDPR_UNKNOWN
@@ -2184,9 +1974,9 @@ sem_variable::merge (sem_item *alias_item)
   if (DECL_IN_CONSTANT_POOL (alias->decl)
       || DECL_IN_CONSTANT_POOL (original->decl))
     {
-      if (dump_file)
-       fprintf (dump_file,
-                "Not unifying; constant pool variables.\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; constant pool variables.\n");
       return false;
     }
 
@@ -2196,37 +1986,48 @@ sem_variable::merge (sem_item *alias_item)
        || (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");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; "
+                    "original and alias are in different sections.\n");
       return false;
     }
 
-  /* We can not merge if address comparsion metters.  */
-  if (original_address_matters && alias_address_matters
-      && flag_merge_constants < 2)
+  /* We cannot merge if address comparison matters.  */
+  if (alias_address_matters && flag_merge_constants < 2)
     {
-      if (dump_file)
-       fprintf (dump_file,
-                "Not unifying; "
-                "adress of original and alias may be compared.\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; address of original may be compared.\n");
       return false;
     }
+
+  if (DECL_ALIGN (original->decl) < DECL_ALIGN (alias->decl))
+    {
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; "
+                    "original and alias have incompatible alignments\n");
+
+      return false;
+    }
+
   if (DECL_COMDAT_GROUP (original->decl) != DECL_COMDAT_GROUP (alias->decl))
     {
-      if (dump_file)
-       fprintf (dump_file, "Not unifying; alias cannot be created; "
-                "across comdat group boundary\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; alias cannot be created; "
+                    "across comdat group boundary\n");
 
       return false;
     }
 
   if (original_discardable)
     {
-      if (dump_file)
-       fprintf (dump_file, "Not unifying; alias cannot be created; "
-                "target is discardable\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_MISSED_OPTIMIZATION,
+                    "Not unifying; alias cannot be created; "
+                    "target is discardable\n");
 
       return false;
     }
@@ -2240,7 +2041,6 @@ sem_variable::merge (sem_item *alias_item)
       DECL_INITIAL (alias->decl) = NULL;
       ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl,
                                                           NULL, true);
-      alias->need_bounds_init = false;
       alias->remove_all_references ();
       if (TREE_ADDRESSABLE (alias->decl))
         original->call_for_symbol_and_aliases (set_addressable, NULL, true);
@@ -2248,8 +2048,9 @@ sem_variable::merge (sem_item *alias_item)
       varpool_node::create_alias (alias_var->decl, decl);
       alias->resolve_alias (original);
 
-      if (dump_file)
-       fprintf (dump_file, "Unified; Variable alias has been created.\n\n");
+      if (dump_enabled_p ())
+       dump_printf (MSG_OPTIMIZED_LOCATIONS,
+                    "Unified; Variable alias has been created.\n");
 
       return true;
     }
@@ -2268,8 +2069,9 @@ sem_variable::dump_to_file (FILE *file)
 
 unsigned int sem_item_optimizer::class_id = 0;
 
-sem_item_optimizer::sem_item_optimizer (): worklist (0), m_classes (0),
-  m_classes_count (0), m_cgraph_node_hooks (NULL), m_varpool_node_hooks (NULL)
+sem_item_optimizer::sem_item_optimizer ()
+: worklist (0), m_classes (0), m_classes_count (0), m_cgraph_node_hooks (NULL),
+  m_varpool_node_hooks (NULL), m_merged_variables (), m_references ()
 {
   m_items.create (0);
   bitmap_obstack_initialize (&m_bmstack);
@@ -2280,7 +2082,8 @@ sem_item_optimizer::~sem_item_optimizer ()
   for (unsigned int i = 0; i < m_items.length (); i++)
     delete m_items[i];
 
-  for (hash_table<congruence_class_group_hash>::iterator it = m_classes.begin ();
+
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
        it != m_classes.end (); ++it)
     {
       for (unsigned int i = 0; i < (*it)->classes.length (); i++)
@@ -2293,6 +2096,7 @@ sem_item_optimizer::~sem_item_optimizer ()
   m_items.release ();
 
   bitmap_obstack_release (&m_bmstack);
+  m_merged_variables.release ();
 }
 
 /* Write IPA ICF summary for symbols.  */
@@ -2349,8 +2153,8 @@ void
 sem_item_optimizer::read_section (lto_file_decl_data *file_data,
                                  const char *data, size_t len)
 {
-  const lto_function_header *header =
-    (const lto_function_header *) data;
+  const lto_function_header *header
+    (const lto_function_header *) data;
   const int cfg_offset = sizeof (lto_function_header);
   const int main_offset = cfg_offset + header->cfg_size;
   const int string_offset = main_offset + header->main_size;
@@ -2361,9 +2165,9 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
   lto_input_block ib_main ((const char *) data + main_offset, 0,
                           header->main_size, file_data->mode_table);
 
-  data_in =
-    lto_data_in_create (file_data, (const char *) data + string_offset,
-                       header->string_size, vNULL);
+  data_in
+    lto_data_in_create (file_data, (const char *) data + string_offset,
+                         header->string_size, vNULL);
 
   count = streamer_read_uhwi (&ib_main);
 
@@ -2378,24 +2182,23 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
       node = lto_symtab_encoder_deref (encoder, index);
 
       hashval_t hash = streamer_read_uhwi (&ib_main);
-
       gcc_assert (node->definition);
 
-      if (dump_file)
-       fprintf (dump_file, "Symbol added:%s (tree: %p, uid:%u)\n",
-                node->asm_name (), (void *) node->decl, node->order);
-
       if (is_a<cgraph_node *> (node))
        {
          cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
 
-         m_items.safe_push (new sem_function (cnode, hash, &m_bmstack));
+         sem_function *fn = new sem_function (cnode, &m_bmstack);
+         fn->set_hash (hash);
+         m_items.safe_push (fn);
        }
       else
        {
          varpool_node *vnode = dyn_cast <varpool_node *> (node);
 
-         m_items.safe_push (new sem_variable (vnode, hash, &m_bmstack));
+         sem_variable *var = new sem_variable (vnode, &m_bmstack);
+         var->set_hash (hash);
+         m_items.safe_push (var);
        }
     }
 
@@ -2404,7 +2207,7 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
   lto_data_in_delete (data_in);
 }
 
-/* Read IPA IPA ICF summary for symbols.  */
+/* Read IPA ICF summary for symbols.  */
 
 void
 sem_item_optimizer::read_summary (void)
@@ -2416,9 +2219,8 @@ sem_item_optimizer::read_summary (void)
   while ((file_data = file_data_vec[j++]))
     {
       size_t len;
-      const char *data = lto_get_section_data (file_data,
-                        LTO_section_ipa_icf, NULL, &len);
-
+      const char *data
+       = lto_get_summary_section_data (file_data, LTO_section_ipa_icf, &len);
       if (data)
        read_section (file_data, data, len);
     }
@@ -2457,9 +2259,9 @@ sem_item_optimizer::add_class (congruence_class *cls)
 {
   gcc_assert (cls->members.length ());
 
-  congruence_class_group *group = get_group_by_hash (
-                                   cls->members[0]->get_hash (),
-                                   cls->members[0]->type);
+  congruence_class_group *group
+    = get_group_by_hash (cls->members[0]->get_hash (),
+                        cls->members[0]->type);
   group->classes.safe_push (cls);
 }
 
@@ -2508,7 +2310,7 @@ sem_item_optimizer::varpool_removal_hook (varpool_node *node, void *data)
 void
 sem_item_optimizer::remove_symtab_node (symtab_node *node)
 {
-  gcc_assert (!m_classes.elements());
+  gcc_assert (m_classes.is_empty ());
 
   m_removed_items_set.add (node);
 }
@@ -2589,9 +2391,6 @@ sem_item_optimizer::execute (void)
     fprintf (dump_file, "Dump after hash based groups\n");
   dump_cong_classes ();
 
-  for (unsigned int i = 0; i < m_items.length(); i++)
-    m_items[i]->init_wpa ();
-
   subdivide_classes_by_equality (true);
 
   if (dump_file)
@@ -2600,14 +2399,14 @@ sem_item_optimizer::execute (void)
   dump_cong_classes ();
 
   process_cong_reduction ();
-  verify_classes ();
+  checking_verify_classes ();
 
   if (dump_file)
     fprintf (dump_file, "Dump after callgraph-based congruence reduction\n");
 
   dump_cong_classes ();
 
-  parse_nonsingleton_classes ();
+  unsigned int loaded_symbols = parse_nonsingleton_classes ();
   subdivide_classes_by_equality ();
 
   if (dump_file)
@@ -2619,11 +2418,11 @@ sem_item_optimizer::execute (void)
 
   process_cong_reduction ();
   dump_cong_classes ();
-  verify_classes ();
-  bool merged_p = merge_classes (prev_class_count);
+  checking_verify_classes ();
+  bool merged_p = merge_classes (prev_class_count, loaded_symbols);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    symtab_node::dump_table (dump_file);
+    symtab->dump (dump_file);
 
   return merged_p;
 }
@@ -2636,23 +2435,18 @@ sem_item_optimizer::parse_funcs_and_vars (void)
 {
   cgraph_node *cnode;
 
+  /* Create dummy func_checker for hashing purpose.  */
+  func_checker checker;
+
   if (flag_ipa_icf_functions)
     FOR_EACH_DEFINED_FUNCTION (cnode)
     {
-      sem_function *f = sem_function::parse (cnode, &m_bmstack);
+      sem_function *f = sem_function::parse (cnode, &m_bmstack, &checker);
       if (f)
        {
          m_items.safe_push (f);
          m_symtab_node_map.put (cnode, f);
-
-         if (dump_file)
-           fprintf (dump_file, "Parsed function:%s\n", f->node->asm_name ());
-
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           f->dump_to_file (dump_file);
        }
-      else if (dump_file)
-       fprintf (dump_file, "Not parsed function:%s\n", cnode->asm_name ());
     }
 
   varpool_node *vnode;
@@ -2660,7 +2454,7 @@ sem_item_optimizer::parse_funcs_and_vars (void)
   if (flag_ipa_icf_variables)
     FOR_EACH_DEFINED_VARIABLE (vnode)
     {
-      sem_variable *v = sem_variable::parse (vnode, &m_bmstack);
+      sem_variable *v = sem_variable::parse (vnode, &m_bmstack, &checker);
 
       if (v)
        {
@@ -2677,6 +2471,7 @@ sem_item_optimizer::add_item_to_class (congruence_class *cls, sem_item *item)
 {
   item->index_in_class = cls->members.length ();
   cls->members.safe_push (item);
+  cls->referenced_by_count += item->referenced_by_count;
   item->cls = cls;
 }
 
@@ -2702,15 +2497,15 @@ sem_item_optimizer::update_hash_by_addr_refs ()
             {
                tree class_type
                  = TYPE_METHOD_BASETYPE (TREE_TYPE (m_items[i]->decl));
-               inchash::hash hstate (m_items[i]->hash);
+               inchash::hash hstate (m_items[i]->get_hash ());
 
                if (TYPE_NAME (class_type)
                     && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type)))
-                 hstate.add_wide_int
+                 hstate.add_hwi
                    (IDENTIFIER_HASH_VALUE
                       (DECL_ASSEMBLER_NAME (TYPE_NAME (class_type))));
 
-               m_items[i]->hash = hstate.end ();
+               m_items[i]->set_hash (hstate.end ());
             }
        }
     }
@@ -2724,7 +2519,7 @@ sem_item_optimizer::update_hash_by_addr_refs ()
 
   /* Global hash value replace current hash values.  */
   for (unsigned i = 0; i < m_items.length (); i++)
-    m_items[i]->hash = m_items[i]->global_hash;
+    m_items[i]->set_hash (m_items[i]->global_hash);
 }
 
 /* Congruence classes are built by hash value.  */
@@ -2736,8 +2531,8 @@ sem_item_optimizer::build_hash_based_classes (void)
     {
       sem_item *item = m_items[i];
 
-      congruence_class_group *group = get_group_by_hash (item->hash,
-                                     item->type);
+      congruence_class_group *group
+       = get_group_by_hash (item->get_hash (), item->type);
 
       if (!group->classes.length ())
        {
@@ -2758,6 +2553,10 @@ sem_item_optimizer::build_graph (void)
     {
       sem_item *item = m_items[i];
       m_symtab_node_map.put (item->node, item);
+
+      /* Initialize hash values if we are not in LTO mode.  */
+      if (!in_lto_p)
+       item->get_hash ();
     }
 
   for (unsigned i = 0; i < m_items.length (); i++)
@@ -2774,7 +2573,7 @@ sem_item_optimizer::build_graph (void)
              sem_item **slot = m_symtab_node_map.get
                (e->callee->ultimate_alias_target ());
              if (slot)
-               item->add_reference (*slot);
+               item->add_reference (&m_references, *slot);
 
              e = e->next_callee;
            }
@@ -2786,7 +2585,7 @@ sem_item_optimizer::build_graph (void)
          sem_item **slot = m_symtab_node_map.get
            (ref->referred->ultimate_alias_target ());
          if (slot)
-           item->add_reference (*slot);
+           item->add_reference (&m_references, *slot);
        }
     }
 }
@@ -2794,21 +2593,28 @@ sem_item_optimizer::build_graph (void)
 /* Semantic items in classes having more than one element and initialized.
    In case of WPA, we load function body.  */
 
-void
+unsigned int
 sem_item_optimizer::parse_nonsingleton_classes (void)
 {
-  unsigned int init_called_count = 0;
+  unsigned int counter = 0;
+
+  /* Create dummy func_checker for hashing purpose.  */
+  func_checker checker;
 
   for (unsigned i = 0; i < m_items.length (); i++)
     if (m_items[i]->cls->members.length () > 1)
       {
-       m_items[i]->init ();
-       init_called_count++;
+       m_items[i]->init (&checker);
+       ++counter;
       }
 
   if (dump_file)
-    fprintf (dump_file, "Init called for %u items (%.2f%%).\n", init_called_count,
-            m_items.length () ? 100.0f * init_called_count / m_items.length (): 0.0f);
+    {
+      float f = m_items.length () ? 100.0f * counter / m_items.length () : 0.0f;
+      fprintf (dump_file, "Init called for %u items (%.2f%%).\n", counter, f);
+    }
+
+  return counter;
 }
 
 /* Equality function for semantic items is used to subdivide existing
@@ -2817,14 +2623,14 @@ sem_item_optimizer::parse_nonsingleton_classes (void)
 void
 sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
 {
-  for (hash_table <congruence_class_group_hash>::iterator it = m_classes.begin ();
+  for (hash_table <congruence_class_hash>::iterator it = m_classes.begin ();
        it != m_classes.end (); ++it)
     {
       unsigned int class_count = (*it)->classes.length ();
 
       for (unsigned i = 0; i < class_count; i++)
        {
-         congruence_class *c = (*it)->classes [i];
+         congruence_class *c = (*it)->classes[i];
 
          if (c->members.length() > 1)
            {
@@ -2839,8 +2645,9 @@ sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
                {
                  sem_item *item = c->members[j];
 
-                 bool equals = in_wpa ? first->equals_wpa (item,
-                               m_symtab_node_map) : first->equals (item, m_symtab_node_map);
+                 bool equals
+                   = in_wpa ? first->equals_wpa (item, m_symtab_node_map)
+                            : first->equals (item, m_symtab_node_map);
 
                  if (equals)
                    new_vector.safe_push (item);
@@ -2848,11 +2655,13 @@ sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
                    {
                      bool integrated = false;
 
-                     for (unsigned k = class_split_first; k < (*it)->classes.length (); k++)
+                     for (unsigned k = class_split_first;
+                          k < (*it)->classes.length (); k++)
                        {
                          sem_item *x = (*it)->classes[k]->members[0];
-                         bool equals = in_wpa ? x->equals_wpa (item,
-                                                               m_symtab_node_map) : x->equals (item, m_symtab_node_map);
+                         bool equals
+                           = in_wpa ? x->equals_wpa (item, m_symtab_node_map)
+                                    : x->equals (item, m_symtab_node_map);
 
                          if (equals)
                            {
@@ -2865,7 +2674,8 @@ sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
 
                      if (!integrated)
                        {
-                         congruence_class *c = new congruence_class (class_id++);
+                         congruence_class *c
+                           = new congruence_class (class_id++);
                          m_classes_count++;
                          add_item_to_class (c, item);
 
@@ -2874,7 +2684,8 @@ sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
                    }
                }
 
-             // we replace newly created new_vector for the class we've just splitted
+             // We replace newly created new_vector for the class we've just
+             // splitted.
              c->members.release ();
              c->members.create (new_vector.length ());
 
@@ -2884,7 +2695,7 @@ sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
        }
     }
 
-  verify_classes ();
+  checking_verify_classes ();
 }
 
 /* Subdivide classes by address references that members of the class
@@ -2899,7 +2710,7 @@ sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
 
   unsigned newly_created_classes = 0;
 
-  for (hash_table <congruence_class_group_hash>::iterator it = m_classes.begin ();
+  for (hash_table <congruence_class_hash>::iterator it = m_classes.begin ();
        it != m_classes.end (); ++it)
     {
       unsigned int class_count = (*it)->classes.length ();
@@ -2907,7 +2718,7 @@ sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
 
       for (unsigned i = 0; i < class_count; i++)
        {
-         congruence_class *c = (*it)->classes [i];
+         congruence_class *c = (*it)->classes[i];
 
          if (c->members.length() > 1)
            {
@@ -2917,11 +2728,12 @@ sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
                {
                  sem_item *source_node = c->members[j];
 
-                 symbol_compare_collection *collection = new symbol_compare_collection (source_node->node);
+                 symbol_compare_collection *collection
+                   = new symbol_compare_collection (source_node->node);
 
                  bool existed;
-                 vec <sem_item *> *slot = &split_map.get_or_insert (collection,
-                                                                    &existed);
+                 vec <sem_item *> *slot
+                   = &split_map.get_or_insert (collection, &existed);
                  gcc_checking_assert (slot);
 
                  slot->safe_push (source_node);
@@ -2930,8 +2742,8 @@ sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
                    delete collection;
                }
 
-              /* If the map contains more than one key, we have to split the map
-                 appropriately.  */
+              /* If the map contains more than one key, we have to split
+                 the map appropriately.  */
              if (split_map.elements () != 1)
                {
                  bool first_class = true;
@@ -2978,39 +2790,39 @@ sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
   return newly_created_classes;
 }
 
-/* Verify congruence classes if checking is enabled.  */
+/* Verify congruence classes, if checking is enabled.  */
+
+void
+sem_item_optimizer::checking_verify_classes (void)
+{
+  if (flag_checking)
+    verify_classes ();
+}
+
+/* Verify congruence classes.  */
 
 void
 sem_item_optimizer::verify_classes (void)
 {
-#if ENABLE_CHECKING
-  for (hash_table <congruence_class_group_hash>::iterator it = m_classes.begin ();
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
        it != m_classes.end (); ++it)
     {
       for (unsigned int i = 0; i < (*it)->classes.length (); i++)
        {
          congruence_class *cls = (*it)->classes[i];
 
-         gcc_checking_assert (cls);
-         gcc_checking_assert (cls->members.length () > 0);
+         gcc_assert (cls);
+         gcc_assert (cls->members.length () > 0);
 
          for (unsigned int j = 0; j < cls->members.length (); j++)
            {
              sem_item *item = cls->members[j];
 
-             gcc_checking_assert (item);
-             gcc_checking_assert (item->cls == cls);
-
-             for (unsigned k = 0; k < item->usages.length (); k++)
-               {
-                 sem_usage_pair *usage = item->usages[k];
-                 gcc_checking_assert (usage->item->index_in_class <
-                                      usage->item->cls->members.length ());
-               }
+             gcc_assert (item);
+             gcc_assert (item->cls == cls);
            }
        }
     }
-#endif
 }
 
 /* Disposes split map traverse function. CLS_PTR is pointer to congruence
@@ -3034,7 +2846,8 @@ sem_item_optimizer::release_split_map (congruence_class * const &,
 
 bool
 sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
-    bitmap const &b, traverse_split_pair *pair)
+                                              bitmap const &b,
+                                              traverse_split_pair *pair)
 {
   sem_item_optimizer *optimizer = pair->optimizer;
   const congruence_class *splitter_cls = pair->cls;
@@ -3045,7 +2858,9 @@ sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
 
   if (popcount > 0 && popcount < cls->members.length ())
     {
-      congruence_class* newclasses[2] = { new congruence_class (class_id++), new congruence_class (class_id++) };
+      auto_vec <congruence_class *, 2> newclasses;
+      newclasses.quick_push (new congruence_class (class_id++));
+      newclasses.quick_push (new congruence_class (class_id++));
 
       for (unsigned int i = 0; i < cls->members.length (); i++)
        {
@@ -3055,10 +2870,11 @@ sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
          add_item_to_class (tc, cls->members[i]);
        }
 
-#ifdef ENABLE_CHECKING
-      for (unsigned int i = 0; i < 2; i++)
-       gcc_checking_assert (newclasses[i]->members.length ());
-#endif
+      if (flag_checking)
+       {
+         for (unsigned int i = 0; i < 2; i++)
+           gcc_assert (newclasses[i]->members.length ());
+       }
 
       if (splitter_cls == cls)
        optimizer->splitter_class_removed = true;
@@ -3073,7 +2889,7 @@ sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
       g.hash = cls->members[0]->get_hash ();
       g.type = cls->members[0]->type;
 
-      congruence_class_group *slot = optimizer->m_classes.find(&g);
+      congruence_class_group *slot = optimizer->m_classes.find (&g);
 
       for (unsigned int i = 0; i < slot->classes.length (); i++)
        if (slot->classes[i] == cls)
@@ -3096,9 +2912,10 @@ sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
          optimizer->worklist_push (newclasses[i]);
       else /* Just smaller class is inserted.  */
        {
-         unsigned int smaller_index = newclasses[0]->members.length () <
-                                      newclasses[1]->members.length () ?
-                                      0 : 1;
+         unsigned int smaller_index
+           = (newclasses[0]->members.length ()
+              < newclasses[1]->members.length ()
+              ? 0 : 1);
          optimizer->worklist_push (newclasses[smaller_index]);
        }
 
@@ -3115,65 +2932,92 @@ sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
       /* Release class if not presented in work list.  */
       if (!in_worklist)
        delete cls;
+
+      return true;
     }
 
+  return false;
+}
 
-  return true;
+/* Compare function for sorting pairs in do_congruence_step_f.  */
+
+int
+sem_item_optimizer::sort_congruence_split (const void *a_, const void *b_)
+{
+  const std::pair<congruence_class *, bitmap> *a
+    = (const std::pair<congruence_class *, bitmap> *)a_;
+  const std::pair<congruence_class *, bitmap> *b
+    = (const std::pair<congruence_class *, bitmap> *)b_;
+  if (a->first->id < b->first->id)
+    return -1;
+  else if (a->first->id > b->first->id)
+    return 1;
+  return 0;
 }
 
 /* Tests if a class CLS used as INDEXth splits any congruence classes.
    Bitmap stack BMSTACK is used for bitmap allocation.  */
 
-void
+bool
 sem_item_optimizer::do_congruence_step_for_index (congruence_class *cls,
-    unsigned int index)
+                                                 unsigned int index)
 {
   hash_map <congruence_class *, bitmap> split_map;
 
   for (unsigned int i = 0; i < cls->members.length (); i++)
     {
       sem_item *item = cls->members[i];
+      sem_usage_pair needle (item, index);
+      vec<sem_item *> *callers = m_references.get (&needle);
+      if (callers == NULL)
+       continue;
 
-      /* Iterate all usages that have INDEX as usage of the item.  */
-      for (unsigned int j = 0; j < item->usages.length (); j++)
+      for (unsigned int j = 0; j < callers->length (); j++)
        {
-         sem_usage_pair *usage = item->usages[j];
-
-         if (usage->index != index)
+         sem_item *caller = (*callers)[j];
+         if (caller->cls->members.length () < 2)
            continue;
-
-         bitmap *slot = split_map.get (usage->item->cls);
+         bitmap *slot = split_map.get (caller->cls);
          bitmap b;
 
          if(!slot)
            {
              b = BITMAP_ALLOC (&m_bmstack);
-             split_map.put (usage->item->cls, b);
+             split_map.put (caller->cls, b);
            }
          else
            b = *slot;
 
-#if ENABLE_CHECKING
-         gcc_checking_assert (usage->item->cls);
-         gcc_checking_assert (usage->item->index_in_class <
-                              usage->item->cls->members.length ());
-#endif
+         gcc_checking_assert (caller->cls);
+         gcc_checking_assert (caller->index_in_class
+                              < caller->cls->members.length ());
 
-         bitmap_set_bit (b, usage->item->index_in_class);
+         bitmap_set_bit (b, caller->index_in_class);
        }
     }
 
+  auto_vec<std::pair<congruence_class *, bitmap> > to_split;
+  to_split.reserve_exact (split_map.elements ());
+  for (hash_map <congruence_class *, bitmap>::iterator i = split_map.begin ();
+       i != split_map.end (); ++i)
+    to_split.safe_push (*i);
+  to_split.qsort (sort_congruence_split);
+
   traverse_split_pair pair;
   pair.optimizer = this;
   pair.cls = cls;
 
   splitter_class_removed = false;
-  split_map.traverse
-  <traverse_split_pair *, sem_item_optimizer::traverse_congruence_split> (&pair);
+  bool r = false;
+  for (unsigned i = 0; i < to_split.length (); ++i)
+    r |= traverse_congruence_split (to_split[i].first, to_split[i].second,
+                                   &pair);
 
   /* Bitmap clean-up.  */
-  split_map.traverse
-  <traverse_split_pair *, sem_item_optimizer::release_split_map> (NULL);
+  split_map.traverse <traverse_split_pair *,
+                     sem_item_optimizer::release_split_map> (NULL);
+
+  return r;
 }
 
 /* Every usage of a congruence class CLS is a candidate that can split the
@@ -3194,9 +3038,9 @@ sem_item_optimizer::do_congruence_step (congruence_class *cls)
   EXECUTE_IF_SET_IN_BITMAP (usage, 0, i, bi)
   {
     if (dump_file && (dump_flags & TDF_DETAILS))
-      fprintf (dump_file, "  processing congruece step for class: %u, index: %u\n",
-              cls->id, i);
-
+      fprintf (dump_file, "  processing congruence step for class: %u "
+              "(%u items, %u references), index: %u\n", cls->id,
+              cls->referenced_by_count, cls->members.length (), i);
     do_congruence_step_for_index (cls, i);
 
     if (splitter_class_removed)
@@ -3216,7 +3060,7 @@ sem_item_optimizer::worklist_push (congruence_class *cls)
     return;
 
   cls->in_worklist = true;
-  worklist.push_back (cls);
+  worklist.insert (cls->referenced_by_count, cls);
 }
 
 /* Pops a class from worklist. */
@@ -3228,8 +3072,7 @@ sem_item_optimizer::worklist_pop (void)
 
   while (!worklist.empty ())
     {
-      cls = worklist.front ();
-      worklist.pop_front ();
+      cls = worklist.extract_min ();
       if (cls->in_worklist)
        {
          cls->in_worklist = false;
@@ -3253,7 +3096,7 @@ sem_item_optimizer::worklist_pop (void)
 void
 sem_item_optimizer::process_cong_reduction (void)
 {
-  for (hash_table<congruence_class_group_hash>::iterator it = m_classes.begin ();
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
        it != m_classes.end (); ++it)
     for (unsigned i = 0; i < (*it)->classes.length (); i++)
       if ((*it)->classes[i]->is_class_used ())
@@ -3261,7 +3104,7 @@ sem_item_optimizer::process_cong_reduction (void)
 
   if (dump_file)
     fprintf (dump_file, "Worklist has been filled with: %lu\n",
-            (unsigned long) worklist.size ());
+            (unsigned long) worklist.nodes ());
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "Congruence class reduction\n");
@@ -3288,17 +3131,13 @@ sem_item_optimizer::dump_cong_classes (void)
   if (!dump_file)
     return;
 
-  fprintf (dump_file,
-          "Congruence classes: %u (unique hash values: %lu), with total: %u items\n",
-          m_classes_count, (unsigned long) m_classes.elements(), m_items.length ());
-
   /* Histogram calculation.  */
   unsigned int max_index = 0;
+  unsigned int single_element_classes = 0;
   unsigned int* histogram = XCNEWVEC (unsigned int, m_items.length () + 1);
 
-  for (hash_table<congruence_class_group_hash>::iterator it = m_classes.begin ();
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
        it != m_classes.end (); ++it)
-
     for (unsigned i = 0; i < (*it)->classes.length (); i++)
       {
        unsigned int c = (*it)->classes[i]->members.length ();
@@ -3306,29 +3145,33 @@ sem_item_optimizer::dump_cong_classes (void)
 
        if (c > max_index)
          max_index = c;
+
+       if (c == 1)
+         ++single_element_classes;
       }
 
   fprintf (dump_file,
-          "Class size histogram [num of members]: number of classe number of classess\n");
-
+          "Congruence classes: %lu with total: %u items (in a non-singular "
+          "class: %u)\n", (unsigned long) m_classes.elements (),
+          m_items.length (), m_items.length () - single_element_classes);
+  fprintf (dump_file,
+          "Class size histogram [number of members]: number of classes\n");
   for (unsigned int i = 0; i <= max_index; i++)
     if (histogram[i])
-      fprintf (dump_file, "[%u]: %u classes\n", i, histogram[i]);
-
-  fprintf (dump_file, "\n\n");
-
+      fprintf (dump_file, "%6u: %6u\n", i, histogram[i]);
 
   if (dump_flags & TDF_DETAILS)
-    for (hash_table<congruence_class_group_hash>::iterator it = m_classes.begin ();
+    for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
         it != m_classes.end (); ++it)
       {
-       fprintf (dump_file, "  group: with %u classes:\n", (*it)->classes.length ());
+       fprintf (dump_file, "  group: with %u classes:\n",
+                (*it)->classes.length ());
 
        for (unsigned i = 0; i < (*it)->classes.length (); i++)
          {
            (*it)->classes[i]->dump (dump_file, 4);
 
-           if(i < (*it)->classes.length () - 1)
+           if (i < (*it)->classes.length () - 1)
              fprintf (dump_file, " ");
          }
       }
@@ -3336,13 +3179,54 @@ sem_item_optimizer::dump_cong_classes (void)
   free (histogram);
 }
 
+/* Sort pair of sem_items A and B by DECL_UID.  */
+
+static int
+sort_sem_items_by_decl_uid (const void *a, const void *b)
+{
+  const sem_item *i1 = *(const sem_item * const *)a;
+  const sem_item *i2 = *(const sem_item * const *)b;
+
+  int uid1 = DECL_UID (i1->decl);
+  int uid2 = DECL_UID (i2->decl);
+  return uid1 - uid2;
+}
+
+/* Sort pair of congruence_classes A and B by DECL_UID of the first member.  */
+
+static int
+sort_congruence_classes_by_decl_uid (const void *a, const void *b)
+{
+  const congruence_class *c1 = *(const congruence_class * const *)a;
+  const congruence_class *c2 = *(const congruence_class * const *)b;
+
+  int uid1 = DECL_UID (c1->members[0]->decl);
+  int uid2 = DECL_UID (c2->members[0]->decl);
+  return uid1 - uid2;
+}
+
+/* Sort pair of congruence_class_groups A and B by
+   DECL_UID of the first member of a first group.  */
+
+static int
+sort_congruence_class_groups_by_decl_uid (const void *a, const void *b)
+{
+  const std::pair<congruence_class_group *, int> *g1
+    = (const std::pair<congruence_class_group *, int> *) a;
+  const std::pair<congruence_class_group *, int> *g2
+    = (const std::pair<congruence_class_group *, int> *) b;
+  return g1->second - g2->second;
+}
+
 /* After reduction is done, we can declare all items in a group
    to be equal. PREV_CLASS_COUNT is start number of classes
    before reduction. True is returned if there's a merge operation
-   processed. */
+   processed.  LOADED_SYMBOLS is number of symbols that were loaded
+   in WPA.  */
 
 bool
-sem_item_optimizer::merge_classes (unsigned int prev_class_count)
+sem_item_optimizer::merge_classes (unsigned int prev_class_count,
+                                  unsigned int loaded_symbols)
 {
   unsigned int item_count = m_items.length ();
   unsigned int class_count = m_classes_count;
@@ -3353,7 +3237,23 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
 
   bool merged_p = false;
 
-  for (hash_table<congruence_class_group_hash>::iterator it = m_classes.begin ();
+  /* PR lto/78211
+     Sort functions in congruence classes by DECL_UID and do the same
+     for the classes to not to break -fcompare-debug.  */
+
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
+       it != m_classes.end (); ++it)
+    {
+      for (unsigned int i = 0; i < (*it)->classes.length (); i++)
+       {
+         congruence_class *c = (*it)->classes[i];
+         c->members.qsort (sort_sem_items_by_decl_uid);
+       }
+
+      (*it)->classes.qsort (sort_congruence_classes_by_decl_uid);
+    }
+
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
        it != m_classes.end (); ++it)
     for (unsigned int i = 0; i < (*it)->classes.length (); i++)
       {
@@ -3365,6 +3265,17 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
          }
       }
 
+  auto_vec<std::pair<congruence_class_group *, int> > classes (
+    m_classes.elements ());
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
+       it != m_classes.end (); ++it)
+    {
+      int uid = DECL_UID ((*it)->classes[0]->members[0]->decl);
+      classes.quick_push (std::pair<congruence_class_group *, int> (*it, uid));
+    }
+
+  classes.qsort (sort_congruence_class_groups_by_decl_uid);
+
   if (dump_file)
     {
       fprintf (dump_file, "\nItem count: %u\n", item_count);
@@ -3378,44 +3289,57 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
               non_singular_classes_count : 0.0f,
               non_singular_classes_count);
       fprintf (dump_file, "Equal symbols: %u\n", equal_items);
-      fprintf (dump_file, "Fraction of visited symbols: %.2f%%\n\n",
-              item_count ? 100.0f * equal_items / item_count : 0.0f);
+      unsigned total = equal_items + non_singular_classes_count;
+      fprintf (dump_file, "Totally needed symbols: %u"
+              ", fraction of loaded symbols: %.2f%%\n\n", total,
+              loaded_symbols ? 100.0f * total / loaded_symbols: 0.0f);
     }
 
-  for (hash_table<congruence_class_group_hash>::iterator it = m_classes.begin ();
-       it != m_classes.end (); ++it)
-    for (unsigned int i = 0; i < (*it)->classes.length (); i++)
+  unsigned int l;
+  std::pair<congruence_class_group *, int> *it;
+  FOR_EACH_VEC_ELT (classes, l, it)
+    for (unsigned int i = 0; i < it->first->classes.length (); i++)
       {
-       congruence_class *c = (*it)->classes[i];
+       congruence_class *c = it->first->classes[i];
 
        if (c->members.length () == 1)
          continue;
 
-       gcc_assert (c->members.length ());
-
        sem_item *source = c->members[0];
 
-       for (unsigned int j = 1; j < c->members.length (); j++)
+       if (DECL_NAME (source->decl)
+           && MAIN_NAME_P (DECL_NAME (source->decl)))
+         /* If merge via wrappers, picking main as the target can be
+            problematic.  */
+         source = c->members[1];
+
+       for (unsigned int j = 0; j < c->members.length (); j++)
          {
            sem_item *alias = c->members[j];
 
-           if (dump_file)
+           if (alias == source)
+             continue;
+
+           dump_user_location_t loc
+             = dump_user_location_t::from_function_decl (source->decl);
+           if (dump_enabled_p ())
              {
-               fprintf (dump_file, "Semantic equality hit:%s->%s\n",
-                        xstrdup_for_dump (source->node->name ()),
-                        xstrdup_for_dump (alias->node->name ()));
-               fprintf (dump_file, "Assembler symbol names:%s->%s\n",
-                        xstrdup_for_dump (source->node->asm_name ()),
-                        xstrdup_for_dump (alias->node->asm_name ()));
+               dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+                                "Semantic equality hit:%s->%s\n",
+                                source->node->dump_name (),
+                                alias->node->dump_name ());
+               dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+                                "Assembler symbol names:%s->%s\n",
+                                source->node->dump_asm_name (),
+                                alias->node->dump_asm_name ());
              }
 
            if (lookup_attribute ("no_icf", DECL_ATTRIBUTES (alias->decl)))
              {
-               if (dump_file)
-                 fprintf (dump_file,
-                          "Merge operation is skipped due to no_icf "
-                          "attribute.\n\n");
-
+               if (dump_enabled_p ())
+                 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+                                  "Merge operation is skipped due to no_icf "
+                                  "attribute.\n");
                continue;
              }
 
@@ -3426,13 +3350,103 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
              }
 
            if (dbg_cnt (merged_ipa_icf))
-             merged_p |= source->merge (alias);
+             {
+               bool merged = source->merge (alias);
+               merged_p |= merged;
+
+               if (merged && alias->type == VAR)
+                 {
+                   symtab_pair p = symtab_pair (source->node, alias->node);
+                   m_merged_variables.safe_push (p);
+                 }
+             }
          }
       }
 
+  if (!m_merged_variables.is_empty ())
+    fixup_points_to_sets ();
+
   return merged_p;
 }
 
+/* Fixup points to set PT.  */
+
+void
+sem_item_optimizer::fixup_pt_set (struct pt_solution *pt)
+{
+  if (pt->vars == NULL)
+    return;
+
+  unsigned i;
+  symtab_pair *item;
+  FOR_EACH_VEC_ELT (m_merged_variables, i, item)
+    if (bitmap_bit_p (pt->vars, DECL_UID (item->second->decl)))
+      bitmap_set_bit (pt->vars, DECL_UID (item->first->decl));
+}
+
+/* Set all points-to UIDs of aliases pointing to node N as UID.  */
+
+static void
+set_alias_uids (symtab_node *n, int uid)
+{
+  ipa_ref *ref;
+  FOR_EACH_ALIAS (n, ref)
+    {
+      if (dump_file)
+       fprintf (dump_file, "  Setting points-to UID of [%s] as %d\n",
+                ref->referring->dump_asm_name (), uid);
+
+      SET_DECL_PT_UID (ref->referring->decl, uid);
+      set_alias_uids (ref->referring, uid);
+    }
+}
+
+/* Fixup points to analysis info.  */
+
+void
+sem_item_optimizer::fixup_points_to_sets (void)
+{
+  /* TODO: remove in GCC 9 and trigger PTA re-creation after IPA passes.  */
+  cgraph_node *cnode;
+
+  FOR_EACH_DEFINED_FUNCTION (cnode)
+    {
+      tree name;
+      unsigned i;
+      function *fn = DECL_STRUCT_FUNCTION (cnode->decl);
+      if (!gimple_in_ssa_p (fn))
+       continue;
+
+      FOR_EACH_SSA_NAME (i, name, fn)
+       if (POINTER_TYPE_P (TREE_TYPE (name))
+           && SSA_NAME_PTR_INFO (name))
+         fixup_pt_set (&SSA_NAME_PTR_INFO (name)->pt);
+      fixup_pt_set (&fn->gimple_df->escaped);
+
+       /* The above gets us to 99% I guess, at least catching the
+         address compares.  Below also gets us aliasing correct
+         but as said we're giving leeway to the situation with
+         readonly vars anyway, so ... */
+       basic_block bb;
+       FOR_EACH_BB_FN (bb, fn)
+       for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
+            gsi_next (&gsi))
+         {
+           gcall *call = dyn_cast<gcall *> (gsi_stmt (gsi));
+           if (call)
+             {
+               fixup_pt_set (gimple_call_use_set (call));
+               fixup_pt_set (gimple_call_clobber_set (call));
+             }
+         }
+    }
+
+  unsigned i;
+  symtab_pair *item;
+  FOR_EACH_VEC_ELT (m_merged_variables, i, item)
+    set_alias_uids (item->first, DECL_UID (item->first->decl));
+}
+
 /* Dump function prints all class members to a FILE with an INDENT.  */
 
 void
@@ -3443,9 +3457,7 @@ congruence_class::dump (FILE *file, unsigned int indent) const
 
   FPUTS_SPACES (file, indent + 2, "");
   for (unsigned i = 0; i < members.length (); i++)
-    fprintf (file, "%s(%p/%u) ", members[i]->node->asm_name (),
-            (void *) members[i]->decl,
-            members[i]->node->order);
+    fprintf (file, "%s ", members[i]->node->dump_asm_name ());
 
   fprintf (file, "\n");
 }
@@ -3456,7 +3468,7 @@ bool
 congruence_class::is_class_used (void)
 {
   for (unsigned int i = 0; i < members.length (); i++)
-    if (members[i]->usages.length ())
+    if (members[i]->referenced_by_count)
       return true;
 
   return false;
@@ -3496,7 +3508,7 @@ ipa_icf_read_summary (void)
   optimizer->register_hooks ();
 }
 
-/* Semantic equality exection function.  */
+/* Semantic equality execution function.  */
 
 static unsigned int
 ipa_icf_driver (void)