From 2d698d3bb7f1b7761b35b31326a0326ce375ef8e Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Thu, 12 Aug 2010 10:38:05 +0000 Subject: [PATCH] re PR tree-optimization/45232 (tree reassociation introduces undefined overflow) 2010-08-12 Richard Guenther PR tree-optimization/45232 * tree-ssa-reassoc.c (can_reassociate_p): Disable re-association for types with undefined overflow. (reassociate_bb): Allow re-associating of bit and min/max operations for types with undefined overflow. * tree-ssa-forwprop.c (associate_plusminus): New function. (tree_ssa_forward_propagate_single_use_vars): Call it. * gcc.dg/tree-ssa/pr44133.c: Adjust warning location. * gcc.dg/tree-ssa/loop-7.c: Adjust. * gcc.dg/tree-ssa/reassoc-1.c: XFAIL. * gcc.dg/tree-ssa/reassoc-20.c: Add reassoc-1.c variant with unsigned arithmetic. * gcc.dg/tree-ssa/reassoc-14.c: Use unsigned arithmetic. * gcc.dg/tree-ssa/reassoc-15.c: Likewise. * gcc.dg/tree-ssa/reassoc-18.c: Likewise. * gcc.dg/tree-ssa/reassoc-2.c: XFAIL. * gcc.dg/tree-ssa/reassoc-21.c: Add reassoc-2.c variant with unsigned arithmetic. * gcc.dg/tree-ssa/reassoc-6.c: XFAIL. * gcc.dg/tree-ssa/reassoc-22.c: Add reassoc-6.c variant with unsigned arithmetic. * gcc.dg/tree-ssa/reassoc-7.c: Use unsigned arithmetic. * gcc.dg/tree-ssa/reassoc-9.c: XFAIL. * gcc.dg/tree-ssa/reassoc-23.c: Add reassoc-9.c variant with unsigned arithmetic. * gcc.dg/tree-ssa/ssa-pre-2.c: Adjust. * gcc.dg/tree-ssa/negate.c: Adjust. * gcc.dg/vect/vect-1.c: Adjust. * gfortran.dg/reassoc_6.f: XFAIL. From-SVN: r163190 --- gcc/ChangeLog | 10 + gcc/testsuite/ChangeLog | 26 ++ gcc/testsuite/gcc.dg/tree-ssa/loop-7.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/negate.c | 11 +- gcc/testsuite/gcc.dg/tree-ssa/pr44133.c | 4 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-1.c | 9 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-14.c | 18 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-15.c | 16 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-18.c | 6 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-2.c | 5 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-20.c | 20 ++ gcc/testsuite/gcc.dg/tree-ssa/reassoc-21.c | 19 ++ gcc/testsuite/gcc.dg/tree-ssa/reassoc-22.c | 13 + gcc/testsuite/gcc.dg/tree-ssa/reassoc-23.c | 17 ++ gcc/testsuite/gcc.dg/tree-ssa/reassoc-6.c | 4 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-7.c | 10 +- gcc/testsuite/gcc.dg/tree-ssa/reassoc-9.c | 6 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c | 8 +- gcc/testsuite/gcc.dg/vect/vect-1.c | 9 +- gcc/testsuite/gfortran.dg/reassoc_6.f | 4 +- gcc/tree-ssa-forwprop.c | 287 +++++++++++++++++++++ gcc/tree-ssa-reassoc.c | 15 +- 22 files changed, 475 insertions(+), 44 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-20.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-21.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-22.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/reassoc-23.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 61b30e9f751..8e062b9d55a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2010-08-12 Richard Guenther + + PR tree-optimization/45232 + * tree-ssa-reassoc.c (can_reassociate_p): Disable re-association + for types with undefined overflow. + (reassociate_bb): Allow re-associating of bit and min/max + operations for types with undefined overflow. + * tree-ssa-forwprop.c (associate_plusminus): New function. + (tree_ssa_forward_propagate_single_use_vars): Call it. + 2010-08-12 Richard Guenther * tree-flow.h (struct ptr_info_def): Add align and misalign fields. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 84bd311b899..28a6805ffe5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,29 @@ +2010-08-12 Richard Guenther + + PR tree-optimization/45232 + * gcc.dg/tree-ssa/pr44133.c: Adjust warning location. + * gcc.dg/tree-ssa/loop-7.c: Adjust. + * gcc.dg/tree-ssa/reassoc-1.c: XFAIL. + * gcc.dg/tree-ssa/reassoc-20.c: Add reassoc-1.c variant with + unsigned arithmetic. + * gcc.dg/tree-ssa/reassoc-14.c: Use unsigned arithmetic. + * gcc.dg/tree-ssa/reassoc-15.c: Likewise. + * gcc.dg/tree-ssa/reassoc-18.c: Likewise. + * gcc.dg/tree-ssa/reassoc-2.c: XFAIL. + * gcc.dg/tree-ssa/reassoc-21.c: Add reassoc-2.c variant with + unsigned arithmetic. + * gcc.dg/tree-ssa/reassoc-6.c: XFAIL. + * gcc.dg/tree-ssa/reassoc-22.c: Add reassoc-6.c variant with + unsigned arithmetic. + * gcc.dg/tree-ssa/reassoc-7.c: Use unsigned arithmetic. + * gcc.dg/tree-ssa/reassoc-9.c: XFAIL. + * gcc.dg/tree-ssa/reassoc-23.c: Add reassoc-9.c variant with + unsigned arithmetic. + * gcc.dg/tree-ssa/ssa-pre-2.c: Adjust. + * gcc.dg/tree-ssa/negate.c: Adjust. + * gcc.dg/vect/vect-1.c: Adjust. + * gfortran.dg/reassoc_6.f: XFAIL. + 2010-08-12 Jakub Jelinek PR debug/45259 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-7.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-7.c index e9e8d7d23ac..ab4a5026f2e 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/loop-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-7.c @@ -31,5 +31,5 @@ int xxx (void) Calls to cst_fun2 and pure_fun2 should not be, since calling with k = 0 may be invalid. */ -/* { dg-final { scan-tree-dump-times "Moving statement" 3 "lim1" } } */ +/* { dg-final { scan-tree-dump-times "Moving statement" 2 "lim1" } } */ /* { dg-final { cleanup-tree-dump "lim\[1-2\]" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/negate.c b/gcc/testsuite/gcc.dg/tree-ssa/negate.c index c51f323e710..12e2cdf7127 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/negate.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/negate.c @@ -8,6 +8,11 @@ int f (int a, int b) return y; } +/* We tested for reassociation to -(a + b) on the following which + isn't a transform that makes things cheaper. With reassoc + no longer applying to types with undefined overflow we lost + this transform. + int g (int a, int b) { int x = -a; @@ -15,6 +20,8 @@ int g (int a, int b) return y; } -/* There should be two additions now. */ -/* { dg-final { scan-tree-dump-times "\\+" 2 "reassoc1"} } */ +*/ + +/* There should be an addition now. */ +/* { dg-final { scan-tree-dump-times "\\+" 1 "reassoc1"} } */ /* { dg-final { cleanup-tree-dump "reassoc1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr44133.c b/gcc/testsuite/gcc.dg/tree-ssa/pr44133.c index dfa9ccfef39..d3d0fe3a986 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr44133.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr44133.c @@ -6,6 +6,6 @@ struct S { int i, j; }; int foo (int l) { struct S s; - s.j = l - 22; /* { dg-warning ".s\.i. is used uninitialized" } */ - return s.i + s.j; + s.j = l - 22; + return s.i + s.j; /* { dg-warning ".s\.i. is used uninitialized" } */ } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-1.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-1.c index ea5e4a77b11..43ccd8eaab1 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-1.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-optimized" } */ + int a, b, c, d; extern int printf (const char *, ...); int main(void) @@ -14,6 +15,10 @@ int main(void) printf ("%d %d\n", e, f); } -/* { dg-final { scan-tree-dump-times "b.._. \\\+ a.._." 1 "optimized"} } */ -/* { dg-final { scan-tree-dump-times " \\\+ " 2 "optimized"} } */ +/* We cannot reassociate these expressions because of undefined signed + integer overflow. Instead the value-numberer has to be extended + to canonicalize these expressions. */ + +/* { dg-final { scan-tree-dump-times "b.._. \\\+ a.._." 1 "optimized" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times " \\\+ " 2 "optimized" { xfail *-*-* } } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-14.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-14.c index 24141ef34e3..5b57160bcd6 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-14.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-14.c @@ -1,19 +1,21 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-reassoc1" } */ -int test1 (int x, int y, int z, int weight) +unsigned int test1 (unsigned int x, unsigned int y, unsigned int z, + unsigned int weight) { - int tmp1 = x * weight; - int tmp2 = y * weight; - int tmp3 = (x - y) * weight; + unsigned int tmp1 = x * weight; + unsigned int tmp2 = y * weight; + unsigned int tmp3 = (x - y) * weight; return tmp1 + (tmp2 + tmp3); } -int test2 (int x, int y, int z, int weight) +unsigned int test2 (unsigned int x, unsigned int y, unsigned int z, + unsigned int weight) { - int tmp1 = x * weight; - int tmp2 = y * weight * weight; - int tmp3 = z * weight * weight * weight; + unsigned int tmp1 = x * weight; + unsigned int tmp2 = y * weight * weight; + unsigned int tmp3 = z * weight * weight * weight; return tmp1 + tmp2 + tmp3; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-15.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-15.c index d9b74d27785..df6fd52136f 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-15.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-15.c @@ -1,14 +1,16 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-reassoc1" } */ -int test3 (int x, int y, int z, int weight, int w1, int w2, int w3) +unsigned int test3 (unsigned int x, unsigned int y, unsigned int z, + unsigned int weight, + unsigned int w1, unsigned int w2, unsigned int w3) { - int wtmp1 = w1 * weight; - int wtmp2 = w2 * weight; - int wtmp3 = w3 * weight; - int tmp1 = x * wtmp1; - int tmp2 = y * wtmp2; - int tmp3 = z * wtmp3; + unsigned int wtmp1 = w1 * weight; + unsigned int wtmp2 = w2 * weight; + unsigned int wtmp3 = w3 * weight; + unsigned int tmp1 = x * wtmp1; + unsigned int tmp2 = y * wtmp2; + unsigned int tmp3 = z * wtmp3; return tmp1 + tmp2 + tmp3; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-18.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-18.c index ce52cd0d04e..ab7fe295aa3 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-18.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-18.c @@ -1,10 +1,10 @@ /* { dg-do compile } */ /* { dg-options "-O -fdump-tree-reassoc1" } */ -int -ETree_nFactorEntriesInFront (int b, int m) +unsigned int +ETree_nFactorEntriesInFront (unsigned int b, unsigned int m) { - int nent = b*b + 2*b*m; + unsigned int nent = b*b + 2*b*m; return nent; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-2.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-2.c index 96be8cfe857..c5787ab5a5b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-2.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-optimized" } */ + int f (int a0,int a1,int a2,int a3,int a4) { int b0, b1, b2, b3, b4,e; @@ -13,5 +14,7 @@ int b0, b1, b2, b3, b4,e; return e; } -/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */ +/* We can't reassociate the expressions due to undefined signed overflow. */ + +/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" { xfail *-*-* } } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-20.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-20.c new file mode 100644 index 00000000000..1cfb9809393 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-20.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +unsigned int a, b, c, d; +extern int printf (const char *, ...); +int main(void) +{ + unsigned int e; + unsigned int f; + /* We should be able to transform these into the same expression, and only have two additions. */ + e = a + b; + e = e + c; + f = c + a; + f = f + b; + printf ("%d %d\n", e, f); +} + +/* { dg-final { scan-tree-dump-times "b.._. \\\+ a.._." 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \\\+ " 2 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-21.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-21.c new file mode 100644 index 00000000000..e02de1b4731 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-21.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +unsigned int f (unsigned int a0, unsigned int a1, unsigned int a2, + unsigned int a3, unsigned int a4) +{ + unsigned int b0, b1, b2, b3, b4, e; + /* this can be optimized to four additions... */ + b4 = a4 + a3 + a2 + a1 + a0; + b3 = a3 + a2 + a1 + a0; + b2 = a2 + a1 + a0; + b1 = a1 + a0; + /* This is actually 0 */ + e = b4 - b3 + b2 - b1 - a4 - a2; + return e; +} + +/* { dg-final { scan-tree-dump-times "return 0" 1 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-22.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-22.c new file mode 100644 index 00000000000..7eb97f45622 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-22.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-reassoc1" } */ +unsigned int foo(unsigned int a, unsigned int b, unsigned int c, unsigned int d) +{ + /* Should be transformed into a + c + 8 */ + unsigned int e = a + 3; + unsigned int f = c + 5; + unsigned int g = e + f; + return g; +} + +/* { dg-final { scan-tree-dump-times "\\\+ 8" 1 "reassoc1"} } */ +/* { dg-final { cleanup-tree-dump "reassoc1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-23.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-23.c new file mode 100644 index 00000000000..65aee7237ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-23.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-reassoc1" } */ + +unsigned int +foo(unsigned int a, unsigned int b, unsigned int c, unsigned int d, + unsigned int e, unsigned int f, unsigned int g, unsigned int h) +{ + /* Should be transformed into e = 20 */ + unsigned int i = (a + 9) + (c + 8); + unsigned int j = (-c + 1) + (-a + 2); + + e = i + j; + return e; +} + +/* { dg-final { scan-tree-dump-times "= 20" 1 "reassoc1"} } */ +/* { dg-final { cleanup-tree-dump "reassoc1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-6.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-6.c index d7c8b818c99..480f7c0161d 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-6.c @@ -9,5 +9,7 @@ int main(int a, int b, int c, int d) return g; } -/* { dg-final { scan-tree-dump-times "\\\+ 8" 1 "reassoc1"} } */ +/* We cannot re-associate the additions due to undefined signed overflow. */ + +/* { dg-final { scan-tree-dump-times "\\\+ 8" 1 "reassoc1" { xfail *-*-* } } } */ /* { dg-final { cleanup-tree-dump "reassoc1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-7.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-7.c index 6b3b227029d..ee9b80fd9c3 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-7.c @@ -1,12 +1,16 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-reassoc1" } */ -int main(int a, int b, int c, int d, int e, int f, int g, int h) + +unsigned int +foo(unsigned int a, unsigned int b, unsigned int c, unsigned int d, + unsigned int e, unsigned int f, unsigned int g, unsigned int h) { /* Should be transformed into a + c + d + e + g + 15 */ - int i = (a + 9) + (c + d); - int j = (e + 4) + (2 + g); + unsigned int i = (a + 9) + (c + d); + unsigned int j = (e + 4) + (2 + g); e = i + j; return e; } + /* { dg-final { scan-tree-dump-times "\\\+ 15" 1 "reassoc1"} } */ /* { dg-final { cleanup-tree-dump "reassoc1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-9.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-9.c index 7fa9ff3f125..d09303ccfde 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-9.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-9.c @@ -10,5 +10,9 @@ int main(int a, int b, int c, int d, int e, int f, int g, int h) e = i + j; return e; } -/* { dg-final { scan-tree-dump-times "= 20" 1 "reassoc1"} } */ + +/* We can always re-associate to a final constant but the current + implementation does not allow easy roll-back without IL changes. */ + +/* { dg-final { scan-tree-dump-times "= 20" 1 "reassoc1" { xfail *-*-* } } } */ /* { dg-final { cleanup-tree-dump "reassoc1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c index 38380d3d185..311f127812b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c @@ -16,7 +16,9 @@ int motion_test1(int data, int data_0, int data_3, int v) return v * t * u; } /* We should eliminate one computation of data_0 + data_3 along the - main path, and one computation of v * i along the main path, causing - two eliminations. */ -/* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */ + main path. We cannot re-associate v * t * u due to undefined + signed overflow so we do not eliminate one computation of v * i along + the main path. */ +/* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */ /* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-1.c b/gcc/testsuite/gcc.dg/vect/vect-1.c index 7a570541c73..182b85b9353 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-1.c +++ b/gcc/testsuite/gcc.dg/vect/vect-1.c @@ -26,7 +26,7 @@ foo (int n) char image[N][N]; char block[N][N]; - /* Not vectorizable yet (cross-iteration cycle). */ + /* Vectorizable. */ diff = 0; for (i = 0; i < N; i++) { diff += (cb[i] - cc[i]); @@ -34,8 +34,7 @@ foo (int n) ibar (&diff); - /* Not vectorizable yet (outer-loop: not attempted. - inner-loop: cross iteration cycle; multi-dimensional arrays). */ + /* Vectorizable. */ diff = 0; for (i = 0; i < N; i++) { for (i = 0; i < N; i++) { @@ -86,6 +85,6 @@ foo (int n) fbar (a); } -/* { dg-final { scan-tree-dump-times "vectorized 4 loops" 1 "vect" { target vect_extract_even_odd_wide } } } */ -/* { dg-final { scan-tree-dump-times "vectorized 3 loops" 1 "vect" { xfail vect_extract_even_odd_wide } } } */ +/* { dg-final { scan-tree-dump-times "vectorized 6 loops" 1 "vect" { target vect_extract_even_odd_wide } } } */ +/* { dg-final { scan-tree-dump-times "vectorized 5 loops" 1 "vect" { xfail vect_extract_even_odd_wide } } } */ /* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/gfortran.dg/reassoc_6.f b/gcc/testsuite/gfortran.dg/reassoc_6.f index cbc36f5675b..97a5de8a748 100644 --- a/gcc/testsuite/gfortran.dg/reassoc_6.f +++ b/gcc/testsuite/gfortran.dg/reassoc_6.f @@ -16,5 +16,7 @@ return end ! Verify that offset of the first element is simplified -! { dg-final { scan-tree-dump-not "~" "optimized" } } +! While we understand to combine x + ~x IVOPTs now messes things +! up by hiding that operation in casts to unsigned. +! { dg-final { scan-tree-dump-not "~" "optimized" { xfail *-*-* } } } ! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index b6278045c85..5bf41e82eb3 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1357,6 +1357,287 @@ simplify_bitwise_and (gimple_stmt_iterator *gsi, gimple stmt) return; } + +/* Perform re-associations of the plus or minus statement STMT that are + always permitted. */ + +static void +associate_plusminus (gimple stmt) +{ + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + enum tree_code code = gimple_assign_rhs_code (stmt); + gimple_stmt_iterator gsi; + bool changed; + + /* We can't reassociate at all for saturating types. */ + if (TYPE_SATURATING (TREE_TYPE (rhs1))) + return; + + /* First contract negates. */ + do + { + changed = false; + + /* A +- (-B) -> A -+ B. */ + if (TREE_CODE (rhs2) == SSA_NAME) + { + gimple def_stmt = SSA_NAME_DEF_STMT (rhs2); + if (is_gimple_assign (def_stmt) + && gimple_assign_rhs_code (def_stmt) == NEGATE_EXPR) + { + code = (code == MINUS_EXPR) ? PLUS_EXPR : MINUS_EXPR; + gimple_assign_set_rhs_code (stmt, code); + rhs2 = gimple_assign_rhs1 (def_stmt); + gimple_assign_set_rhs2 (stmt, rhs2); + gimple_set_modified (stmt, true); + changed = true; + } + } + + /* (-A) + B -> B - A. */ + if (TREE_CODE (rhs1) == SSA_NAME + && code == PLUS_EXPR) + { + gimple def_stmt = SSA_NAME_DEF_STMT (rhs1); + if (is_gimple_assign (def_stmt) + && gimple_assign_rhs_code (def_stmt) == NEGATE_EXPR) + { + code = MINUS_EXPR; + gimple_assign_set_rhs_code (stmt, code); + rhs1 = rhs2; + gimple_assign_set_rhs1 (stmt, rhs1); + rhs2 = gimple_assign_rhs1 (def_stmt); + gimple_assign_set_rhs2 (stmt, rhs2); + gimple_set_modified (stmt, true); + changed = true; + } + } + } + while (changed); + + /* We can't reassociate floating-point or fixed-point plus or minus + because of saturation to +-Inf. */ + if (FLOAT_TYPE_P (TREE_TYPE (rhs1)) + || FIXED_POINT_TYPE_P (TREE_TYPE (rhs1))) + goto out; + + /* Second match patterns that allow contracting a plus-minus pair + irrespective of overflow issues. + + (A +- B) - A -> +- B + (A +- B) -+ B -> A + (CST +- A) +- CST -> CST +- A + (A + CST) +- CST -> A + CST + ~A + A -> -1 + ~A + 1 -> -A + A - (A +- B) -> -+ B + A +- (B +- A) -> +- B + CST +- (CST +- A) -> CST +- A + CST +- (A +- CST) -> CST +- A + A + ~A -> -1 + + via commutating the addition and contracting operations to zero + by reassociation. */ + + gsi = gsi_for_stmt (stmt); + if (TREE_CODE (rhs1) == SSA_NAME) + { + gimple def_stmt = SSA_NAME_DEF_STMT (rhs1); + if (is_gimple_assign (def_stmt)) + { + enum tree_code def_code = gimple_assign_rhs_code (def_stmt); + if (def_code == PLUS_EXPR + || def_code == MINUS_EXPR) + { + tree def_rhs1 = gimple_assign_rhs1 (def_stmt); + tree def_rhs2 = gimple_assign_rhs2 (def_stmt); + if (operand_equal_p (def_rhs1, rhs2, 0) + && code == MINUS_EXPR) + { + /* (A +- B) - A -> +- B. */ + code = ((def_code == PLUS_EXPR) + ? TREE_CODE (def_rhs2) : NEGATE_EXPR); + rhs1 = def_rhs2; + rhs2 = NULL_TREE; + gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == stmt); + gimple_set_modified (stmt, true); + } + else if (operand_equal_p (def_rhs2, rhs2, 0) + && code != def_code) + { + /* (A +- B) -+ B -> A. */ + code = TREE_CODE (def_rhs1); + rhs1 = def_rhs1; + rhs2 = NULL_TREE; + gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == stmt); + gimple_set_modified (stmt, true); + } + else if (TREE_CODE (rhs2) == INTEGER_CST + && TREE_CODE (def_rhs1) == INTEGER_CST) + { + /* (CST +- A) +- CST -> CST +- A. */ + tree cst = fold_binary (code, TREE_TYPE (rhs1), + def_rhs1, rhs2); + if (cst && !TREE_OVERFLOW (cst)) + { + code = def_code; + gimple_assign_set_rhs_code (stmt, code); + rhs1 = cst; + gimple_assign_set_rhs1 (stmt, rhs1); + rhs2 = def_rhs2; + gimple_assign_set_rhs2 (stmt, rhs2); + gimple_set_modified (stmt, true); + } + } + else if (TREE_CODE (rhs2) == INTEGER_CST + && TREE_CODE (def_rhs2) == INTEGER_CST + && def_code == PLUS_EXPR) + { + /* (A + CST) +- CST -> A + CST. */ + tree cst = fold_binary (code, TREE_TYPE (rhs1), + def_rhs2, rhs2); + if (cst && !TREE_OVERFLOW (cst)) + { + code = PLUS_EXPR; + gimple_assign_set_rhs_code (stmt, code); + rhs1 = def_rhs1; + gimple_assign_set_rhs1 (stmt, rhs1); + rhs2 = cst; + gimple_assign_set_rhs2 (stmt, rhs2); + gimple_set_modified (stmt, true); + } + } + } + else if (def_code == BIT_NOT_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) + { + tree def_rhs1 = gimple_assign_rhs1 (def_stmt); + if (code == PLUS_EXPR + && operand_equal_p (def_rhs1, rhs2, 0)) + { + /* ~A + A -> -1. */ + code = INTEGER_CST; + rhs1 = build_int_cst (TREE_TYPE (rhs2), -1); + rhs2 = NULL_TREE; + gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == stmt); + gimple_set_modified (stmt, true); + } + else if (code == PLUS_EXPR + && integer_onep (rhs1)) + { + /* ~A + 1 -> -A. */ + code = NEGATE_EXPR; + rhs1 = def_rhs1; + rhs2 = NULL_TREE; + gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == stmt); + gimple_set_modified (stmt, true); + } + } + } + } + + if (rhs2 && TREE_CODE (rhs2) == SSA_NAME) + { + gimple def_stmt = SSA_NAME_DEF_STMT (rhs2); + if (is_gimple_assign (def_stmt)) + { + enum tree_code def_code = gimple_assign_rhs_code (def_stmt); + if (def_code == PLUS_EXPR + || def_code == MINUS_EXPR) + { + tree def_rhs1 = gimple_assign_rhs1 (def_stmt); + tree def_rhs2 = gimple_assign_rhs2 (def_stmt); + if (operand_equal_p (def_rhs1, rhs1, 0) + && code == MINUS_EXPR) + { + /* A - (A +- B) -> -+ B. */ + code = ((def_code == PLUS_EXPR) + ? NEGATE_EXPR : TREE_CODE (def_rhs2)); + rhs1 = def_rhs2; + rhs2 = NULL_TREE; + gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == stmt); + gimple_set_modified (stmt, true); + } + else if (operand_equal_p (def_rhs2, rhs1, 0) + && code != def_code) + { + /* A +- (B +- A) -> +- B. */ + code = ((code == PLUS_EXPR) + ? TREE_CODE (def_rhs1) : NEGATE_EXPR); + rhs1 = def_rhs1; + rhs2 = NULL_TREE; + gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == stmt); + gimple_set_modified (stmt, true); + } + else if (TREE_CODE (rhs1) == INTEGER_CST + && TREE_CODE (def_rhs1) == INTEGER_CST) + { + /* CST +- (CST +- A) -> CST +- A. */ + tree cst = fold_binary (code, TREE_TYPE (rhs2), + rhs1, def_rhs1); + if (cst && !TREE_OVERFLOW (cst)) + { + code = (code == def_code ? PLUS_EXPR : MINUS_EXPR); + gimple_assign_set_rhs_code (stmt, code); + rhs1 = cst; + gimple_assign_set_rhs1 (stmt, rhs1); + rhs2 = def_rhs2; + gimple_assign_set_rhs2 (stmt, rhs2); + gimple_set_modified (stmt, true); + } + } + else if (TREE_CODE (rhs1) == INTEGER_CST + && TREE_CODE (def_rhs2) == INTEGER_CST) + { + /* CST +- (A +- CST) -> CST +- A. */ + tree cst = fold_binary (def_code == code + ? PLUS_EXPR : MINUS_EXPR, + TREE_TYPE (rhs2), + rhs1, def_rhs2); + if (cst && !TREE_OVERFLOW (cst)) + { + rhs1 = cst; + gimple_assign_set_rhs1 (stmt, rhs1); + rhs2 = def_rhs1; + gimple_assign_set_rhs2 (stmt, rhs2); + gimple_set_modified (stmt, true); + } + } + } + else if (def_code == BIT_NOT_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (rhs2))) + { + tree def_rhs1 = gimple_assign_rhs1 (def_stmt); + if (code == PLUS_EXPR + && operand_equal_p (def_rhs1, rhs1, 0)) + { + /* A + ~A -> -1. */ + code = INTEGER_CST; + rhs1 = build_int_cst (TREE_TYPE (rhs1), -1); + rhs2 = NULL_TREE; + gimple_assign_set_rhs_with_ops (&gsi, code, rhs1, NULL_TREE); + gcc_assert (gsi_stmt (gsi) == stmt); + gimple_set_modified (stmt, true); + } + } + } + } + +out: + if (gimple_modified_p (stmt)) + { + fold_stmt_inplace (stmt); + update_stmt (stmt); + } +} + /* Main entry point for the forward propagation optimizer. */ static unsigned int @@ -1478,6 +1759,12 @@ tree_ssa_forward_propagate_single_use_vars (void) simplify_bitwise_and (&gsi, stmt); gsi_next (&gsi); } + else if (gimple_assign_rhs_code (stmt) == PLUS_EXPR + || gimple_assign_rhs_code (stmt) == MINUS_EXPR) + { + associate_plusminus (stmt); + gsi_next (&gsi); + } else gsi_next (&gsi); } diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 6cd3cebfe86..adc5a8dcf67 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -1949,7 +1949,7 @@ static bool can_reassociate_p (tree op) { tree type = TREE_TYPE (op); - if (INTEGRAL_TYPE_P (type) + if ((INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)) || NON_SAT_FIXED_POINT_TYPE_P (type) || (flag_associative_math && FLOAT_TYPE_P (type))) return true; @@ -2065,9 +2065,16 @@ reassociate_bb (basic_block bb) rhs1 = gimple_assign_rhs1 (stmt); rhs2 = gimple_assign_rhs2 (stmt); - if (!can_reassociate_p (lhs) - || !can_reassociate_p (rhs1) - || !can_reassociate_p (rhs2)) + /* For non-bit or min/max operations we can't associate + all types. Verify that here. */ + if (rhs_code != BIT_IOR_EXPR + && rhs_code != BIT_AND_EXPR + && rhs_code != BIT_XOR_EXPR + && rhs_code != MIN_EXPR + && rhs_code != MAX_EXPR + && (!can_reassociate_p (lhs) + || !can_reassociate_p (rhs1) + || !can_reassociate_p (rhs2))) continue; if (associative_tree_code (rhs_code))