diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2974266dc25..67d23869fd1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2007-02-28 Richard Guenther + + PR middle-end/30364 + * fold-const.c (fold_binary): Do not associate expressions + with more than one variable for integer types that do not wrap. + 2007-02-28 Sandra Loosemore * builtins.c (fold_builtin_call_list, fold_builtin_call_valist): diff --git a/gcc/fold-const.c b/gcc/fold-const.c index f1f4c2cb296..c8e2f514c71 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -9424,6 +9424,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) { tree var0, con0, lit0, minus_lit0; tree var1, con1, lit1, minus_lit1; + bool ok = true; /* Split both trees into variables, constants, and literals. Then associate each group together, the constants with literals, @@ -9434,12 +9435,32 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) var1 = split_tree (arg1, code, &con1, &lit1, &minus_lit1, code == MINUS_EXPR); + /* With undefined overflow we can only associate constants + with one variable. */ + if ((POINTER_TYPE_P (type) + || (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type))) + && var0 && var1) + { + tree tmp0 = var0; + tree tmp1 = var1; + + if (TREE_CODE (tmp0) == NEGATE_EXPR) + tmp0 = TREE_OPERAND (tmp0, 0); + if (TREE_CODE (tmp1) == NEGATE_EXPR) + tmp1 = TREE_OPERAND (tmp1, 0); + /* The only case we can still associate with two variables + is if they are the same, modulo negation. */ + if (!operand_equal_p (tmp0, tmp1, 0)) + ok = false; + } + /* Only do something if we found more than two objects. Otherwise, nothing has changed and we risk infinite recursion. */ - if (2 < ((var0 != 0) + (var1 != 0) - + (con0 != 0) + (con1 != 0) - + (lit0 != 0) + (lit1 != 0) - + (minus_lit0 != 0) + (minus_lit1 != 0))) + if (ok + && (2 < ((var0 != 0) + (var1 != 0) + + (con0 != 0) + (con1 != 0) + + (lit0 != 0) + (lit1 != 0) + + (minus_lit0 != 0) + (minus_lit1 != 0)))) { /* Recombine MINUS_EXPR operands by using PLUS_EXPR. */ if (code == MINUS_EXPR) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 921cf1493e7..f6a9766d11e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2007-02-28 Richard Guenther + + PR middle-end/30364 + * gcc.dg/torture/pr30364-1.c: New testcase. + * gcc.dg/torture/pr30364-2.c: Likewise. + * gcc.dg/torture/pr30364-3.c: Likewise. + 2007-02-28 Kaveh R. Ghazi * gcc.dg/torture/builtin-frexp-1.c: On mips*-*-irix6* and diff --git a/gcc/testsuite/gcc.dg/torture/pr30364-1.c b/gcc/testsuite/gcc.dg/torture/pr30364-1.c new file mode 100644 index 00000000000..09506c21c1c --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr30364-1.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ + +extern void abort (void); + +int f(int a, int b) +{ + if (a > 0x7FFFFFF0) return 0; + if (b > 0x7FFFFFF0) return 0; + + int c = (a - 20) + (b - 20); + return c > 0x7FFFFFF0; +} + +int main() +{ + if (f (0x7FFFFFF0, 41) != 1) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr30364-2.c b/gcc/testsuite/gcc.dg/torture/pr30364-2.c new file mode 100644 index 00000000000..20450f55557 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr30364-2.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ + +extern void abort (void); + +int f(unsigned int a, unsigned int b) +{ + if (a > 0x7FFFFFF0) return 0; + if (b > 0x7FFFFFF0) return 0; + + int c = (a - 20) + (b - 20); + return c > 0x7FFFFFF0; +} + +int main() +{ + if (f (0x7FFFFFF0, 41) != 1) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr30364-3.c b/gcc/testsuite/gcc.dg/torture/pr30364-3.c new file mode 100644 index 00000000000..4365679a8e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr30364-3.c @@ -0,0 +1,20 @@ +/* { dg-do run } */ +/* { dg-options "-fwrapv" } */ + +extern void abort (void); + +int f(int a, int b) +{ + if (a > 0x7FFFFFF0) return 0; + if (b > 0x7FFFFFF0) return 0; + + int c = (a - 20) + (b - 20); + return c > 0x7FFFFFF0; +} + +int main() +{ + if (f (0x7FFFFFF0, 41) != 1) + abort (); + return 0; +}