When transform {iv0.base, iv0.step} LT/LE {iv1.base, iv1.step} to {iv0.base, iv0.step - iv1.step} LT/LE {iv1.base, 0}
There would be error if 'iv0.step - iv1.step' in negative, for which means run until wrap/overflow. For example: {1, +, 1} <= {4, +, 3} => {1, +, -2} <= {4, +, 0} This patch avoid this kind transform. Bootstrap and regtest pass on ppc64le. Is this ok for trunk? BR. Jiufu gcc/ChangeLog: 2021-09-02 Jiufu Guo <guoji...@linux.ibm.com> PR tree-optimization/102131 * tree-ssa-loop-niter.c (number_of_iterations_cond): Avoid transform until wrap condition gcc/testsuite/ChangeLog: 2021-09-02 Jiufu Guo <guoji...@linux.ibm.com> PR tree-optimization/102131 * gcc.dg/pr102131.c: New test. --- gcc/tree-ssa-loop-niter.c | 18 +++++++++ gcc/testsuite/gcc.dg/pr102131.c | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr102131.c diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c index 7af92d1c893..52ce517af89 100644 --- a/gcc/tree-ssa-loop-niter.c +++ b/gcc/tree-ssa-loop-niter.c @@ -1866,6 +1866,24 @@ number_of_iterations_cond (class loop *loop, || !iv0->no_overflow || !iv1->no_overflow)) return false; + /* GT/GE has been transformed to LT/LE already. + cmp_code could be LT, LE or NE + + For LE/LT transform + {iv0.base, iv0.step} LT/LE {iv1.base, iv1.step} + to + {iv0.base, iv0.step - iv1.step} LT/LE {iv1.base, 0} + Negative iv0.step - iv1.step means decreasing until wrap, + then the transform is not accurate. + + For example: + {1, +, 1} <= {4, +, 3} + is not same with + {1, +, -2} <= {4, +, 0} + */ + if ((code == LE_EXPR || code == LT_EXPR) && tree_int_cst_sign_bit (step)) + return false; + iv0->step = step; if (!POINTER_TYPE_P (type)) iv0->no_overflow = false; diff --git a/gcc/testsuite/gcc.dg/pr102131.c b/gcc/testsuite/gcc.dg/pr102131.c new file mode 100644 index 00000000000..0fcfaa132da --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr102131.c @@ -0,0 +1,69 @@ +/* { dg-do run } */ + +unsigned int a; +int +fun1 () +{ + unsigned b = 0; + int c = 1; + for (; b < 3; b++) + { + while (c < b) + __builtin_abort (); + for (a = 0; a < 3; a++) + c++; + } + return 0; +} + +unsigned b; +int +fun2 () +{ + unsigned c = 0; + for (a = 0; a < 2; a++) + for (b = 0; b < 2; b++) + if (++c < a) + __builtin_abort (); + return 0; +} + +int +fun3 (void) +{ + unsigned a, b, c = 0; + for (a = 0; a < 10; a++) + { + for (b = 0; b < 2; b++) + { + c++; + if (c < a) + { + __builtin_abort (); + } + } + } + return 0; +} + +int +fun4 () +{ + unsigned i; + for (i = 0; i < 3; ++i) + { + if (i > i * 2) + __builtin_abort (); + } + return 0; +} + +int +main () +{ + fun1 (); + fun2 (); + fun3 (); + fun4 (); + return 0; +} -- 2.17.1