Hi,
this is on ipa-icf-gimple.c

@@ -2827,11 +2829,19 @@ cgraph_node::verify_node (void)
                            {
                              if (verify_edge_corresponds_to_fndecl (e, decl))
                                {
-                                 error ("edge points to wrong declaration:");
-                                 debug_tree (e->callee->decl);
-                                 fprintf (stderr," Instead of:");
-                                 debug_tree (decl);
-                                 error_found = true;
+                                 /* The edge can be redirected in WPA by IPA 
ICF.
+                                    Following check really ensures that it's
+                                    not the case.  */
+
+                                 cgraph_node *current_node = cgraph_node::get 
(decl);
+                                 if (!current_node || 
!current_node->icf_merged)

I would move this into verify_edge_corresponds_to_fndecl.

diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c
new file mode 100644
index 0000000..7031eaa
--- /dev/null
+++ b/gcc/ipa-icf-gimple.c
@@ -0,0 +1,384 @@
+/* Interprocedural Identical Code Folding pass
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   Contributed by Jan Hubicka <hubi...@ucw.cz> and Martin Liska 
<mli...@suse.cz>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */

Please add toplevel comment about what the code does and how to use it.

+namespace ipa_icf {
+
+/* Basic block equivalence comparison function that returns true if
+   basic blocks BB1 and BB2 (from functions FUNC1 and FUNC2) correspond.  */
... to each other?
I would add short comment that as comparsion goes you build voclabulary
of equivalences of variables/ssanames etc.
So people reading the code do not get lost at very beggining.

+
+bool
+func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2)
+{
+  unsigned i;
+  gimple_stmt_iterator gsi1, gsi2;
+  gimple s1, s2;
+
+  if (bb1->nondbg_stmt_count != bb2->nondbg_stmt_count
+      || bb1->edge_count != bb2->edge_count)
+    return RETURN_FALSE ();

The UPPERCASE looks ugly.  I see that RETURN_FALSE is a warpper for 
return_false_with_msg
that outputs line and file information.

I would make it lowercase even if it is macro. You may consider using
CXX_MEM_STAT_INFO style default argument to avoid function macro completely.
Probably not big win given that it won't save you from preprocesor mess.
+
+  gsi1 = gsi_start_bb (bb1->bb);
+  gsi2 = gsi_start_bb (bb2->bb);
+
+  for (i = 0; i < bb1->nondbg_stmt_count; i++)
+    {
+      if (is_gimple_debug (gsi_stmt (gsi1)))
+       gsi_next_nondebug (&gsi1);
+
+      if (is_gimple_debug (gsi_stmt (gsi2)))
+       gsi_next_nondebug (&gsi2);
+
+      s1 = gsi_stmt (gsi1);
+      s2 = gsi_stmt (gsi2);
+
+      if (gimple_code (s1) != gimple_code (s2))
+       return RETURN_FALSE_WITH_MSG ("gimple codes are different");

I think you need to compare EH here.  Consider case where one unit
is compiled with -fno-exception and thus all EH regions are removed,
while other function has EH regions in it.  Those are not equivalent.

EH region is obtained by lookup_stmt_eh and then you need to comapre
them for match as you do with gimple_resx_regoin.

+  t1 = gimple_call_fndecl (s1);
+  t2 = gimple_call_fndecl (s2);
+
+  /* Function pointer variables are not supported yet.  */

They seems to be, compare_operand seems just right.

+
+/* Verifies for given GIMPLEs S1 and S2 that
+   label statements are semantically equivalent.  */
+
+bool
+func_checker::compare_gimple_label (gimple g1, gimple g2)
+{
+  if (m_ignore_labels)
+    return true;
+
+  tree t1 = gimple_label_label (g1);
+  tree t2 = gimple_label_label (g2);
+
+  return compare_tree_ssa_label (t1, t2);
+}

I would expect the main BB loop to record BB in which label belongs to
and the BB assciatio neing checked here.
Otherwise I do not see how switch statements are compared to not have
different permutations of targets. Also note that one BB may have
multiple labels in them and they are equivalent.

Also I would punt on occurence of FORCED_LABEL. Those are tricky as they
may be passed around and compared for address and no one really defines
what should happen.  Better to avoid those.

+
+/* Verifies for given GIMPLEs S1 and S2 that
+   switch statements are semantically equivalent.  */
+
+bool
+func_checker::compare_gimple_switch (gimple g1, gimple g2)
+{
+  unsigned lsize1, lsize2, i;
+  tree t1, t2, low1, low2, high1, high2;
+
+  lsize1 = gimple_switch_num_labels (g1);
+  lsize2 = gimple_switch_num_labels (g2);
+
+  if (lsize1 != lsize2)
+    return false;
+
+  t1 = gimple_switch_index (g1);
+  t2 = gimple_switch_index (g2);
+
+  if (TREE_CODE (t1) != SSA_NAME || TREE_CODE(t2) != SSA_NAME)
+    return false;

Why non-SSA_NAMES are excluded? I see that constants should be optimized out,
but I do not see a need for specific test here.
+
+  if (!compare_operand (t1, t2))
+    return false;
+
+  for (i = 0; i < lsize1; i++)
+    {
+      low1 = CASE_LOW (gimple_switch_label (g1, i));
+      low2 = CASE_LOW (gimple_switch_label (g2, i));
+
+      if ((low1 != NULL) != (low2 != NULL)
+         || (low1 && low2 && TREE_INT_CST_LOW (low1) != TREE_INT_CST_LOW 
(low2)))
+       return false;

You want to compare integers for equivality.  Just use tree_int_cst_equal.
+
+      high1 = CASE_HIGH (gimple_switch_label (g1, i));
+      high2 = CASE_HIGH (gimple_switch_label (g2, i));
+
+      if ((high1 != NULL) != (high2 != NULL)
+         || (high1 && high2
+             && TREE_INT_CST_LOW (high1) != TREE_INT_CST_LOW (high2)))
+       return false;

Same here.
+    }
+
+  return true;
+}
+
+/* Verifies for given GIMPLEs S1 and S2 that
+   return statements are semantically equivalent.  */
+
+bool
+func_checker::compare_gimple_return (gimple g1, gimple g2)
+{
+  tree t1, t2;
+
+  t1 = gimple_return_retval (g1);
+  t2 = gimple_return_retval (g2);
+
+  /* Void return type.  */
+  if (t1 == NULL && t2 == NULL)
+    return true;
+  else
+    return compare_operand (t1, t2);

Do you check somewhere DECL_BY_REFERENCE (DECL_RESULT (struct function))? Those 
needs to match, too.
Perhaps it is always the case that SSA form differs, but I would test it.
+}
+
+/* Verifies for given GIMPLEs S1 and S2 that
+   goto statements are semantically equivalent.  */
+
+bool
+func_checker::compare_gimple_goto (gimple g1, gimple g2)
+{
+  tree dest1, dest2;
+
+  dest1 = gimple_goto_dest (g1);
+  dest2 = gimple_goto_dest (g2);
+
+  if (TREE_CODE (dest1) != TREE_CODE (dest2) || TREE_CODE (dest1) != SSA_NAME)
+    return false;
+
+  return compare_operand (dest1, dest2);

You probably need to care only about indirect gotos, the direct ones are 
checked by
CFG compare.  So is the condtional jump.
+
+/* Verifies for given GIMPLEs S1 and S2 that ASM statements are equivalent.
+   For the beginning, the pass only supports equality for
+   '__asm__ __volatile__ ("", "", "", "memory")'.  */
+
+bool
+func_checker::compare_gimple_asm (gimple g1, gimple g2)
+{
+  if (gimple_asm_volatile_p (g1) != gimple_asm_volatile_p (g2))
+    return false;
+
+  if (gimple_asm_ninputs (g1) || gimple_asm_ninputs (g2))
+    return false;
+
+  if (gimple_asm_noutputs (g1) || gimple_asm_noutputs (g2))
+    return false;
+
+  if (gimple_asm_nlabels (g1) || gimple_asm_nlabels (g2))
+    return false;
+
+  if (gimple_asm_nclobbers (g1) != gimple_asm_nclobbers (g2))
+    return false;
+
+  for (unsigned i = 0; i < gimple_asm_nclobbers (g1); i++)
+    {
+      tree clobber1 = TREE_VALUE (gimple_asm_clobber_op (g1, i));
+      tree clobber2 = TREE_VALUE (gimple_asm_clobber_op (g2, i));
+
+      if (!operand_equal_p (clobber1, clobber2, OEP_ONLY_CONST))
+       return false;
+    }
+

Even asm statements with no inputs or outputs can differ by the actual
asm statement. Compare it too.

Comparing inputs/outputs/labels should be very easy to do.

Compare all gimple_asm_n* for equivalency.
At the end walk operands and watch the case they are TREE_LIST.
THen compare TREE_VALUE (op) of the list for operand_equal_p
and TREE_VALUE (TREE_PURPOSE (op)) for equivalency
(those are the constraints)

If they are not (clobbers are not, those are just strings), operand_equal_p
should do.

+  return true;
+}
+
+} // ipa_icf namespace

Otherwise I think ipa-gimple-icf is quite fine now.
Please send updated version and I think it can go to mainline before the actual 
ipa-icf.

Reply via email to