Hi!

We tail merge
  a = bar (7);
with
  *x = bar (7);
completely ignoring the case that the lhs are different.
IMHO we can't merge if one of the calls has lhs and the other doesn't,
or if both calls have non-SSA_NAME lhs and they aren't equal (this case).
If both calls have SSA_NAME lhs, I can see why it might be nice to tail
merge both if the calls have the same argument same destination even when
the lhs don't valueize the same (sccvn will value number the same just
pure/const calls, right), but I don't see how it can actually work,
the SSA_NAMEs will be used somewhere later on in the BB or in the PHI,
and there we compare vn_valueize anyway.  We'd need to somehow mark
those two SSA_NAMEs as equivalent for further VN.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2012-01-17  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/51877
        * tree-ssa-tail-merge.c (gimple_equal_p): Don't return true whenever
        call arguments and fndecls compare equal, instead return false if they
        don't.  Return true only if lhs1 and lhs2 are either both NULL, or
        both SSA_NAMEs that are valueized the same, or they satisfy
        operand_equal_p.

        * gcc.c-torture/execute/pr51877.c: New test.

--- gcc/tree-ssa-tail-merge.c.jj        2011-12-12 22:10:26.000000000 +0100
+++ gcc/tree-ssa-tail-merge.c   2012-01-17 08:28:56.903471558 +0100
@@ -1071,14 +1071,18 @@ gimple_equal_p (same_succ same_succ, gim
          equal = false;
          break;
        }
-      if (equal)
-       return true;
+      if (!equal)
+       return false;
 
       lhs1 = gimple_get_lhs (s1);
       lhs2 = gimple_get_lhs (s2);
-      return (lhs1 != NULL_TREE && lhs2 != NULL_TREE
-             && TREE_CODE (lhs1) == SSA_NAME && TREE_CODE (lhs2) == SSA_NAME
-             && vn_valueize (lhs1) == vn_valueize (lhs2));
+      if (lhs1 == NULL_TREE && lhs2 == NULL_TREE)
+       return true;
+      if (lhs1 == NULL_TREE || lhs2 == NULL_TREE)
+       return false;
+      if (TREE_CODE (lhs1) == SSA_NAME && TREE_CODE (lhs2) == SSA_NAME)
+       return vn_valueize (lhs1) == vn_valueize (lhs2);
+      return operand_equal_p (lhs1, lhs2, 0);
 
     case GIMPLE_ASSIGN:
       lhs1 = gimple_get_lhs (s1);
--- gcc/testsuite/gcc.c-torture/execute/pr51877.c.jj    2012-01-17 
08:36:31.012781551 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr51877.c       2012-01-17 
08:35:26.000000000 +0100
@@ -0,0 +1,50 @@
+/* PR tree-optimization/51877 */
+
+extern void abort (void);
+struct A { int a; char b[32]; } a, b;
+
+__attribute__((noinline, noclone))
+struct A
+bar (int x)
+{
+  struct A r;
+  static int n;
+  r.a = ++n;
+  __builtin_memset (r.b, 0, sizeof (r.b));
+  r.b[0] = x;
+  return r;
+}
+
+__attribute__((noinline, noclone))
+void
+baz (void)
+{
+  asm volatile ("" : : : "memory");
+}
+
+__attribute__((noinline, noclone))
+void
+foo (struct A *x, int y)
+{
+  if (y == 6)
+    a = bar (7);
+  else
+    *x = bar (7);
+  baz ();
+}
+
+int
+main ()
+{
+  a = bar (3);
+  b = bar (4);
+  if (a.a != 1 || a.b[0] != 3 || b.a != 2 || b.b[0] != 4)
+    abort ();
+  foo (&b, 0);
+  if (a.a != 1 || a.b[0] != 3 || b.a != 3 || b.b[0] != 7)
+    abort ();
+  foo (&b, 6);
+  if (a.a != 4 || a.b[0] != 7 || b.a != 3 || b.b[0] != 7)
+    abort ();
+  return 0;
+}

        Jakub

Reply via email to