On November 10, 2014 9:45:27 PM CET, Jakub Jelinek <ja...@redhat.com> wrote:
>Hi!
>
>As the following two testcases shows, there are lots of issues in
>ICF compare_gimple_call, in particular, it doesn't handle indirect
>calls
>properly (see the ipa-icf-31.c testcase), doesn't handle internal calls
>properly (see ubsan/ipa-icf-1.c), didn't check gimple_call flags at
>all.
>
>As discussed with Honza, the call chain test (from Martin) is probably
>insufficient, I'm open with leaving it out from the patch, but perhaps
>what the patch has is better than nothing at all for now.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
>2014-11-10  Jakub Jelinek  <ja...@redhat.com>
>           Martin Liska  <mli...@suse.cz>
>
>       * ipa-icf-gimple.c (func_checker::compare_bb): Fix comment typo.
>       (func_checker::compare_gimple_call): Compare gimple_call_fn,
>       gimple_call_chain, gimple_call_fntype and call flags.
>testsuite/
>       * gcc.dg/ubsan/ipa-icf-1.c: New test.
>       * gcc.dg/ipa/ipa-icf-31.c: New test.
>
>--- gcc/ipa-icf-gimple.c.jj    2014-10-30 14:42:20.000000000 +0100
>+++ gcc/ipa-icf-gimple.c       2014-11-10 19:08:38.339986360 +0100
>@@ -554,7 +554,7 @@ func_checker::parse_labels (sem_bb *bb)
> 
>In general, a collection of equivalence dictionaries is built for types
>like SSA names, declarations (VAR_DECL, PARM_DECL, ..). This
>infrastructure
>-   is utilized by every statement-by-stament comparison function.  */
>+   is utilized by every statement-by-statement comparison function. 
>*/
> 
> bool
> func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2)
>@@ -662,9 +662,49 @@ func_checker::compare_gimple_call (gimpl
>   t1 = gimple_call_fndecl (s1);
>   t2 = gimple_call_fndecl (s2);

Just drop these and compare gimple_call_fn only.

>-  /* Function pointer variables are not supported yet.  */
>   if (!compare_operand (t1, t2))
>-    return return_false();
>+    return return_false ();
>+
>+  if (t1 == NULL_TREE)
>+    {
>+      t1 = gimple_call_fn (s1);
>+      t2 = gimple_call_fn (s2);
>+      if (!compare_operand (t1, t2))
>+      return return_false ();
>+    }
>+
>+  /* Compare flags.  */
>+  if (gimple_call_internal_p (s1) != gimple_call_internal_p (s2)
>+      || gimple_call_ctrl_altering_p (s1) !=
>gimple_call_ctrl_altering_p (s2)
>+      || gimple_call_tail_p (s1) != gimple_call_tail_p (s2)
>+      || gimple_call_return_slot_opt_p (s1) !=
>gimple_call_return_slot_opt_p (s2)
>+      || gimple_call_from_thunk_p (s1) != gimple_call_from_thunk_p
>(s2)
>+      || gimple_call_va_arg_pack_p (s1) != gimple_call_va_arg_pack_p
>(s2)
>+      || gimple_call_alloca_for_var_p (s1) !=
>gimple_call_alloca_for_var_p (s2)
>+      || gimple_call_with_bounds_p (s1) != gimple_call_with_bounds_p
>(s2))
>+    return false;
>+
>+  if (gimple_call_internal_p (s1)
>+      && gimple_call_internal_fn (s1) != gimple_call_internal_fn (s2))
>+    return false;
>+
>+  tree fntype1 = gimple_call_fntype (s1);
>+  tree fntype2 = gimple_call_fntype (s2);
>+  if (fntype1 == NULL_TREE)
>+    {
>+      if (fntype2)
>+      return false;
>+    }
>+  else if (fntype2 == NULL_TREE)
>+    return false;
>+  else if (!types_compatible_p (fntype1, fntype2))
>+    return return_false_with_msg ("call function types are not
>compatible");
>+
>+  tree chain1 = gimple_call_chain (s1);
>+  tree chain2 = gimple_call_chain (s2);
>+
>+  if ((chain1 && !chain2) || (!chain1 && chain2))
>+    return return_false_with_msg ("Tree call chains are different");

I miss a compare_operands for the call chain.

Otherwise OK.

Thanks,
Richard.

>   /* Checking of argument.  */
>   for (i = 0; i < gimple_call_num_args (s1); ++i)
>--- gcc/testsuite/gcc.dg/ubsan/ipa-icf-1.c.jj  2014-11-10
>19:00:53.509525071 +0100
>+++ gcc/testsuite/gcc.dg/ubsan/ipa-icf-1.c     2014-11-10
>19:02:21.836925806 +0100
>@@ -0,0 +1,23 @@
>+/* { dg-do run } */
>+/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
>+/* { dg-options "-fsanitize=undefined -fipa-icf" } */
>+
>+__attribute__ ((noinline, noclone))
>+int f1 (int x, int y)
>+{
>+  return x + y;
>+}
>+
>+__attribute__ ((noinline, noclone))
>+int f2 (int x, int y)
>+{
>+  return x - y;
>+}
>+
>+int
>+main ()
>+{
>+  if (f1 (5, 6) != 11 || f2 (5, 6) != -1)
>+    __builtin_abort ();
>+  return 0;
>+}
>--- gcc/testsuite/gcc.dg/ipa/ipa-icf-31.c.jj   2014-11-10
>18:59:16.604294652 +0100
>+++ gcc/testsuite/gcc.dg/ipa/ipa-icf-31.c      2014-11-10 18:59:59.690519616
>+0100
>@@ -0,0 +1,41 @@
>+/* { dg-do run } */
>+/* { dg-options "-O2 -fipa-icf" } */
>+
>+__attribute__ ((noinline, noclone))
>+int f1 (int x, int (*p1) (void), int (*p2) (void))
>+{
>+  if (x)
>+    return p1 ();
>+  else
>+    return p2 ();
>+}
>+
>+__attribute__ ((noinline, noclone))
>+int f2 (int x, int (*p1) (void), int (*p2) (void))
>+{
>+  if (x)
>+    return p2 ();
>+  else
>+    return p1 ();
>+}
>+
>+__attribute__ ((noinline, noclone))
>+int f3 (void)
>+{
>+  return 1;
>+}
>+
>+__attribute__ ((noinline, noclone))
>+int f4 (void)
>+{
>+  return 2;
>+}
>+
>+int
>+main ()
>+{
>+  if (f1 (0, f3, f4) != 2 || f1 (1, f3, f4) != 1 || f2 (0, f3, f4) !=
>1
>+      || f2 (1, f3, f4) != 2)
>+    __builtin_abort ();
>+  return 0;
>+}
>
>       Jakub


Reply via email to