Hi,
here is a variant of patch I intend to commit after x86_64 bootstrap&regtest
and LTO-bootstrap.  What i changed are the ipa-icf-gimple.c bits (dorpping all
comparsions relying that external references are already matched and used at
same spots). Second change is sem_function::compare_cgraph_references doing
right thing wrt reference type.

I think as an optimization sem_item_optimizer::build_graph can drop all
interposable references, because they are already handled earlier as sensitive
and cgraph references.

Honza

2015-02-28  Martin Liska  <mli...@suse.cz>
            Jan Hubicka   <hubi...@ucw.cz>

        PR ipa/65245
        * ipa-icf-gimple.c (func_checker::compare_function_decl):
        Remove.
        (func_checker::compare_variable_decl): Skip symtab vars.
        (func_checker::compare_cst_or_decl): Update.
        * ipa-icf.c (sem_function::parse): Do not consider aliases.
        (sem_function::compare_cgraph_references): Add ADDRESS parameter;
        use correct symtab predicates.
        (sem_function::equals_wpa): Update uses of compare_cgraph_references.
        (sem_variable::parse):  Update comment.
        (sem_item_optimizer::build_graph): Consider ultimate aliases
        for references.

gcc/testsuite/ChangeLog:

2015-02-28  Martin Liska  <mli...@suse.cz>
            Jan Hubicka   <hubi...@ucw.cz>

        PR ipa/65245
        * gcc.dg/ipa/ipa-icf-34.c: New test.

Index: ipa-icf.c
===================================================================
--- ipa-icf.c   (revision 221089)
+++ ipa-icf.c   (working copy)
@@ -335,17 +335,26 @@ sem_function::get_hash (void)
 
 /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs
    point to a same function. Comparison can be skipped if IGNORED_NODES
-   contains these nodes.  */
+   contains these nodes.  ADDRESS indicate if address is taken.  */
 
 bool
-sem_function::compare_cgraph_references (hash_map <symtab_node *, sem_item *>
-    &ignored_nodes,
-    symtab_node *n1, symtab_node *n2)
+sem_function::compare_cgraph_references (
+    hash_map <symtab_node *, sem_item *> &ignored_nodes,
+    symtab_node *n1, symtab_node *n2, bool address)
 {
-  if (n1 == n2 || (ignored_nodes.get (n1) && ignored_nodes.get (n2)))
+  enum availability avail1, avail2;
+
+  if (address && n1->equal_address_to (n2) == 1)
+    return true;
+  if (!address && n1->semantically_equivalent_p (n2))
     return true;
 
-  /* TODO: add more precise comparison for weakrefs, etc.  */
+  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))
+    return true;
 
   return return_false_with_msg ("different references");
 }
@@ -412,7 +421,9 @@ sem_function::equals_wpa (sem_item *item
     {
       item->node->iterate_reference (i, ref2);
 
-      if (!compare_cgraph_references (ignored_nodes, ref->referred, 
ref2->referred))
+      if (!compare_cgraph_references (ignored_nodes, ref->referred,
+                                     ref2->referred,
+                                     ref->address_matters_p ()))
        return false;
     }
 
@@ -421,7 +432,8 @@ sem_function::equals_wpa (sem_item *item
 
   while (e1 && e2)
     {
-      if (!compare_cgraph_references (ignored_nodes, e1->callee, e2->callee))
+      if (!compare_cgraph_references (ignored_nodes, e1->callee,
+                                     e2->callee, false))
        return false;
 
       e1 = e1->next_callee;
@@ -1117,7 +1129,7 @@ sem_function::parse (cgraph_node *node,
   tree fndecl = node->decl;
   function *func = DECL_STRUCT_FUNCTION (fndecl);
 
-  /* TODO: add support for thunks and aliases.  */
+  /* TODO: add support for thunks.  */
 
   if (!func || !node->has_gimple_body_p ())
     return NULL;
@@ -1429,6 +1441,9 @@ sem_variable::parse (varpool_node *node,
 {
   tree decl = node->decl;
 
+  if (node->alias)
+    return NULL;
+
   bool readonly = TYPE_P (decl) ? TYPE_READONLY (decl) : TREE_READONLY (decl);
   if (!readonly)
     return NULL;
@@ -2086,7 +2101,8 @@ sem_item_optimizer::build_graph (void)
          cgraph_edge *e = cnode->callees;
          while (e)
            {
-             sem_item **slot = m_symtab_node_map.get (e->callee);
+             sem_item **slot = m_symtab_node_map.get
+               (e->callee->ultimate_alias_target ());
              if (slot)
                item->add_reference (*slot);
 
@@ -2097,7 +2113,8 @@ sem_item_optimizer::build_graph (void)
       ipa_ref *ref = NULL;
       for (unsigned i = 0; item->node->iterate_reference (i, ref); i++)
        {
-         sem_item **slot = m_symtab_node_map.get (ref->referred);
+         sem_item **slot = m_symtab_node_map.get
+           (ref->referred->ultimate_alias_target ());
          if (slot)
            item->add_reference (*slot);
        }
Index: ipa-icf.h
===================================================================
--- ipa-icf.h   (revision 221089)
+++ ipa-icf.h   (working copy)
@@ -353,10 +353,11 @@ private:
 
   /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs
      point to a same function. Comparison can be skipped if IGNORED_NODES
-     contains these nodes.  */
+     contains these nodes.  ADDRESS indicate if address is taken.  */
   bool compare_cgraph_references (hash_map <symtab_node *, sem_item *>
                                  &ignored_nodes,
-                                 symtab_node *n1, symtab_node *n2);
+                                 symtab_node *n1, symtab_node *n2,
+                                 bool address);
 
   /* Processes function equality comparison.  */
   bool equals_private (sem_item *item,
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c  (revision 221089)
+++ config/i386/i386.c  (working copy)
@@ -10061,6 +10061,13 @@ ix86_compute_frame_layout (struct ix86_f
       if (crtl->stack_alignment_needed < PREFERRED_STACK_BOUNDARY)
        crtl->stack_alignment_needed = PREFERRED_STACK_BOUNDARY;
     }
+  /* Be sure we get stack aligned for mcount call.  */
+  else if (crtl->profile && flag_fentry)
+    {
+      crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+      if (crtl->stack_alignment_needed < PREFERRED_STACK_BOUNDARY)
+       crtl->stack_alignment_needed = PREFERRED_STACK_BOUNDARY;
+    }
 
   stack_alignment_needed = crtl->stack_alignment_needed / BITS_PER_UNIT;
   preferred_alignment = crtl->preferred_stack_boundary / BITS_PER_UNIT;
Index: config/i386/darwin.h
===================================================================
--- config/i386/darwin.h        (revision 221089)
+++ config/i386/darwin.h        (working copy)
@@ -210,6 +210,8 @@ extern int darwin_emit_branch_islands;
 #undef FUNCTION_PROFILER
 #define FUNCTION_PROFILER(FILE, LABELNO)                               \
     do {                                                               \
+      if (!ACCUMULATE_OUTGOING_ARGS)                                   \
+        fprintf (FILE, "\tpushl %%ebx\n");  /*  Align stack  */                
\
       if (TARGET_MACHO_BRANCH_ISLANDS                                  \
           && MACHOPIC_INDIRECT && !TARGET_64BIT)                       \
        {                                                               \
@@ -218,6 +220,8 @@ extern int darwin_emit_branch_islands;
          machopic_validate_stub_or_non_lazy_ptr (name);                \
        }                                                               \
       else fprintf (FILE, "\tcall mcount\n");                          \
+      if (!ACCUMULATE_OUTGOING_ARGS)                                   \
+       fprintf (FILE, "\tpopl %%ebx\n");  /*  Align stack  */          \
     } while (0)
 
 #define C_COMMON_OVERRIDE_OPTIONS                                      \
Index: testsuite/gcc.dg/ipa/ipa-icf-34.c
===================================================================
--- testsuite/gcc.dg/ipa/ipa-icf-34.c   (revision 0)
+++ testsuite/gcc.dg/ipa/ipa-icf-34.c   (revision 0)
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fipa-icf -fdump-ipa-icf"  } */
+
+static int do_work(void)
+{
+  return 0;
+}
+
+static int foo() __attribute__((alias("do_work")));
+static int bar() __attribute__((alias("do_work")));
+
+static int a()
+{
+  return foo();
+}
+
+static int b()
+{
+  return bar();
+}
+
+int main()
+{
+  return a() + b();
+}
+
+/* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf"  } } */
+/* { dg-final { cleanup-ipa-dump "icf" } } */
Index: ipa-icf-gimple.c
===================================================================
--- ipa-icf-gimple.c    (revision 221089)
+++ ipa-icf-gimple.c    (working copy)
@@ -312,10 +312,9 @@ func_checker::compare_cst_or_decl (tree
        return return_with_debug (ret);
       }
     case FUNCTION_DECL:
-      {
-       ret = compare_function_decl (t1, t2);
-       return return_with_debug (ret);
-      }
+      /* All function decls are in the symbol table and known to match
+        before we start comparing bodies.  */
+      return true;
     case VAR_DECL:
       return return_with_debug (compare_variable_decl (t1, t2));
     case FIELD_DECL:
@@ -537,39 +536,6 @@ func_checker::compare_tree_list_operand
   return true;
 }
 
-/* Verifies that trees T1 and T2, representing function declarations
-   are equivalent from perspective of ICF.  */
-
-bool
-func_checker::compare_function_decl (tree t1, tree t2)
-{
-  bool ret = false;
-
-  if (t1 == t2)
-    return true;
-
-  symtab_node *n1 = symtab_node::get (t1);
-  symtab_node *n2 = symtab_node::get (t2);
-
-  if (m_ignored_source_nodes != NULL && m_ignored_target_nodes != NULL)
-    {
-      ret = m_ignored_source_nodes->contains (n1)
-           && m_ignored_target_nodes->contains (n2);
-
-      if (ret)
-       return true;
-    }
-
-  /* If function decl is WEAKREF, we compare targets.  */
-  cgraph_node *f1 = cgraph_node::get (t1);
-  cgraph_node *f2 = cgraph_node::get (t2);
-
-  if(f1 && f2 && f1->weakref && f2->weakref)
-    ret = f1->alias_target == f2->alias_target;
-
-  return ret;
-}
-
 /* Verifies that trees T1 and T2 do correspond.  */
 
 bool
@@ -590,20 +556,10 @@ func_checker::compare_variable_decl (tre
       && DECL_ASSEMBLER_NAME (t1) != DECL_ASSEMBLER_NAME (t2))
     return return_false_with_msg ("HARD REGISTERS are different");
 
-  if (TREE_CODE (t1) == VAR_DECL && (DECL_EXTERNAL (t1) || TREE_STATIC (t1)))
-    {
-      symtab_node *n1 = symtab_node::get (t1);
-      symtab_node *n2 = symtab_node::get (t2);
-
-      if (m_ignored_source_nodes != NULL && m_ignored_target_nodes != NULL)
-       {
-         ret = m_ignored_source_nodes->contains (n1)
-               && m_ignored_target_nodes->contains (n2);
-
-         if (ret)
-           return true;
-       }
-    }
+  /* Symbol table variables are known to match before we start comparing
+     bodies.  */
+  if (decl_in_symtab_p (t1))
+    return decl_in_symtab_p (t2);
   ret = compare_decl (t1, t2);
 
   return return_with_debug (ret);

Reply via email to