d: Force TYPE_MODE of classes and non-POD structs as BLKmode
[gcc.git] / gcc / ipa-icf.c
index bcfed2b08686537a31820df5a45af1e5e61bbbb1..5bbbec6c806fac05054010fea795a91f73020f5e 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural Identical Code Folding pass
-   Copyright (C) 2014-2019 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>
 
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coverage.h"
 #include "gimple-pretty-print.h"
 #include "data-streamer.h"
+#include "tree-streamer.h"
 #include "fold-const.h"
 #include "calls.h"
 #include "varasm.h"
@@ -78,12 +79,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "tree-ssa-alias-compare.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"
+#include "symtab-thunks.h"
+#include "alias.h"
 
 using namespace ipa_icf_gimple;
 
@@ -225,14 +229,16 @@ 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_item (FUNC, stack), memory_access_types (), m_alias_sets_hash (0),
+    m_checker (NULL), m_compared_func (NULL)
 {
   bb_sizes.create (0);
   bb_sorted.create (0);
 }
 
 sem_function::sem_function (cgraph_node *node, bitmap_obstack *stack)
-: sem_item (FUNC, node, stack), m_checker (NULL), m_compared_func (NULL)
+  : sem_item (FUNC, node, stack), memory_access_types (),
+    m_alias_sets_hash (0), m_checker (NULL), m_compared_func (NULL)
 {
   bb_sizes.create (0);
   bb_sorted.create (0);
@@ -300,7 +306,7 @@ sem_function::get_hash (void)
 
 /* 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.
@@ -347,6 +353,10 @@ sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
       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
@@ -484,7 +494,7 @@ sem_function::param_used_p (unsigned int i)
 
   class ipa_node_params *parms_info = IPA_NODE_REF (get_node ());
 
-  if (vec_safe_length (parms_info->descriptors) <= i)
+  if (!parms_info || vec_safe_length (parms_info->descriptors) <= i)
     return true;
 
   return ipa_is_param_used (IPA_NODE_REF (get_node ()), i);
@@ -526,22 +536,14 @@ sem_function::equals_wpa (sem_item *item,
 
   m_compared_func = static_cast<sem_function *> (item);
 
-  if (cnode->thunk.thunk_p != cnode2->thunk.thunk_p)
-    return return_false_with_msg ("thunk_p mismatch");
+  if (cnode->thunk != cnode2->thunk)
+    return return_false_with_msg ("thunk mismatch");
+  if (cnode->former_thunk_p () != cnode2->former_thunk_p ())
+    return return_false_with_msg ("former_thunk_p mismatch");
 
-  if (cnode->thunk.thunk_p)
-    {
-      if (cnode->thunk.fixed_offset != cnode2->thunk.fixed_offset)
-        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 || cnode->former_thunk_p ())
+      && thunk_info::get (cnode) != thunk_info::get (cnode2))
+    return return_false_with_msg ("thunk_info mismatch");
 
   /* Compare special function DECL attributes.  */
   if (DECL_FUNCTION_PERSONALITY (decl)
@@ -550,7 +552,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))
@@ -573,10 +575,11 @@ sem_function::equals_wpa (sem_item *item,
      type memory location for ipa-polymorphic-call and we do not want
      it to get confused by wrong type.  */
   if (DECL_CXX_CONSTRUCTOR_P (decl)
+      && opt_for_fn (decl, flag_devirtualize)
       && 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))
@@ -726,7 +729,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
@@ -845,8 +848,9 @@ sem_function::equals_private (sem_item *item)
     return return_false ();
 
   m_checker = new func_checker (decl, m_compared_func->decl,
-                               compare_polymorphic_p (),
                                false,
+                               opt_for_fn (m_compared_func->decl,
+                                           flag_strict_aliasing),
                                &refs_set,
                                &m_compared_func->refs_set);
   arg1 = DECL_ARGUMENTS (decl);
@@ -880,7 +884,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();
+      return return_false ();
 
   auto_vec <int> bb_dict;
 
@@ -926,7 +930,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;
 }
 
@@ -965,7 +969,7 @@ redirect_all_callers (cgraph_node *n, cgraph_node *to)
       /* Redirecting thunks to interposable symbols or symbols in other sections
         may not be supported by target output code.  Play safe for now and
         punt on redirection.  */
-      if (!e->caller->thunk.thunk_p)
+      if (!e->caller->thunk)
        {
          struct cgraph_edge *nexte = e->next_caller;
           e->redirect_callee (to);
@@ -1115,7 +1119,7 @@ sem_function::merge (sem_item *alias_item)
         }
       /* 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)
@@ -1161,7 +1165,7 @@ sem_function::merge (sem_item *alias_item)
       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
@@ -1266,6 +1270,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.  */
@@ -1287,11 +1292,13 @@ sem_function::merge (sem_item *alias_item)
     {
       gcc_assert (!create_alias);
       alias->icf_merged = true;
+      symtab->call_cgraph_removal_hooks (alias);
       local_original->icf_merged = 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_enabled_p ())
        dump_printf (MSG_OPTIMIZED_LOCATIONS,
@@ -1333,8 +1340,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 ();
 
@@ -1355,7 +1363,7 @@ sem_function::init (void)
 
   edge_count = n_edges_for_fn (func);
   cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
-  if (!cnode->thunk.thunk_p)
+  if (!cnode->thunk)
     {
       cfg_checksum = coverage_compute_cfg_checksum (func);
 
@@ -1400,168 +1408,10 @@ sem_function::init (void)
   else
     {
       cfg_checksum = 0;
-      inchash::hash hstate;
-      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);
-      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_hwi (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_hwi (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_hwi (int_size_in_bytes (TREE_TYPE (exp)));
-      return add_expr (TREE_OPERAND (exp, 0), hstate);
-    default:
-      break;
+      gcode_hash = thunk_info::get (cnode)->hash ();
     }
-}
-
-/* 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);
-
-  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))
-    {
-      /* Incomplete types must be skipped here.  */
-      if (!COMPLETE_TYPE_P (type))
-       {
-         hstate.add_int (RECORD_TYPE);
-         return;
-       }
-
-      hashval_t *val = m_type_hash_cache.get (type);
 
-      if (!val)
-       {
-         inchash::hash hstate2;
-         unsigned nf;
-         tree f;
-         hashval_t hash;
-
-         hstate2.add_int (RECORD_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_hwi (hash);
-         m_type_hash_cache.put (type, hash);
-       }
-      else
-        hstate.add_hwi (*val);
-    }
+  m_checker = NULL;
 }
 
 /* Improve accumulated hash for HSTATE based on a gimple statement STMT.  */
@@ -1576,46 +1426,54 @@ 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, func_checker::OP_NORMAL);
       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);
-         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;
-       }
       /* fall through */
     case GIMPLE_CALL:
     case GIMPLE_ASM:
     case GIMPLE_COND:
     case GIMPLE_GOTO:
     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);
-       }
-      /* 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)));
+      {
+       func_checker::operand_access_type_map map (5);
+       func_checker::classify_operands (stmt, &map);
+
+       /* All these statements are equivalent if their operands are.  */
+       for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
+         {
+           func_checker::operand_access_type
+               access_type = func_checker::get_operand_access_type
+                                         (&map, gimple_op (stmt, i));
+           m_checker->hash_operand (gimple_op (stmt, i), hstate, 0,
+                                    access_type);
+           /* For memory accesses when hasing for LTO stremaing record
+              base and ref alias ptr types so we can compare them at WPA
+              time without having to read actual function body.  */
+           if (access_type == func_checker::OP_MEMORY
+               && lto_streaming_expected_p ()
+               && flag_strict_aliasing)
+             {
+               ao_ref ref;
+
+               ao_ref_init (&ref, gimple_op (stmt, i));
+               tree t = ao_ref_alias_ptr_type (&ref);
+               if (!variably_modified_type_p (t, NULL_TREE))
+                 memory_access_types.safe_push (t);
+               t = ao_ref_base_alias_ptr_type (&ref);
+               if (!variably_modified_type_p (t, NULL_TREE))
+                 memory_access_types.safe_push (t);
+             }
+         }
+       /* 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)));
+      }
+      break;
     default:
       break;
     }
@@ -1646,12 +1504,13 @@ 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);
 
-  if (!func || (!node->has_gimple_body_p () && !node->thunk.thunk_p))
+  if (!func || (!node->has_gimple_body_p () && !node->thunk))
     return NULL;
 
   if (lookup_attribute_by_prefix ("omp ", DECL_ATTRIBUTES (node->decl)) != NULL)
@@ -1667,8 +1526,7 @@ sem_function::parse (cgraph_node *node, bitmap_obstack *stack)
     return NULL;
 
   sem_function *f = new sem_function (node, stack);
-
-  f->init ();
+  f->init (checker);
 
   return f;
 }
@@ -1704,7 +1562,8 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
       tree phi_result1 = gimple_phi_result (phi1);
       tree phi_result2 = gimple_phi_result (phi2);
 
-      if (!m_checker->compare_operand (phi_result1, phi_result2))
+      if (!m_checker->compare_operand (phi_result1, phi_result2,
+                                      func_checker::OP_NORMAL))
        return return_false_with_msg ("PHI results are different");
 
       size1 = gimple_phi_num_args (phi1);
@@ -1718,7 +1577,7 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
          t1 = gimple_phi_arg (phi1, i)->def;
          t2 = gimple_phi_arg (phi2, i)->def;
 
-         if (!m_checker->compare_operand (t1, t2))
+         if (!m_checker->compare_operand (t1, t2, func_checker::OP_NORMAL))
            return return_false ();
 
          e1 = gimple_phi_arg_edge (phi1, i);
@@ -1734,17 +1593,6 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
   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.  */
 
@@ -1755,7 +1603,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)
     {
@@ -2047,40 +1895,45 @@ 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, stack);
-
-  v->init ();
+  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 (m_hash_set)
-    return m_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_hwi (tree_to_shwi (DECL_SIZE (decl)));
-  add_expr (ctor, hstate);
-  set_hash (hstate.end ());
+/* References independent hash function.  */
 
+hashval_t
+sem_variable::get_hash (void)
+{
+  gcc_checking_assert (m_hash_set);
   return m_hash;
 }
 
@@ -2157,7 +2010,7 @@ sem_variable::merge (sem_item *alias_item)
       return false;
     }
 
-  /* We cannot merge if address comparsion metters.  */
+  /* We cannot merge if address comparison matters.  */
   if (alias_address_matters && flag_merge_constants < 2)
     {
       if (dump_enabled_p ())
@@ -2302,6 +2155,14 @@ sem_item_optimizer::write_summary (void)
          streamer_write_uhwi_stream (ob->main_stream, node_ref);
 
          streamer_write_uhwi (ob, (*item)->get_hash ());
+
+         if ((*item)->type == FUNC)
+           {
+             sem_function *fn = static_cast<sem_function *> (*item);
+             streamer_write_uhwi (ob, fn->memory_access_types.length ());
+             for (unsigned i = 0; i < fn->memory_access_types.length (); i++)
+               stream_write_tree (ob, fn->memory_access_types[i], true);
+           }
        }
     }
 
@@ -2353,6 +2214,18 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
          cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
 
          sem_function *fn = new sem_function (cnode, &m_bmstack);
+         unsigned count = streamer_read_uhwi (&ib_main);
+         inchash::hash hstate (0);
+         if (flag_incremental_link == INCREMENTAL_LINK_LTO)
+           fn->memory_access_types.reserve_exact (count);
+         for (unsigned i = 0; i < count; i++)
+           {
+             tree type = stream_read_tree (&ib_main, data_in);
+             hstate.add_int (get_deref_alias_set (type));
+             if (flag_incremental_link == INCREMENTAL_LINK_LTO)
+               fn->memory_access_types.quick_push (type);
+           }
+         fn->m_alias_sets_hash = hstate.end ();
          fn->set_hash (hash);
          m_items.safe_push (fn);
        }
@@ -2383,9 +2256,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);
     }
@@ -2550,6 +2422,7 @@ sem_item_optimizer::execute (void)
 
   build_graph ();
   update_hash_by_addr_refs ();
+  update_hash_by_memory_access_type ();
   build_hash_based_classes ();
 
   if (dump_file)
@@ -2571,7 +2444,7 @@ sem_item_optimizer::execute (void)
 
   dump_cong_classes ();
 
-  parse_nonsingleton_classes ();
+  unsigned int loaded_symbols = parse_nonsingleton_classes ();
   subdivide_classes_by_equality ();
 
   if (dump_file)
@@ -2584,7 +2457,7 @@ sem_item_optimizer::execute (void)
   process_cong_reduction ();
   dump_cong_classes ();
   checking_verify_classes ();
-  bool merged_p = merge_classes (prev_class_count);
+  bool merged_p = merge_classes (prev_class_count, loaded_symbols);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     symtab->dump (dump_file);
@@ -2600,10 +2473,13 @@ 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);
@@ -2616,7 +2492,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)
        {
@@ -2661,11 +2537,24 @@ sem_item_optimizer::update_hash_by_addr_refs ()
                  = TYPE_METHOD_BASETYPE (TREE_TYPE (m_items[i]->decl));
                inchash::hash hstate (m_items[i]->get_hash ());
 
+               /* Hash ODR types by mangled name if it is defined.
+                  If not we know that type is anonymous of free_lang_data
+                  was not run and in that case type main variants are
+                  unique.  */
                if (TYPE_NAME (class_type)
-                    && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type)))
+                    && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type))
+                    && !type_in_anonymous_namespace_p
+                                (class_type))
                  hstate.add_hwi
                    (IDENTIFIER_HASH_VALUE
                       (DECL_ASSEMBLER_NAME (TYPE_NAME (class_type))));
+               else
+                 {
+                   gcc_checking_assert
+                        (!in_lto_p
+                         || type_in_anonymous_namespace_p (class_type));
+                   hstate.add_hwi (TYPE_UID (TYPE_MAIN_VARIANT (class_type)));
+                 }
 
                m_items[i]->set_hash (hstate.end ());
             }
@@ -2684,6 +2573,21 @@ sem_item_optimizer::update_hash_by_addr_refs ()
     m_items[i]->set_hash (m_items[i]->global_hash);
 }
 
+void
+sem_item_optimizer::update_hash_by_memory_access_type ()
+{
+  for (unsigned i = 0; i < m_items.length (); i++)
+    {
+      if (m_items[i]->type == FUNC)
+       {
+         sem_function *fn = static_cast<sem_function *> (m_items[i]);
+         inchash::hash hstate (fn->get_hash ());
+         hstate.add_int (fn->m_alias_sets_hash);
+         fn->set_hash (hstate.end ());
+       }
+    }
+}
+
 /* Congruence classes are built by hash value.  */
 
 void
@@ -2755,15 +2659,18 @@ 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 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 ();
+       m_items[i]->init (&checker);
        ++counter;
       }
 
@@ -2772,6 +2679,8 @@ sem_item_optimizer::parse_nonsingleton_classes (void)
       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
@@ -3312,8 +3221,7 @@ sem_item_optimizer::dump_cong_classes (void)
           "class: %u)\n", (unsigned long) m_classes.elements (),
           m_items.length (), m_items.length () - single_element_classes);
   fprintf (dump_file,
-          "Class size histogram [num of members]: number of classe number "
-          "of classess\n");
+          "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, "%6u: %6u\n", i, histogram[i]);
@@ -3379,10 +3287,12 @@ sort_congruence_class_groups_by_decl_uid (const void *a, const void *b)
 /* 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;
@@ -3445,8 +3355,10 @@ 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);
     }
 
   unsigned int l;
@@ -3480,12 +3392,12 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
              {
                dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
                                 "Semantic equality hit:%s->%s\n",
-                                xstrdup_for_dump (source->node->name ()),
-                                xstrdup_for_dump (alias->node->name ()));
+                                source->node->dump_name (),
+                                alias->node->dump_name ());
                dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
                                 "Assembler symbol names:%s->%s\n",
-                                xstrdup_for_dump (source->node->asm_name ()),
-                                xstrdup_for_dump (alias->node->asm_name ()));
+                                source->node->dump_asm_name (),
+                                alias->node->dump_asm_name ());
              }
 
            if (lookup_attribute ("no_icf", DECL_ATTRIBUTES (alias->decl)))
@@ -3548,7 +3460,7 @@ set_alias_uids (symtab_node *n, int uid)
     {
       if (dump_file)
        fprintf (dump_file, "  Setting points-to UID of [%s] as %d\n",
-                xstrdup_for_dump (ref->referring->asm_name ()), uid);
+                ref->referring->dump_asm_name (), uid);
 
       SET_DECL_PT_UID (ref->referring->decl, uid);
       set_alias_uids (ref->referring, uid);
@@ -3577,7 +3489,7 @@ sem_item_optimizer::fixup_points_to_sets (void)
          fixup_pt_set (&SSA_NAME_PTR_INFO (name)->pt);
       fixup_pt_set (&fn->gimple_df->escaped);
 
-       /* The above get's us to 99% I guess, at least catching the
+       /* 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 ... */
@@ -3662,7 +3574,7 @@ ipa_icf_read_summary (void)
   optimizer->register_hooks ();
 }
 
-/* Semantic equality exection function.  */
+/* Semantic equality execution function.  */
 
 static unsigned int
 ipa_icf_driver (void)