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