mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-15 14:01:04 +08:00
re PR tree-optimization/45232 (tree reassociation introduces undefined overflow)
2010-08-12 Richard Guenther <rguenther@suse.de> 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
This commit is contained in:
parent
1be38ccb1b
commit
2d698d3bb7
@ -1,3 +1,13 @@
|
||||
2010-08-12 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
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 <rguenther@suse.de>
|
||||
|
||||
* tree-flow.h (struct ptr_info_def): Add align and misalign fields.
|
||||
|
@ -1,3 +1,29 @@
|
||||
2010-08-12 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
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 <jakub@redhat.com>
|
||||
|
||||
PR debug/45259
|
||||
|
@ -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\]" } } */
|
||||
|
@ -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" } } */
|
||||
|
@ -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" } */
|
||||
}
|
||||
|
@ -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" } } */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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" } } */
|
||||
|
20
gcc/testsuite/gcc.dg/tree-ssa/reassoc-20.c
Normal file
20
gcc/testsuite/gcc.dg/tree-ssa/reassoc-20.c
Normal file
@ -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" } } */
|
19
gcc/testsuite/gcc.dg/tree-ssa/reassoc-21.c
Normal file
19
gcc/testsuite/gcc.dg/tree-ssa/reassoc-21.c
Normal file
@ -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" } } */
|
13
gcc/testsuite/gcc.dg/tree-ssa/reassoc-22.c
Normal file
13
gcc/testsuite/gcc.dg/tree-ssa/reassoc-22.c
Normal file
@ -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" } } */
|
17
gcc/testsuite/gcc.dg/tree-ssa/reassoc-23.c
Normal file
17
gcc/testsuite/gcc.dg/tree-ssa/reassoc-23.c
Normal file
@ -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" } } */
|
@ -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" } } */
|
||||
|
@ -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" } } */
|
||||
|
@ -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" } } */
|
||||
|
@ -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" } } */
|
||||
|
@ -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" } } */
|
||||
|
@ -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" } }
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user