re PR lto/85574 (LTO bootstapped binaries differ)
[gcc.git] / gcc / ipa-icf.c
index 28de251c42129cd3633415acdd7a98b38ab791bb..ebaf5825e1e99c6a525b08793c986ae8e17c021e 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural Identical Code Folding pass
-   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+   Copyright (C) 2014-2019 Free Software Foundation, Inc.
 
    Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz>
 
@@ -74,7 +74,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 #include "symbol-summary.h"
 #include "ipa-prop.h"
-#include "ipa-inline.h"
+#include "ipa-fnsummary.h"
 #include "except.h"
 #include "attribs.h"
 #include "print-tree.h"
@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-icf.h"
 #include "stor-layout.h"
 #include "dbgcnt.h"
+#include "tree-vector-builder.h"
 
 using namespace ipa_icf_gimple;
 
@@ -195,8 +196,8 @@ 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: ");
 
@@ -226,6 +227,8 @@ void sem_item::set_hash (hashval_t 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)
@@ -286,11 +289,11 @@ sem_function::get_hash (void)
 
       /* 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_wide_int
+       hstate.add_hwi
         (cl_optimization_hash
           (TREE_OPTIMIZATION (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))));
       hstate.add_flag (DECL_CXX_CONSTRUCTOR_P (decl));
@@ -302,57 +305,6 @@ sem_function::get_hash (void)
   return m_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;
-    }
-  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;
-}
-
 /* 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
@@ -426,8 +378,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)
@@ -539,9 +491,8 @@ sem_function::param_used_p (unsigned int i)
 
   struct ipa_node_params *parms_info = IPA_NODE_REF (get_node ());
 
-  if (parms_info->descriptors.is_empty ()
-      || parms_info->descriptors.length () <= i)
-     return true;
+  if (vec_safe_length (parms_info->descriptors) <= i)
+    return true;
 
   return ipa_is_param_used (IPA_NODE_REF (get_node ()), i);
 }
@@ -591,6 +542,8 @@ 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)
@@ -658,7 +611,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))
        {
@@ -712,8 +665,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
@@ -870,13 +823,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;
@@ -1117,6 +1066,17 @@ sem_function::merge (sem_item *alias_item)
       return false;
     }
 
+  if (!original->in_same_comdat_group_p (alias)
+      || original->comdat_local_p ())
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "Not unifying; alias nor wrapper cannot be created; "
+                "across comdat group boundary\n\n");
+
+      return false;
+    }
+
   /* See if original is in a section that can be discarded if the main
      symbol is not used.  */
 
@@ -1191,8 +1151,9 @@ sem_function::merge (sem_item *alias_item)
            fprintf (dump_file,
                     "can not create wrapper of stdarg function.\n");
        }
-      else if (inline_summaries
-              && inline_summaries->get (alias)->self_size <= 2)
+      else if (ipa_fn_summaries
+              && ipa_fn_summaries->get (alias) != NULL
+              && ipa_fn_summaries->get (alias)->self_size <= 2)
        {
          if (dump_file)
            fprintf (dump_file, "Wrapper creation is not "
@@ -1213,8 +1174,7 @@ sem_function::merge (sem_item *alias_item)
         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,
@@ -1333,7 +1293,8 @@ sem_function::merge (sem_item *alias_item)
       alias->icf_merged = true;
       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);
 
       if (dump_file)
@@ -1426,6 +1387,7 @@ sem_function::init (void)
              }
          }
 
+       hstate.commit_flag ();
        gcode_hash = hstate.end ();
        bb_sizes.safe_push (nondbg_stmt_count);
 
@@ -1441,8 +1403,8 @@ 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);
@@ -1489,7 +1451,7 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate)
        unsigned HOST_WIDE_INT idx;
        tree value;
 
-       hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
+       hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
 
        FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
          if (value)
@@ -1504,7 +1466,7 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate)
     case VAR_DECL:
     case CONST_DECL:
     case PARM_DECL:
-      hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
+      hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
       break;
     case MEM_REF:
     case POINTER_PLUS_EXPR:
@@ -1522,7 +1484,7 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate)
       }
       break;
     CASE_CONVERT:
-      hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
+      hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
       return add_expr (TREE_OPERAND (exp, 0), hstate);
     default:
       break;
@@ -1571,8 +1533,14 @@ sem_item::add_type (const_tree type, inchash::hash &hstate)
     }
   else if (RECORD_OR_UNION_TYPE_P (type))
     {
-      gcc_checking_assert (COMPLETE_TYPE_P (type));
-      hashval_t *val = optimizer->m_type_hash_cache.get (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)
        {
@@ -1582,8 +1550,6 @@ sem_item::add_type (const_tree type, inchash::hash &hstate)
          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)
              {
@@ -1593,11 +1559,11 @@ sem_item::add_type (const_tree type, inchash::hash &hstate)
 
          hstate2.add_int (nf);
          hash = hstate2.end ();
-         hstate.add_wide_int (hash);
-         optimizer->m_type_hash_cache.put (type, hash);
+         hstate.add_hwi (hash);
+         m_type_hash_cache.put (type, hash);
        }
       else
-        hstate.add_wide_int (*val);
+        hstate.add_hwi (*val);
     }
 }
 
@@ -1648,6 +1614,11 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &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)));
     default:
       break;
     }
@@ -1888,12 +1859,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;
 }
@@ -1968,8 +1936,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:
@@ -2025,17 +1993,17 @@ sem_variable::equals (tree t1, tree t2)
                                                &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:
@@ -2115,30 +2083,13 @@ sem_variable::get_hash (void)
 
   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)));
+    hstate.add_hwi (tree_to_shwi (DECL_SIZE (decl)));
   add_expr (ctor, hstate);
   set_hash (hstate.end ());
 
   return m_hash;
 }
 
-/* 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",
-                xstrdup_for_dump (ref->referring->asm_name ()), uid);
-
-      SET_DECL_PT_UID (ref->referring->decl, uid);
-      set_alias_uids (ref->referring, uid);
-    }
-}
-
 /* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
    be applied.  */
 
@@ -2265,7 +2216,6 @@ sem_variable::merge (sem_item *alias_item)
       if (dump_file)
        fprintf (dump_file, "Unified; Variable alias has been created.\n");
 
-      set_alias_uids (original, DECL_UID (original->decl));
       return true;
     }
 }
@@ -2285,7 +2235,7 @@ 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)
+  m_varpool_node_hooks (NULL), m_merged_variables ()
 {
   m_items.create (0);
   bitmap_obstack_initialize (&m_bmstack);
@@ -2310,6 +2260,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.  */
@@ -2399,8 +2350,8 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
       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);
+       fprintf (dump_file, "Symbol added: %s (tree: %p)\n",
+                node->dump_asm_name (), (void *) node->decl);
 
       if (is_a<cgraph_node *> (node))
        {
@@ -2644,7 +2595,7 @@ sem_item_optimizer::execute (void)
   bool merged_p = merge_classes (prev_class_count);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    symtab_node::dump_table (dump_file);
+    symtab->dump (dump_file);
 
   return merged_p;
 }
@@ -2727,7 +2678,7 @@ sem_item_optimizer::update_hash_by_addr_refs ()
 
                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))));
 
@@ -3166,6 +3117,22 @@ sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
   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.  */
 
@@ -3206,13 +3173,20 @@ sem_item_optimizer::do_congruence_step_for_index (congruence_class *cls,
        }
     }
 
+  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);
+  for (unsigned i = 0; i < to_split.length (); ++i)
+    traverse_congruence_split (to_split[i].first, to_split[i].second, &pair);
 
   /* Bitmap clean-up.  */
   split_map.traverse <traverse_split_pair *,
@@ -3380,6 +3354,66 @@ 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);
+
+  if (uid1 < uid2)
+    return -1;
+  else if (uid1 > uid2)
+    return 1;
+  else
+    return 0;
+}
+
+/* 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);
+
+  if (uid1 < uid2)
+    return -1;
+  else if (uid1 > uid2)
+    return 1;
+  else
+    return 0;
+}
+
+/* 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 congruence_class_group *g1
+    = *(const congruence_class_group * const *)a;
+  const congruence_class_group *g2
+    = *(const congruence_class_group * const *)b;
+
+  int uid1 = DECL_UID (g1->classes[0]->members[0]->decl);
+  int uid2 = DECL_UID (g2->classes[0]->members[0]->decl);
+
+  if (uid1 < uid2)
+    return -1;
+  else if (uid1 > uid2)
+    return 1;
+  else
+    return 0;
+}
+
 /* 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
@@ -3397,6 +3431,22 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
 
   bool merged_p = false;
 
+  /* 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++)
@@ -3409,6 +3459,13 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
          }
       }
 
+  auto_vec <congruence_class_group *> classes (m_classes.elements ());
+  for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
+       it != m_classes.end (); ++it)
+    classes.quick_push (*it);
+
+  classes.qsort (sort_congruence_class_groups_by_decl_uid);
+
   if (dump_file)
     {
       fprintf (dump_file, "\nItem count: %u\n", item_count);
@@ -3426,11 +3483,12 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count)
               item_count ? 100.0f * equal_items / item_count : 0.0f);
     }
 
-  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++)
+  unsigned int l;
+  congruence_class_group *it;
+  FOR_EACH_VEC_ELT (classes, l, it)
+    for (unsigned int i = 0; i < it->classes.length (); i++)
       {
-       congruence_class *c = (*it)->classes[i];
+       congruence_class *c = it->classes[i];
 
        if (c->members.length () == 1)
          continue;
@@ -3477,13 +3535,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",
+                xstrdup_for_dump (ref->referring->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 get's 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
@@ -3494,9 +3642,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");
 }