"Bin.Cheng" <amker.ch...@gmail.com> writes:
On Wed, Aug 4, 2021 at 10:42 AM guojiufu
<guoji...@linux.ibm.com> wrote:
Hi,
cut...
>> @@ -0,0 +1,63 @@
>> +TYPE __attribute__ ((noinline))
>> +foo_sign (int *__restrict__ a, int *__restrict__ b, TYPE l,
>> TYPE n)
>> +{
>> + for (l = L_BASE; n < l; l += C)
>> + *a++ = *b++ + 1;
>> + return l;
>> +}
>> +
>> +TYPE __attribute__ ((noinline))
>> +bar_sign (int *__restrict__ a, int *__restrict__ b, TYPE l,
>> TYPE n)
>> +{
>> + for (l = L_BASE_DOWN; l < n; l -= C)
I noticed that both L_BASE and L_BASE_DOWN are defined as l,
which
makes this test a bit confusing. Could you clean the use of l,
for
example, by using an auto var for the loop index invariable?
Otherwise the patch looks good to me. Thanks very much for the
work.
Thanks a lot for your help to review!
L_BASE.. are not needed. Updated the patch which use
a new index var 'i' for loop instead param 'l':
TYPE i;
for (i = l; n < i; i += C)
I updated the patch as below.
Bootstrap & regress pass on powerpc64 and powerpc64le.
For code like:
unsigned foo(unsigned val, unsigned start)
{
unsigned cnt = 0;
for (unsigned i = start; i > val; ++i)
cnt++;
return cnt;
}
The number of iterations should be about UINT_MAX - start.
There is function adjust_cond_for_loop_until_wrap which
handles similar work for const bases.
Like adjust_cond_for_loop_until_wrap, this patch enhance
function number_of_iterations_cond/number_of_iterations_lt
to analyze number of iterations for this kind of loop.
Bootstrap and regtest pass on powerpc64le, x86_64 and aarch64.
Is this ok for trunk?
gcc/ChangeLog:
2021-08-16 Jiufu Guo <guoji...@linux.ibm.com>
PR tree-optimization/101145
* tree-ssa-loop-niter.c (number_of_iterations_until_wrap):
New function.
(number_of_iterations_lt): Invoke above function.
(adjust_cond_for_loop_until_wrap):
Merge to number_of_iterations_until_wrap.
(number_of_iterations_cond): Update invokes for
adjust_cond_for_loop_until_wrap and
number_of_iterations_lt.
gcc/testsuite/ChangeLog:
2021-08-16 Jiufu Guo <guoji...@linux.ibm.com>
PR tree-optimization/101145
* gcc.dg/vect/pr101145.c: New test.
* gcc.dg/vect/pr101145.inc: New test.
* gcc.dg/vect/pr101145_1.c: New test.
* gcc.dg/vect/pr101145_2.c: New test.
* gcc.dg/vect/pr101145_3.c: New test.
* gcc.dg/vect/pr101145inf.c: New test.
* gcc.dg/vect/pr101145inf.inc: New test.
* gcc.dg/vect/pr101145inf_1.c: New test.
---
gcc/testsuite/gcc.dg/vect/pr101145.c | 187
++++++++++++++++++++++
gcc/testsuite/gcc.dg/vect/pr101145.inc | 65 ++++++++
gcc/testsuite/gcc.dg/vect/pr101145_1.c | 13 ++
gcc/testsuite/gcc.dg/vect/pr101145_2.c | 13 ++
gcc/testsuite/gcc.dg/vect/pr101145_3.c | 13 ++
gcc/testsuite/gcc.dg/vect/pr101145inf.c | 25 +++
gcc/testsuite/gcc.dg/vect/pr101145inf.inc | 28 ++++
gcc/testsuite/gcc.dg/vect/pr101145inf_1.c | 23 +++
gcc/tree-ssa-loop-niter.c | 157
++++++++++--------
9 files changed, 459 insertions(+), 65 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145.c
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145.inc
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145_1.c
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145_2.c
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145_3.c
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145inf.c
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145inf.inc
create mode 100644 gcc/testsuite/gcc.dg/vect/pr101145inf_1.c
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145.c
b/gcc/testsuite/gcc.dg/vect/pr101145.c
new file mode 100644
index 00000000000..74031b031cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145.c
@@ -0,0 +1,187 @@
+/* { dg-require-effective-target vect_int } */
+/* { dg-options "-O3 -fdump-tree-vect-details" } */
+#include <limits.h>
+
+unsigned __attribute__ ((noinline))
+foo (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned n)
+{
+ while (n < ++l)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+foo_1 (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned)
+{
+ while (UINT_MAX - 64 < ++l)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+foo_2 (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned n)
+{
+ l = UINT_MAX - 32;
+ while (n < ++l)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+foo_3 (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned n)
+{
+ while (n <= ++l)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+foo_4 (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned n)
+{ // infininate
+ while (0 <= ++l)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+foo_5 (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned n)
+{
+ //no loop
+ l = UINT_MAX;
+ while (n < ++l)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+bar (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned n)
+{
+ while (--l < n)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+bar_1 (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned)
+{
+ while (--l < 64)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+unsigned __attribute__ ((noinline))
+bar_2 (int *__restrict__ a, int *__restrict__ b, unsigned l,
unsigned n)
+{
+ l = 32;
+ while (--l < n)
+ *a++ = *b++ + 1;
+ return l;
+}
+
+
+int a[3200], b[3200];
+int fail;
+
+int
+main ()
+{
+ unsigned l, n;
+ unsigned res;
+ /* l > n*/
+ n = UINT_MAX - 64;
+ l = n + 32;
+ res = foo (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ l = n;
+ res = foo (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ l = n - 1;
+ res = foo (a, b, l, n);
+ if (res != l + 1)
+ fail++;
+
+ l = n - 32;
+ res = foo (a, b, l, n);
+ if (res != l + 1)
+ fail++;
+
+ l = UINT_MAX;
+ res = foo (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ l = n + 32;
+ res = foo_1 (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ l = n + 32;
+ res = foo_2 (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ l = n;
+ res = foo_3 (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ l = n - 1;
+ res = foo_3 (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ l = n - 2;
+ res = foo_3 (a, b, l, n);
+ if (res != l + 1)
+ fail++;
+
+ res = foo_5 (a, b, l, n);
+ if (res != 0)
+ fail++;
+
+ n = 64;
+ l = n - 32;
+ res = bar (a, b, l, n);
+ res++;
+ if (res != 0)
+ fail++;
+
+ l = n;
+ res = bar (a, b, l, n);
+ res++;
+ if (res != 0)
+ fail++;
+
+ l = n + 1;
+ res = bar (a, b, l, n);
+ res++;
+ if (res != l)
+ fail++;
+
+ l = 0;
+ res = bar (a, b, l, n);
+ res++;
+ if (res != l)
+ fail++;
+
+ l = 32;
+ res = bar_1 (a, b, l, n);
+ res++;
+ if (res != 0)
+ fail++;
+
+ res = bar_1 (a, b, l, n);
+ res++;
+ if (res != 0)
+ fail++;
+
+ if (fail)
+ __builtin_abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 7
"vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145.inc
b/gcc/testsuite/gcc.dg/vect/pr101145.inc
new file mode 100644
index 00000000000..615d2e5e552
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145.inc
@@ -0,0 +1,65 @@
+TYPE __attribute__ ((noinline))
+foo_sign (int *__restrict__ a, int *__restrict__ b, TYPE l, TYPE
n)
+{
+ TYPE i;
+ for (i = l; n < i; i += C)
+ *a++ = *b++ + 1;
+ return i;
+}
+
+TYPE __attribute__ ((noinline))
+bar_sign (int *__restrict__ a, int *__restrict__ b, TYPE l, TYPE
n)
+{
+ TYPE i;
+ for (i = l; i < n; i -= C)
+ *a++ = *b++ + 1;
+ return i;
+}
+
+int __attribute__ ((noinline)) neq (int a, int b) { return a !=
b; }
+
+int a[1000], b[1000];
+int fail;
+
+int
+main ()
+{
+ TYPE res;
+ TYPE l;
+ TYPE n;
+ n = N_BASE;
+ l = n - C;
+ res = foo_sign (a, b, l, n);
+ if (res != l)
+ fail++;
+
+ l = n;
+ res = foo_sign (a, b, l, n);
+ if (res != l)
+ fail++;
+
+ l = n + C;
+ res = foo_sign (a, b, l, n);
+ if (neq ((res - MIN) / C, 0))
+ fail++;
+
+ n = N_BASE_DOWN;
+ l = n - C;
+ res = bar_sign (a, b, l, n);
+ if (neq ((MAX - res) / C, 0))
+ fail++;
+
+ l = n;
+ res = bar_sign (a, b, l, n);
+ if (res != l)
+ fail++;
+
+ l = n + C;
+ res = bar_sign (a, b, l, n);
+ if (res != l)
+ fail++;
+
+ if (fail)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145_1.c
b/gcc/testsuite/gcc.dg/vect/pr101145_1.c
new file mode 100644
index 00000000000..8bc26e2436e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145_1.c
@@ -0,0 +1,13 @@
+/* { dg-require-effective-target vect_int } */
+/* { dg-options "-O3 -fdump-tree-vect-details" } */
+#define TYPE signed char
+#define MIN -128
+#define MAX 127
+#define N_BASE (MAX - 32)
+#define N_BASE_DOWN (MIN + 32)
+
+#define C 3
+
+#include "pr101145.inc"
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2
"vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145_2.c
b/gcc/testsuite/gcc.dg/vect/pr101145_2.c
new file mode 100644
index 00000000000..b14c4b4b519
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145_2.c
@@ -0,0 +1,13 @@
+/* { dg-require-effective-target vect_int } */
+/* { dg-options "-O3 -fdump-tree-vect-details" } */
+#define TYPE unsigned char
+#define MIN 0
+#define MAX 255
+#define N_BASE (MAX - 32 + 1)
+#define N_BASE_DOWN (MIN + 32)
+
+#define C 2
+
+#include "pr101145.inc"
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2
"vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145_3.c
b/gcc/testsuite/gcc.dg/vect/pr101145_3.c
new file mode 100644
index 00000000000..99289afec0b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145_3.c
@@ -0,0 +1,13 @@
+/* { dg-require-effective-target vect_int } */
+/* { dg-options "-O3 -fdump-tree-vect-details" } */
+#define TYPE int *
+#define MIN ((TYPE)0)
+#define MAX ((TYPE)((long long)-1))
+#define N_BASE (MIN - 32)
+#define N_BASE_DOWN (MIN + 32)
+
+#define C 1
+
+#include "pr101145.inc"
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2
"vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145inf.c
b/gcc/testsuite/gcc.dg/vect/pr101145inf.c
new file mode 100644
index 00000000000..ed49f5670b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145inf.c
@@ -0,0 +1,25 @@
+/* { dg-do run { target *-*-linux* *-*-gnu* *-*-uclinux* } } */
+/* { dg-options "-O3" } */
+#include <limits.h>
+#include "pr101145inf.inc"
+
+__attribute__ ((noinline))
+unsigned foo(unsigned val, unsigned start)
+{
+ unsigned cnt = 0;
+ for (unsigned i = start; val <= i; i+=16)
+ cnt++;
+ return cnt;
+}
+
+void test_finite ()
+{
+ unsigned n = foo (16, UINT_MAX - 32);
+ if (n != 3)
+ __builtin_abort ();
+}
+
+void test_infinite ()
+{
+ foo (15, UINT_MAX - 32);
+}
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145inf.inc
b/gcc/testsuite/gcc.dg/vect/pr101145inf.inc
new file mode 100644
index 00000000000..4aa3d049187
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145inf.inc
@@ -0,0 +1,28 @@
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+void test_finite ();
+void test_infinite ();
+
+void do_exit (int i)
+{
+ exit (0);
+}
+
+int main(void)
+{
+ test_finite ();
+ struct sigaction s;
+ sigemptyset (&s.sa_mask);
+ s.sa_handler = do_exit;
+ s.sa_flags = 0;
+ sigaction (SIGALRM, &s, NULL);
+ alarm (1);
+
+ test_infinite ();
+
+ __builtin_abort ();
+ return 1;
+}
+
diff --git a/gcc/testsuite/gcc.dg/vect/pr101145inf_1.c
b/gcc/testsuite/gcc.dg/vect/pr101145inf_1.c
new file mode 100644
index 00000000000..4ee3e31c7fe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr101145inf_1.c
@@ -0,0 +1,23 @@
+/* { dg-do run { target *-*-linux* *-*-gnu* *-*-uclinux* } } */
+/* { dg-options "-O3" } */
+#include <limits.h>
+#include "pr101145inf.inc"
+
+__attribute__ ((noinline))
+unsigned foo(unsigned val, unsigned start)
+{
+ unsigned cnt = 0;
+ for (unsigned i = start; i < val; i-=16)
+ cnt++;
+ return cnt;
+}
+
+void test_finite ()
+{
+ foo (UINT_MAX - 15, 32);
+}
+
+void test_infinite ()
+{
+ foo (UINT_MAX - 14, 32);
+}
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 466158a5eb1..7af92d1c893 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -1473,6 +1473,93 @@ assert_loop_rolls_lt (tree type, affine_iv
*iv0, affine_iv *iv1,
}
}
+/* Determines number of iterations of loop whose ending condition
+ is IV0 < IV1 which likes: {base, -C} < n, or n < {base, C}.
+ The number of iterations is stored to NITER. */
+
+static bool
+number_of_iterations_until_wrap (class loop *, tree type,
affine_iv *iv0,
+ affine_iv *iv1, class
tree_niter_desc *niter)
+{
+ tree niter_type = unsigned_type_for (type);
+ tree step, num, assumptions, may_be_zero;
+ wide_int high, low, max, min;
+
+ may_be_zero = fold_build2 (LE_EXPR, boolean_type_node,
iv1->base, iv0->base);
+ if (integer_onep (may_be_zero))
+ return false;
+
+ int prec = TYPE_PRECISION (type);
+ signop sgn = TYPE_SIGN (type);
+ min = wi::min_value (prec, sgn);
+ max = wi::max_value (prec, sgn);
+
+ /* n < {base, C}. */
+ if (integer_zerop (iv0->step) && !tree_int_cst_sign_bit
(iv1->step))
+ {
+ step = iv1->step;
+ /* MIN + C - 1 <= n. */
+ tree last = wide_int_to_tree (type, min + wi::to_wide
(step) - 1);
+ assumptions = fold_build2 (LE_EXPR, boolean_type_node,
last, iv0->base);
+ if (integer_zerop (assumptions))
+ return false;
+
+ num = fold_build2 (MINUS_EXPR, niter_type, wide_int_to_tree
(type, max),
+ iv1->base);
+ high = max;
+ if (TREE_CODE (iv1->base) == INTEGER_CST)
+ low = wi::to_wide (iv1->base) - 1;
+ else if (TREE_CODE (iv0->base) == INTEGER_CST)
+ low = wi::to_wide (iv0->base);
+ else
+ low = min;
+ }
+ /* {base, -C} < n. */
+ else if (tree_int_cst_sign_bit (iv0->step) && integer_zerop
(iv1->step))
+ {
+ step = fold_build1 (NEGATE_EXPR, TREE_TYPE (iv0->step),
iv0->step);
+ /* MAX - C + 1 >= n. */
+ tree last = wide_int_to_tree (type, max - wi::to_wide
(step) + 1);
+ assumptions = fold_build2 (GE_EXPR, boolean_type_node,
last, iv1->base);
+ if (integer_zerop (assumptions))
+ return false;
+
+ num = fold_build2 (MINUS_EXPR, niter_type, iv0->base,
+ wide_int_to_tree (type, min));
+ low = min;
+ if (TREE_CODE (iv0->base) == INTEGER_CST)
+ high = wi::to_wide (iv0->base) + 1;
+ else if (TREE_CODE (iv1->base) == INTEGER_CST)
+ high = wi::to_wide (iv1->base);
+ else
+ high = max;
+ }
+ else
+ return false;
+
+ /* (delta + step - 1) / step */
+ step = fold_convert (niter_type, step);
+ num = fold_convert (niter_type, num);
+ num = fold_build2 (PLUS_EXPR, niter_type, num, step);
+ niter->niter = fold_build2 (FLOOR_DIV_EXPR, niter_type, num,
step);
+
+ widest_int delta, s;
+ delta = widest_int::from (high, sgn) - widest_int::from (low,
sgn);
+ s = wi::to_widest (step);
+ delta = delta + s - 1;
+ niter->max = wi::udiv_floor (delta, s);
+
+ niter->may_be_zero = may_be_zero;
+
+ if (!integer_nonzerop (assumptions))
+ niter->assumptions = fold_build2 (TRUTH_AND_EXPR,
boolean_type_node,
+ niter->assumptions,
assumptions);
+
+ niter->control.no_overflow = false;
+
+ return true;
+}
+
/* Determines number of iterations of loop whose ending condition
is IV0 < IV1. TYPE is the type of the iv. The number of
iterations is stored to NITER. BNDS bounds the difference
@@ -1501,6 +1588,11 @@ number_of_iterations_lt (class loop *loop,
tree type, affine_iv *iv0,
niter->bound = iv0->base;
}
+ /* {base, -C} < n, or n < {base, C} */
+ if (tree_int_cst_sign_bit (iv0->step)
+ || (!integer_zerop (iv1->step) && !tree_int_cst_sign_bit
(iv1->step)))
+ return number_of_iterations_until_wrap (loop, type, iv0, iv1,
niter);
+
delta = fold_build2 (MINUS_EXPR, niter_type,
fold_convert (niter_type, iv1->base),
fold_convert (niter_type, iv0->base));
@@ -1665,62 +1757,6 @@ dump_affine_iv (FILE *file, affine_iv *iv)
}
}
-/* Given exit condition IV0 CODE IV1 in TYPE, this function
adjusts
- the condition for loop-until-wrap cases. For example:
- (unsigned){8, -1}_loop < 10 => {0, 1} != 9
- 10 < (unsigned){0, max - 7}_loop => {0, 1} != 8
- Return true if condition is successfully adjusted. */
-
-static bool
-adjust_cond_for_loop_until_wrap (tree type, affine_iv *iv0,
tree_code *code,
- affine_iv *iv1)
-{
- /* Only support simple cases for the moment. */
- if (TREE_CODE (iv0->base) != INTEGER_CST
- || TREE_CODE (iv1->base) != INTEGER_CST)
- return false;
-
- tree niter_type = unsigned_type_for (type), high, low;
- /* Case: i-- < 10. */
- if (integer_zerop (iv1->step))
- {
- /* TODO: Should handle case in which abs(step) != 1. */
- if (!integer_minus_onep (iv0->step))
- return false;
- /* Give up on infinite loop. */
- if (*code == LE_EXPR
- && tree_int_cst_equal (iv1->base, TYPE_MAX_VALUE
(type)))
- return false;
- high = fold_build2 (PLUS_EXPR, niter_type,
- fold_convert (niter_type, iv0->base),
- build_int_cst (niter_type, 1));
- low = fold_convert (niter_type, TYPE_MIN_VALUE (type));
- }
- else if (integer_zerop (iv0->step))
- {
- /* TODO: Should handle case in which abs(step) != 1. */
- if (!integer_onep (iv1->step))
- return false;
- /* Give up on infinite loop. */
- if (*code == LE_EXPR
- && tree_int_cst_equal (iv0->base, TYPE_MIN_VALUE
(type)))
- return false;
- high = fold_convert (niter_type, TYPE_MAX_VALUE (type));
- low = fold_build2 (MINUS_EXPR, niter_type,
- fold_convert (niter_type, iv1->base),
- build_int_cst (niter_type, 1));
- }
- else
- gcc_unreachable ();
-
- iv0->base = low;
- iv0->step = fold_convert (niter_type, integer_one_node);
- iv1->base = high;
- iv1->step = build_int_cst (niter_type, 0);
- *code = NE_EXPR;
- return true;
-}
-
/* Determine the number of iterations according to condition (for
staying
inside loop) which compares two induction variables using
comparison
operator CODE. The induction variable on left side of the
comparison
@@ -1855,15 +1891,6 @@ number_of_iterations_cond (class loop
*loop,
return true;
}
- /* Handle special case loops: while (i-- < 10) and while (10 <
i++) by
- adjusting iv0, iv1 and code. */
- if (code != NE_EXPR
- && (tree_int_cst_sign_bit (iv0->step)
- || (!integer_zerop (iv1->step)
- && !tree_int_cst_sign_bit (iv1->step)))
- && !adjust_cond_for_loop_until_wrap (type, iv0, &code,
iv1))
- return false;
-
/* OK, now we know we have a senseful loop. Handle several
cases, depending
on what comparison operator is used. */
bound_difference (loop, iv1->base, iv0->base, &bnds);
--
2.17.1
Thanks,
bin
>> + *a++ = *b++ + 1;
>> + return l;
>> +}
>> +