From b44e7f07c5a8b8dfe7549583d3504f1a39208b03 Mon Sep 17 00:00:00 2001 From: Zdenek Dvorak Date: Fri, 9 Feb 2007 14:29:11 +0100 Subject: [PATCH] re PR tree-optimization/23361 (Can't eliminate empty loops with power of two step and variable bounds) 2007-02-09 Zdenek Dvorak Richard Guenther PR middle-end/23361 * fold-const.c (fold_comparison): Handle obfuscated comparisons against INT_MIN/INT_MAX. * tree-ssa-loop-ivcanon.c (remove_empty_loop): Print to dump file if a loop is removed. * gcc.dg/fold-compare-3.c: New testcase. * gcc.dg/tree-ssa/loop-24.c: Likewise. Co-Authored-By: Richard Guenther From-SVN: r121742 --- gcc/ChangeLog | 9 ++ gcc/fold-const.c | 34 +++++ gcc/testsuite/ChangeLog | 7 ++ gcc/testsuite/gcc.dg/fold-compare-3.c | 159 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/loop-24.c | 17 +++ gcc/tree-ssa-loop-ivcanon.c | 3 + 6 files changed, 229 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/fold-compare-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/loop-24.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 777ca6382c9..cd1f1960c9e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2007-02-09 Zdenek Dvorak + Richard Guenther + + PR middle-end/23361 + * fold-const.c (fold_comparison): Handle obfuscated comparisons + against INT_MIN/INT_MAX. + * tree-ssa-loop-ivcanon.c (remove_empty_loop): Print to dump + file if a loop is removed. + 2007-02-09 Joseph Myers * calls.c (store_one_arg): Pass correct alignment to diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 0b37a0f9437..d20d78f5956 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -8043,6 +8043,40 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) lhs = fold_build2 (lhs_add ? PLUS_EXPR : MINUS_EXPR, TREE_TYPE (arg1), const2, const1); + + /* If the constant operation overflowed this can be + simplified as a comparison against INT_MAX/INT_MIN. */ + if (TREE_CODE (lhs) == INTEGER_CST + && TREE_OVERFLOW (lhs)) + { + int const1_sgn = tree_int_cst_sgn (const1); + enum tree_code code2 = code; + + /* Get the sign of the constant on the lhs if the + operation were VARIABLE + CONST1. */ + if (TREE_CODE (arg0) == MINUS_EXPR) + const1_sgn = -const1_sgn; + + /* The sign of the constant determines if we overflowed + INT_MAX (const1_sgn == -1) or INT_MIN (const1_sgn == 1). + Canonicalize to the INT_MIN overflow by swapping the comparison + if necessary. */ + if (const1_sgn == -1) + code2 = swap_tree_comparison (code); + + /* We now can look at the canonicalized case + VARIABLE + 1 CODE2 INT_MIN + and decide on the result. */ + if (code2 == LT_EXPR + || code2 == LE_EXPR + || code2 == EQ_EXPR) + return omit_one_operand (type, boolean_false_node, variable); + else if (code2 == NE_EXPR + || code2 == GE_EXPR + || code2 == GT_EXPR) + return omit_one_operand (type, boolean_true_node, variable); + } + if (TREE_CODE (lhs) == TREE_CODE (arg1) && (TREE_CODE (lhs) != INTEGER_CST || !TREE_OVERFLOW (lhs))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5608be04434..8575ad558af 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2007-02-09 Zdenek Dvorak + Richard Guenther + + PR middle-end/23361 + * gcc.dg/fold-compare-3.c: New testcase. + * gcc.dg/tree-ssa/loop-24.c: Likewise. + 2007-02-09 Uros Bizjak * gcc.dg/pr26570.c: Clean up coverage files. diff --git a/gcc/testsuite/gcc.dg/fold-compare-3.c b/gcc/testsuite/gcc.dg/fold-compare-3.c new file mode 100644 index 00000000000..011bf47bd6e --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-compare-3.c @@ -0,0 +1,159 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-cleanup_cfg1" } */ + +#include + +void this_comparison_is_false (void); +void this_comparison_is_true (void); +void this_comparison_is_not_decidable (void); + +void bla1eq (int var) +{ + if (var + 10 == INT_MIN + 9) + this_comparison_is_false (); +} + +void bla2eq (int var) +{ + if (var + 10 == INT_MIN + 10) + this_comparison_is_not_decidable (); +} + +void bla3eq (int var) +{ + if (var - 10 == INT_MAX - 9) + this_comparison_is_false (); +} + +void bla4eq (int var) +{ + if (var - 10 == INT_MAX - 10) + this_comparison_is_not_decidable (); +} + +void bla1ne (int var) +{ + if (var + 10 != INT_MIN + 9) + this_comparison_is_true (); +} + +void bla2ne (int var) +{ + if (var + 10 != INT_MIN + 10) + this_comparison_is_not_decidable (); +} + +void bla3ne (int var) +{ + if (var - 10 != INT_MAX - 9) + this_comparison_is_true (); +} + +void bla4ne (int var) +{ + if (var - 10 != INT_MAX - 10) + this_comparison_is_not_decidable (); +} + +void bla1lt (int var) +{ + if (var + 10 < INT_MIN + 10) + this_comparison_is_false (); +} + +void bla2lt (int var) +{ + if (var + 10 < INT_MIN + 11) + this_comparison_is_not_decidable (); +} + +void bla3lt (int var) +{ + if (var - 10 < INT_MAX - 9) + this_comparison_is_true (); +} + +void bla4lt (int var) +{ + if (var - 10 < INT_MAX - 10) + this_comparison_is_not_decidable (); +} + +void bla1le (int var) +{ + if (var + 10 <= INT_MIN + 9) + this_comparison_is_false (); +} + +void bla2le (int var) +{ + if (var + 10 <= INT_MIN + 10) + this_comparison_is_not_decidable (); +} + +void bla3le (int var) +{ + if (var - 10 <= INT_MAX - 10) + this_comparison_is_true (); +} + +void bla4le (int var) +{ + if (var - 10 <= INT_MAX - 11) + this_comparison_is_not_decidable (); +} + +void bla1gt (int var) +{ + if (var + 10 > INT_MIN + 9) + this_comparison_is_true (); +} + +void bla2gt (int var) +{ + if (var + 10 > INT_MIN + 10) + this_comparison_is_not_decidable (); +} + +void bla3gt (int var) +{ + if (var - 10 > INT_MAX - 10) + this_comparison_is_false (); +} + +void bla4gt (int var) +{ + if (var - 10 > INT_MAX - 11) + this_comparison_is_not_decidable (); +} + +void bla1ge (int var) +{ + if (var + 10 >= INT_MIN + 10) + this_comparison_is_true (); +} + +void bla2ge (int var) +{ + if (var + 10 >= INT_MIN + 11) + this_comparison_is_not_decidable (); +} + +void bla3ge (int var) +{ + if (var - 11 >= INT_MAX - 10) + this_comparison_is_false (); +} + +void bla4ge (int var) +{ + if (var - 10 >= INT_MAX - 10) + this_comparison_is_not_decidable (); +} + +/* { dg-final { scan-tree-dump-times "this_comparison_is_false" 0 "cleanup_cfg1" } } */ +/* { dg-final { scan-tree-dump-times "this_comparison_is_true" 6 "cleanup_cfg1" } } */ +/* { dg-final { scan-tree-dump-times "this_comparison_is_not_decidable" 12 "cleanup_cfg1" } } */ +/* { dg-final { scan-tree-dump-times "if " 12 "cleanup_cfg1" } } */ + +/* { dg-final { cleanup-tree-dump "cleanup_cfg1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-24.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-24.c new file mode 100644 index 00000000000..dfad30dcd3d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-24.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fstrict-overflow -fdump-tree-empty" } */ + +void foo(int a, int b) +{ for(;a!=b;a+=4); } + +void foo2(int a, int b) +{ for(;acount; + if (dump_file) + fprintf (dump_file, "Removing empty loop %d\n", loop->num); + non_exit = EDGE_SUCC (exit->src, 0); if (non_exit == exit) non_exit = EDGE_SUCC (exit->src, 1);