From 8a76c4a040d2c601206ee24bd59b176d542c7f35 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 14 Jun 2011 16:59:52 +0200 Subject: [PATCH] re PR rtl-optimization/49390 (GCSE miscompilation) PR rtl-optimization/49390 Revert: 2010-06-29 Bernd Schmidt * cse.c (exp_equiv_p): For MEMs, if for_gcse, only compare MEM_ALIAS_SET. * gcc.c-torture/execute/pr49390.c: New test. From-SVN: r175023 --- gcc/ChangeLog | 9 ++ gcc/cse.c | 22 +++-- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.c-torture/execute/pr49390.c | 88 +++++++++++++++++++ 4 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr49390.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 80cd0a425d6..5a5fc837415 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2011-06-14 Jakub Jelinek + + PR rtl-optimization/49390 + Revert: + 2010-06-29 Bernd Schmidt + + * cse.c (exp_equiv_p): For MEMs, if for_gcse, only compare + MEM_ALIAS_SET. + 2011-06-14 Zdenek Dvorak Tom de Vries diff --git a/gcc/cse.c b/gcc/cse.c index cfa2b00216c..213b6083e7f 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -2669,16 +2669,26 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse) case MEM: if (for_gcse) { - /* Can't merge two expressions in different alias sets, since we - can decide that the expression is transparent in a block when - it isn't, due to it being set with the different alias set. */ - if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y)) - return 0; - /* A volatile mem should not be considered equivalent to any other. */ if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y)) return 0; + + /* Can't merge two expressions in different alias sets, since we + can decide that the expression is transparent in a block when + it isn't, due to it being set with the different alias set. + + Also, can't merge two expressions with different MEM_ATTRS. + They could e.g. be two different entities allocated into the + same space on the stack (see e.g. PR25130). In that case, the + MEM addresses can be the same, even though the two MEMs are + absolutely not equivalent. + + But because really all MEM attributes should be the same for + equivalent MEMs, we just use the invariant that MEMs that have + the same attributes share the same mem_attrs data structure. */ + if (MEM_ATTRS (x) != MEM_ATTRS (y)) + return 0; } break; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 300e0c52802..4b7610d926f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-06-14 Jakub Jelinek + + PR rtl-optimization/49390 + * gcc.c-torture/execute/pr49390.c: New test. + 2011-06-14 Rainer Orth * g++.dg/torture/pr48954.C: Use dg-require-effective-target lto. diff --git a/gcc/testsuite/gcc.c-torture/execute/pr49390.c b/gcc/testsuite/gcc.c-torture/execute/pr49390.c new file mode 100644 index 00000000000..dfcdea16fc0 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr49390.c @@ -0,0 +1,88 @@ +/* PR rtl-optimization/49390 */ + +struct S { unsigned int s1; unsigned int s2; }; +struct T { unsigned int t1; struct S t2; }; +struct U { unsigned short u1; unsigned short u2; }; +struct V { struct U v1; struct T v2; }; +struct S a; +char *b; +union { char b[64]; struct V v; } u; +volatile int v; +extern void abort (void); + +__attribute__((noinline, noclone)) void +foo (int x, void *y, unsigned int z, unsigned int w) +{ + if (x != 4 || y != (void *) &u.v.v2) + abort (); + v = z + w; + v = 16384; +} + +__attribute__((noinline, noclone)) void +bar (struct S x) +{ + v = x.s1; + v = x.s2; +} + +__attribute__((noinline, noclone)) int +baz (struct S *x) +{ + v = x->s1; + v = x->s2; + v = 0; + return v + 1; +} + +__attribute__((noinline, noclone)) void +test (struct S *c) +{ + struct T *d; + struct S e = a; + unsigned int f, g; + if (c == 0) + c = &e; + else + { + if (c->s2 % 8192 <= 15 || (8192 - c->s2 % 8192) <= 31) + foo (1, 0, c->s1, c->s2); + } + if (!baz (c)) + return; + g = (((struct U *) b)->u2 & 2) ? 32 : __builtin_offsetof (struct V, v2); + f = c->s2 % 8192; + if (f == 0) + { + e.s2 += g; + f = g; + } + else if (f < g) + { + foo (2, 0, c->s1, c->s2); + return; + } + if ((((struct U *) b)->u2 & 1) && f == g) + { + bar (*c); + foo (3, 0, c->s1, c->s2); + return; + } + d = (struct T *) (b + c->s2 % 8192); + if (d->t2.s1 >= c->s1 && (d->t2.s1 != c->s1 || d->t2.s2 >= c->s2)) + foo (4, d, c->s1, c->s2); + return; +} + +int +main () +{ + struct S *c = 0; + asm ("" : "+r" (c) : "r" (&a)); + u.v.v2.t2.s1 = 8192; + b = u.b; + test (c); + if (v != 16384) + abort (); + return 0; +} -- 2.30.2