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 <[email protected]>
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 <[email protected]>
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