Hi, here is a variant of patch I intend to commit after x86_64 bootstrap®test 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);