aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lyon <christophe.lyon@linaro.org>2016-01-07 14:42:05 +0100
committerLinaro Code Review <review@review.linaro.org>2016-01-12 11:49:08 +0000
commitb3cbd8a6d7b6a56e2b99e80561ad72a263c38e23 (patch)
tree0d5b64558786063ba59da28a77f86bf27abca271
parentceed650db42cc32a57d536f612afb3dc639d52d7 (diff)
Fix bug #1982
gcc/testsuite/ Revert backport from trunk r225443. 2015-07-06 Bin Cheng <bin.cheng@arm.com> PR tree-optimization/66720 * gcc.dg/vect/pr48052.c: Use dg-require-effective-target vect_int_mult. gcc/ Revert backport from trunk r224009. 2015-06-02 Bin Cheng <bin.cheng@arm.com> PR tree-optimization/52563 PR tree-optimization/62173 * tree-ssa-loop-ivopts.c (struct iv): New field. Reorder fields. (alloc_iv, set_iv): New parameter. (determine_biv_step): Delete. (find_bivs): Inline original determine_biv_step. Pass new argument to set_iv. (idx_find_step): Use no_overflow information for conversion. * tree-scalar-evolution.c (analyze_scalar_evolution_in_loop): Let resolve_mixers handle folded_casts. (instantiate_scev_name): Change bool parameter to bool pointer. (instantiate_scev_poly, instantiate_scev_binary): Ditto. (instantiate_array_ref, instantiate_scev_not): Ditto. (instantiate_scev_3, instantiate_scev_2): Ditto. (instantiate_scev_1, instantiate_scev_r): Ditto. (instantiate_scev_convert, ): Change parameter. Pass argument to chrec_convert_aggressive. (instantiate_scev): Change argument. (resolve_mixers): New parameter and set it. (scev_const_prop): New argument. * tree-scalar-evolution.h (resolve_mixers): New parameter. * tree-chrec.c (convert_affine_scev): Call chrec_convert instead of chrec_conert_1. (chrec_convert): New parameter. Move definition below. (chrec_convert_aggressive): New parameter and set it. Call convert_affine_scev. * tree-chrec.h (chrec_convert): New parameter. (chrec_convert_aggressive): Ditto. gcc/testsuite/ Revert backport from trunk r224009. 2015-06-02 Bin Cheng <bin.cheng@arm.com> PR tree-optimization/52563 PR tree-optimization/62173 * gcc.dg/tree-ssa/scev-3.c: Remove xfail. * gcc.dg/tree-ssa/scev-4.c: Ditto. gcc/ Revert backport from trunk r224020. 2015-06-02 Bin Cheng <bin.cheng@arm.com> PR tree-optimization/48052 * cfgloop.h (struct control_iv): New. (struct loop): New field control_ivs. * tree-ssa-loop-niter.c : Include "stor-layout.h". (number_of_iterations_lt): Set no_overflow information. (number_of_iterations_exit): Init control iv in niter struct. (record_control_iv): New. (estimate_numbers_of_iterations_loop): Call record_control_iv. (loop_exits_before_overflow): New. Interface factored out of scev_probably_wraps_p. (scev_probably_wraps_p): Factor loop niter related code into loop_exits_before_overflow. (free_numbers_of_iterations_estimates_loop): Free control ivs. * tree-ssa-loop-niter.h (free_loop_control_ivs): New. gcc/testsuite/ Revert backport from trunk r224020. 2015-06-02 Bin Cheng <bin.cheng@arm.com> PR tree-optimization/48052 * gcc.dg/tree-ssa/scev-8.c: New. * gcc.dg/tree-ssa/scev-9.c: New. * gcc.dg/tree-ssa/scev-10.c: New. * gcc.dg/vect/pr48052.c: New. gcc/testsuite/ Revert backport from trunk r224055. 2015-06-03 Bin Cheng <bin.cheng@arm.com> * gcc.dg/tree-ssa/pr65447.c: Increase searching number. 2015-06-02 Kugan Vivekanandarajah <kuganv@linaro.org> gcc/ Revert backport from trunk r224058. 2015-06-03 Bin Cheng <bin.cheng@arm.com> * tree-ssa-loop-ivopts.c (dump_iv): New parameter. (dump_use, dump_cand, find_induction_variables): Pass new argument to dump_iv. (record_use): Preserve the ssa name information in IV. gcc/ Revert backport from trunk r224769. 2015-06-23 Bin Cheng <bin.cheng@arm.com> PR tree-optimization/66449 * tree-ssa-loop-niter.c (loop_exits_before_overflow): Use POINTER_PLUS_EXPR for pointers. gcc/testsuite/ Revert backport from trunk r224769. 2015-06-23 Bin Cheng <bin.cheng@arm.com> PR tree-optimization/66449 * gcc.dg/vect/pr66449.c: New test. Change-Id: I0e04dc3450c817e13f99f888e14fe31f5a1de9c2
-rw-r--r--gcc/cfgloop.h11
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr65447.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr66449.c18
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/scev-10.c23
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/scev-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/scev-4.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/scev-8.c62
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/scev-9.c22
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr48052.c26
-rw-r--r--gcc/tree-chrec.c104
-rw-r--r--gcc/tree-chrec.h4
-rw-r--r--gcc/tree-scalar-evolution.c138
-rw-r--r--gcc/tree-scalar-evolution.h2
-rw-r--r--gcc/tree-ssa-loop-ivopts.c72
-rw-r--r--gcc/tree-ssa-loop-niter.c293
-rw-r--r--gcc/tree-ssa-loop-niter.h1
16 files changed, 210 insertions, 572 deletions
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index b0116786d49..1d845729e5e 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -116,14 +116,6 @@ enum loop_estimation
EST_LAST
};
-/* The structure describing non-overflow control induction variable for
- loop's exit edge. */
-struct GTY ((chain_next ("%h.next"))) control_iv {
- tree base;
- tree step;
- struct control_iv *next;
-};
-
/* Structure to hold information for each natural loop. */
struct GTY ((chain_next ("%h.next"))) loop {
/* Index into loops array. */
@@ -211,9 +203,6 @@ struct GTY ((chain_next ("%h.next"))) loop {
/* Upper bound on number of iterations of a loop. */
struct nb_iter_bound *bounds;
- /* Non-overflow control ivs of a loop. */
- struct control_iv *control_ivs;
-
/* Head of the cyclic list of the exits of the loop. */
struct loop_exit *exits;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr65447.c b/gcc/testsuite/gcc.dg/tree-ssa/pr65447.c
index 4c910389d66..5f89a684dbc 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr65447.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr65447.c
@@ -50,4 +50,4 @@ void foo (double *p)
}
/* We should groups address type IV uses. */
-/* { dg-final { scan-tree-dump-not "\\nuse 5\\n" "ivopts" } } */
+/* { dg-final { scan-tree-dump-not "\\nuse 2\\n" "ivopts" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr66449.c b/gcc/testsuite/gcc.dg/tree-ssa/pr66449.c
deleted file mode 100644
index 986b3fb6b9a..00000000000
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr66449.c
+++ /dev/null
@@ -1,18 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O3" } */
-
-void *fn1(void *p1, void *p2, long p3)
-{
- long a = (long)p1, b = (long)p2, c = p3;
-
- while (c)
- {
- int d = ((int *)b)[0];
-
- c--;
- ((char *)a)[0] = d;
- a++;
- }
- return 0;
-}
-
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-10.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-10.c
deleted file mode 100644
index fd815b2fe08..00000000000
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-10.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-ivopts-details" } */
-
-int *a;
-
-int
-foo (signed char s, signed char l)
-{
- signed char i;
- int sum = 0;
-
- for (i = s; i < l; i++)
- {
- sum += a[i];
- }
-
- return sum;
-}
-
-/* Address of array reference is scev. */
-/* { dg-final { scan-tree-dump-times "use \[0-9\]\n address" 1 "ivopts" } } */
-
-
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
index 1346f26d6c1..dc072a998fa 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
@@ -15,4 +15,4 @@ f(int k)
}
}
-/* { dg-final { scan-tree-dump-times "&a" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "&a" 1 "optimized" { xfail { lp64 || llp64 } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
index 99d033709af..927b6605e98 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
@@ -20,4 +20,4 @@ f(int k)
}
}
-/* { dg-final { scan-tree-dump-times "&a" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "&a" 1 "optimized" { xfail { lp64 || llp64 } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
deleted file mode 100644
index 766f674d55b..00000000000
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-ivopts-details" } */
-
-int *a;
-
-int
-foo1 (long long s, long long l)
-{
- long long i;
-
- for (i = s; i < l; i++)
- {
- a[(short)i] = 0;
- }
- return 0;
-}
-
-int
-foo2 (unsigned char s, unsigned char l, unsigned char c)
-{
- unsigned char i, step = 1;
- int sum = 0;
-
- for (i = s; i < l; i++)
- {
- sum += a[c];
- c += step;
- }
-
- return sum;
-}
-
-int
-foo3 (unsigned char s, unsigned char l, unsigned char c)
-{
- unsigned char i;
- int sum = 0;
-
- for (i = s; i != l; i += c)
- {
- sum += a[i];
- }
-
- return sum;
-}
-
-int
-foo4 (unsigned char s, unsigned char l)
-{
- unsigned char i;
- int sum = 0;
-
- for (i = s; i != l; i++)
- {
- sum += a[i];
- }
-
- return sum;
-}
-
-/* Address of array references are not scevs. */
-/* { dg-final { scan-tree-dump-not "use \[0-9\]\n address" "ivopts" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-9.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-9.c
deleted file mode 100644
index 22e96c00d48..00000000000
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-9.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-ivopts-details" } */
-
-int *a;
-
-int
-foo (unsigned char s, unsigned char l)
-{
- unsigned char i;
- int sum = 0;
-
- for (i = s; i < l; i += 1)
- {
- sum += a[i];
- }
-
- return sum;
-}
-
-/* Address of array reference is scev. */
-/* { dg-final { scan-tree-dump-times "use \[0-9\]\n address" 1 "ivopts" } } */
-
diff --git a/gcc/testsuite/gcc.dg/vect/pr48052.c b/gcc/testsuite/gcc.dg/vect/pr48052.c
deleted file mode 100644
index 071e0bc7b65..00000000000
--- a/gcc/testsuite/gcc.dg/vect/pr48052.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/* { dg-do compile } */
-/* { dg-require-effective-target vect_int_mult } */
-
-int foo(int* A, int* B, unsigned start, unsigned BS)
-{
- int s = 0;
- for (unsigned k = start; k < start + BS; k++)
- {
- s += A[k] * B[k];
- }
-
- return s;
-}
-
-int bar(int* A, int* B, unsigned BS)
-{
- int s = 0;
- for (unsigned k = 0; k < BS; k++)
- {
- s += A[k] * B[k];
- }
-
- return s;
-}
-
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" } } */
diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c
index 9357a561739..b599c2c3e5e 100644
--- a/gcc/tree-chrec.c
+++ b/gcc/tree-chrec.c
@@ -1178,6 +1178,8 @@ nb_vars_in_chrec (tree chrec)
}
}
+static tree chrec_convert_1 (tree, tree, gimple, bool);
+
/* Converts BASE and STEP of affine scev to TYPE. LOOP is the loop whose iv
the scev corresponds to. AT_STMT is the statement at that the scev is
evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume that
@@ -1252,7 +1254,8 @@ convert_affine_scev (struct loop *loop, tree type,
use_overflow_semantics))
return false;
- new_base = chrec_convert (type, *base, at_stmt, use_overflow_semantics);
+ new_base = chrec_convert_1 (type, *base, at_stmt,
+ use_overflow_semantics);
/* The step must be sign extended, regardless of the signedness
of CT and TYPE. This only needs to be handled specially when
CT is unsigned -- to avoid e.g. unsigned char [100, +, 255]
@@ -1263,11 +1266,10 @@ convert_affine_scev (struct loop *loop, tree type,
if (TYPE_PRECISION (step_type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct))
{
tree signed_ct = build_nonstandard_integer_type (TYPE_PRECISION (ct), 0);
- new_step = chrec_convert (signed_ct, new_step, at_stmt,
- use_overflow_semantics);
+ new_step = chrec_convert_1 (signed_ct, new_step, at_stmt,
+ use_overflow_semantics);
}
- new_step = chrec_convert (step_type, new_step, at_stmt,
- use_overflow_semantics);
+ new_step = chrec_convert_1 (step_type, new_step, at_stmt, use_overflow_semantics);
if (automatically_generated_chrec_p (new_base)
|| automatically_generated_chrec_p (new_step))
@@ -1304,6 +1306,36 @@ chrec_convert_rhs (tree type, tree chrec, gimple at_stmt)
determining a more accurate estimation of the number of iterations.
By default AT_STMT could be safely set to NULL_TREE.
+ The following rule is always true: TREE_TYPE (chrec) ==
+ TREE_TYPE (CHREC_LEFT (chrec)) == TREE_TYPE (CHREC_RIGHT (chrec)).
+ An example of what could happen when adding two chrecs and the type
+ of the CHREC_RIGHT is different than CHREC_LEFT is:
+
+ {(uint) 0, +, (uchar) 10} +
+ {(uint) 0, +, (uchar) 250}
+
+ that would produce a wrong result if CHREC_RIGHT is not (uint):
+
+ {(uint) 0, +, (uchar) 4}
+
+ instead of
+
+ {(uint) 0, +, (uint) 260}
+*/
+
+tree
+chrec_convert (tree type, tree chrec, gimple at_stmt)
+{
+ return chrec_convert_1 (type, chrec, at_stmt, true);
+}
+
+/* Convert CHREC to TYPE. When the analyzer knows the context in
+ which the CHREC is built, it sets AT_STMT to the statement that
+ contains the definition of the analyzed variable, otherwise the
+ conversion is less accurate: the information is used for
+ determining a more accurate estimation of the number of iterations.
+ By default AT_STMT could be safely set to NULL_TREE.
+
USE_OVERFLOW_SEMANTICS is true if this function should assume that
the rules for overflow of the given language apply (e.g., that signed
arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
@@ -1388,53 +1420,15 @@ keep_cast:
return res;
}
-/* Convert CHREC to TYPE. When the analyzer knows the context in
- which the CHREC is built, it sets AT_STMT to the statement that
- contains the definition of the analyzed variable, otherwise the
- conversion is less accurate: the information is used for
- determining a more accurate estimation of the number of iterations.
- By default AT_STMT could be safely set to NULL_TREE.
-
- The following rule is always true: TREE_TYPE (chrec) ==
- TREE_TYPE (CHREC_LEFT (chrec)) == TREE_TYPE (CHREC_RIGHT (chrec)).
- An example of what could happen when adding two chrecs and the type
- of the CHREC_RIGHT is different than CHREC_LEFT is:
-
- {(uint) 0, +, (uchar) 10} +
- {(uint) 0, +, (uchar) 250}
-
- that would produce a wrong result if CHREC_RIGHT is not (uint):
-
- {(uint) 0, +, (uchar) 4}
-
- instead of
-
- {(uint) 0, +, (uint) 260}
-
- USE_OVERFLOW_SEMANTICS is true if this function should assume that
- the rules for overflow of the given language apply (e.g., that signed
- arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
- tests, but also to enforce that the result follows them. */
-
-tree
-chrec_convert (tree type, tree chrec, gimple at_stmt,
- bool use_overflow_semantics)
-{
- return chrec_convert_1 (type, chrec, at_stmt, use_overflow_semantics);
-}
-
/* Convert CHREC to TYPE, without regard to signed overflows. Returns the new
chrec if something else than what chrec_convert would do happens, NULL_TREE
- otherwise. This function set TRUE to variable pointed by FOLD_CONVERSIONS
- if the result chrec may overflow. */
+ otherwise. */
tree
-chrec_convert_aggressive (tree type, tree chrec, bool *fold_conversions)
+chrec_convert_aggressive (tree type, tree chrec)
{
tree inner_type, left, right, lc, rc, rtype;
- gcc_assert (fold_conversions != NULL);
-
if (automatically_generated_chrec_p (chrec)
|| TREE_CODE (chrec) != POLYNOMIAL_CHREC)
return NULL_TREE;
@@ -1443,33 +1437,17 @@ chrec_convert_aggressive (tree type, tree chrec, bool *fold_conversions)
if (TYPE_PRECISION (type) > TYPE_PRECISION (inner_type))
return NULL_TREE;
- if (useless_type_conversion_p (type, inner_type))
- return NULL_TREE;
-
- if (!*fold_conversions && evolution_function_is_affine_p (chrec))
- {
- tree base, step;
- struct loop *loop;
-
- loop = get_chrec_loop (chrec);
- base = CHREC_LEFT (chrec);
- step = CHREC_RIGHT (chrec);
- if (convert_affine_scev (loop, type, &base, &step, NULL, true))
- return build_polynomial_chrec (loop->num, base, step);
- }
rtype = POINTER_TYPE_P (type) ? sizetype : type;
left = CHREC_LEFT (chrec);
right = CHREC_RIGHT (chrec);
- lc = chrec_convert_aggressive (type, left, fold_conversions);
+ lc = chrec_convert_aggressive (type, left);
if (!lc)
lc = chrec_convert (type, left, NULL);
- rc = chrec_convert_aggressive (rtype, right, fold_conversions);
+ rc = chrec_convert_aggressive (rtype, right);
if (!rc)
rc = chrec_convert (rtype, right, NULL);
- *fold_conversions = true;
-
return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc);
}
diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h
index 144ba2c3979..49cb0e21d99 100644
--- a/gcc/tree-chrec.h
+++ b/gcc/tree-chrec.h
@@ -59,9 +59,9 @@ enum ev_direction scev_direction (const_tree);
extern tree chrec_fold_plus (tree, tree, tree);
extern tree chrec_fold_minus (tree, tree, tree);
extern tree chrec_fold_multiply (tree, tree, tree);
-extern tree chrec_convert (tree, tree, gimple, bool = true);
+extern tree chrec_convert (tree, tree, gimple);
extern tree chrec_convert_rhs (tree, tree, gimple);
-extern tree chrec_convert_aggressive (tree, tree, bool *);
+extern tree chrec_convert_aggressive (tree, tree);
/* Operations. */
extern tree chrec_apply (unsigned, tree, tree);
diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
index 3a2c284b582..1b457059d0e 100644
--- a/gcc/tree-scalar-evolution.c
+++ b/gcc/tree-scalar-evolution.c
@@ -2143,7 +2143,7 @@ analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop,
/* We cannot just do
tmp = analyze_scalar_evolution (use_loop, version);
- ev = resolve_mixers (wrto_loop, tmp, folded_casts);
+ ev = resolve_mixers (wrto_loop, tmp);
as resolve_mixers would query the scalar evolution with respect to
wrto_loop. For example, in the situation described in the function
@@ -2152,9 +2152,9 @@ analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop,
analyze_scalar_evolution (use_loop, version) = k2
- and resolve_mixers (loop1, k2, folded_casts) finds that the value of
- k2 in loop 1 is 100, which is a wrong result, since we are interested
- in the value in loop 3.
+ and resolve_mixers (loop1, k2) finds that the value of k2 in loop 1
+ is 100, which is a wrong result, since we are interested in the
+ value in loop 3.
Instead, we need to proceed from use_loop to wrto_loop loop by loop,
each time checking that there is no evolution in the inner loop. */
@@ -2164,7 +2164,10 @@ analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop,
while (1)
{
tmp = analyze_scalar_evolution (use_loop, ev);
- ev = resolve_mixers (use_loop, tmp, folded_casts);
+ ev = resolve_mixers (use_loop, tmp);
+
+ if (folded_casts && tmp != ev)
+ *folded_casts = true;
if (use_loop == wrto_loop)
return ev;
@@ -2287,7 +2290,7 @@ loop_closed_phi_def (tree var)
}
static tree instantiate_scev_r (basic_block, struct loop *, struct loop *,
- tree, bool *, int);
+ tree, bool, int);
/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
and EVOLUTION_LOOP, that were left under a symbolic form.
@@ -2296,10 +2299,9 @@ static tree instantiate_scev_r (basic_block, struct loop *, struct loop *,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2308,7 +2310,7 @@ static tree
instantiate_scev_name (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
- bool *fold_conversions,
+ bool fold_conversions,
int size_expr)
{
tree res;
@@ -2402,10 +2404,9 @@ instantiate_scev_name (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2413,7 +2414,7 @@ instantiate_scev_name (basic_block instantiate_below,
static tree
instantiate_scev_poly (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *,
- tree chrec, bool *fold_conversions, int size_expr)
+ tree chrec, bool fold_conversions, int size_expr)
{
tree op1;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
@@ -2447,10 +2448,9 @@ instantiate_scev_poly (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2460,7 +2460,7 @@ instantiate_scev_binary (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, enum tree_code code,
tree type, tree c0, tree c1,
- bool *fold_conversions, int size_expr)
+ bool fold_conversions, int size_expr)
{
tree op1;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, inner_loop,
@@ -2506,10 +2506,9 @@ instantiate_scev_binary (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2517,7 +2516,7 @@ instantiate_scev_binary (basic_block instantiate_below,
static tree
instantiate_array_ref (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
- tree chrec, bool *fold_conversions, int size_expr)
+ tree chrec, bool fold_conversions, int size_expr)
{
tree res;
tree index = TREE_OPERAND (chrec, 1);
@@ -2544,10 +2543,9 @@ instantiate_array_ref (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2556,7 +2554,7 @@ static tree
instantiate_scev_convert (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree type, tree op,
- bool *fold_conversions, int size_expr)
+ bool fold_conversions, int size_expr)
{
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
inner_loop, op,
@@ -2567,21 +2565,19 @@ instantiate_scev_convert (basic_block instantiate_below,
if (fold_conversions)
{
- tree tmp = chrec_convert_aggressive (type, op0, fold_conversions);
+ tree tmp = chrec_convert_aggressive (type, op0);
if (tmp)
return tmp;
+ }
- /* If we used chrec_convert_aggressive, we can no longer assume that
- signed chrecs do not overflow, as chrec_convert does, so avoid
- calling it in that case. */
- if (*fold_conversions)
- {
- if (chrec && op0 == op)
- return chrec;
+ if (chrec && op0 == op)
+ return chrec;
- return fold_convert (type, op0);
- }
- }
+ /* If we used chrec_convert_aggressive, we can no longer assume that
+ signed chrecs do not overflow, as chrec_convert does, so avoid
+ calling it in that case. */
+ if (fold_conversions)
+ return fold_convert (type, op0);
return chrec_convert (type, op0, NULL);
}
@@ -2595,10 +2591,9 @@ instantiate_scev_convert (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2608,7 +2603,7 @@ instantiate_scev_not (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
enum tree_code code, tree type, tree op,
- bool *fold_conversions, int size_expr)
+ bool fold_conversions, int size_expr)
{
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
inner_loop, op,
@@ -2646,10 +2641,9 @@ instantiate_scev_not (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2658,7 +2652,7 @@ static tree
instantiate_scev_3 (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
- bool *fold_conversions, int size_expr)
+ bool fold_conversions, int size_expr)
{
tree op1, op2;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
@@ -2695,10 +2689,9 @@ instantiate_scev_3 (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2707,7 +2700,7 @@ static tree
instantiate_scev_2 (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
- bool *fold_conversions, int size_expr)
+ bool fold_conversions, int size_expr)
{
tree op1;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
@@ -2736,10 +2729,9 @@ instantiate_scev_2 (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2748,7 +2740,7 @@ static tree
instantiate_scev_1 (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
- bool *fold_conversions, int size_expr)
+ bool fold_conversions, int size_expr)
{
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
inner_loop, TREE_OPERAND (chrec, 0),
@@ -2770,10 +2762,9 @@ instantiate_scev_1 (basic_block instantiate_below,
CACHE is the cache of already instantiated values.
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
+ FOLD_CONVERSIONS should be set to true when the conversions that
+ may wrap in signed/pointer type are folded, as long as the value of
+ the chrec is preserved.
SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */
@@ -2782,7 +2773,7 @@ static tree
instantiate_scev_r (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
- bool *fold_conversions, int size_expr)
+ bool fold_conversions, int size_expr)
{
/* Give up if the expression is larger than the MAX that we allow. */
if (size_expr++ > PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
@@ -2907,7 +2898,7 @@ instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop,
}
res = instantiate_scev_r (instantiate_below, evolution_loop,
- NULL, chrec, NULL, 0);
+ NULL, chrec, false, 0);
if (destr)
{
@@ -2931,10 +2922,9 @@ instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop,
of an expression. */
tree
-resolve_mixers (struct loop *loop, tree chrec, bool *folded_casts)
+resolve_mixers (struct loop *loop, tree chrec)
{
bool destr = false;
- bool fold_conversions = false;
if (!global_cache)
{
global_cache = new instantiate_cache_type;
@@ -2942,10 +2932,7 @@ resolve_mixers (struct loop *loop, tree chrec, bool *folded_casts)
}
tree ret = instantiate_scev_r (block_before_loop (loop), loop, NULL,
- chrec, &fold_conversions, 0);
-
- if (folded_casts && !*folded_casts)
- *folded_casts = fold_conversions;
+ chrec, true, 0);
if (destr)
{
@@ -3398,8 +3385,7 @@ scev_const_prop (void)
&& !INTEGRAL_TYPE_P (type))
continue;
- ev = resolve_mixers (loop, analyze_scalar_evolution (loop, name),
- NULL);
+ ev = resolve_mixers (loop, analyze_scalar_evolution (loop, name));
if (!is_gimple_min_invariant (ev)
|| !may_propagate_copy (name, ev))
continue;
diff --git a/gcc/tree-scalar-evolution.h b/gcc/tree-scalar-evolution.h
index 6d312806636..eae0a9a3fa7 100644
--- a/gcc/tree-scalar-evolution.h
+++ b/gcc/tree-scalar-evolution.h
@@ -31,7 +31,7 @@ extern void scev_reset_htab (void);
extern void scev_finalize (void);
extern tree analyze_scalar_evolution (struct loop *, tree);
extern tree instantiate_scev (basic_block, struct loop *, tree);
-extern tree resolve_mixers (struct loop *, tree, bool *);
+extern tree resolve_mixers (struct loop *, tree);
extern void gather_stats_on_scev_database (void);
extern unsigned int scev_const_prop (void);
extern bool expression_expensive_p (tree);
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index bf8c3893f01..d5f33646343 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -171,10 +171,9 @@ struct iv
tree base_object; /* A memory object to that the induction variable points. */
tree step; /* Step of the iv (constant only). */
tree ssa_name; /* The ssa name with the value. */
- unsigned use_id; /* The identifier in the use if it is the case. */
bool biv_p; /* Is it a biv? */
bool have_use_for; /* Do we already have a use for it? */
- bool no_overflow; /* True if the iv doesn't overflow. */
+ unsigned use_id; /* The identifier in the use if it is the case. */
};
/* Per-ssa version information (induction variable descriptions, etc.). */
@@ -516,9 +515,9 @@ single_dom_exit (struct loop *loop)
/* Dumps information about the induction variable IV to FILE. */
void
-dump_iv (FILE *file, struct iv *iv, bool dump_name)
+dump_iv (FILE *file, struct iv *iv)
{
- if (iv->ssa_name && dump_name)
+ if (iv->ssa_name)
{
fprintf (file, "ssa name ");
print_generic_expr (file, iv->ssa_name, TDF_SLIM);
@@ -595,7 +594,7 @@ dump_use (FILE *file, struct iv_use *use)
print_generic_expr (file, *use->op_p, TDF_SLIM);
fprintf (file, "\n");
- dump_iv (file, use->iv, false);
+ dump_iv (file, use->iv);
if (use->related_cands)
{
@@ -683,7 +682,7 @@ dump_cand (FILE *file, struct iv_cand *cand)
break;
}
- dump_iv (file, iv, false);
+ dump_iv (file, iv);
}
/* Returns the info for ssa version VER. */
@@ -1005,10 +1004,10 @@ contain_complex_addr_expr (tree expr)
}
/* Allocates an induction variable with given initial value BASE and step STEP
- for loop LOOP. NO_OVERFLOW implies the iv doesn't overflow. */
+ for loop LOOP. */
static struct iv *
-alloc_iv (tree base, tree step, bool no_overflow = false)
+alloc_iv (tree base, tree step)
{
tree expr = base;
struct iv *iv = XCNEW (struct iv);
@@ -1035,24 +1034,21 @@ alloc_iv (tree base, tree step, bool no_overflow = false)
iv->have_use_for = false;
iv->use_id = 0;
iv->ssa_name = NULL_TREE;
- iv->no_overflow = no_overflow;
return iv;
}
-/* Sets STEP and BASE for induction variable IV. NO_OVERFLOW implies the IV
- doesn't overflow. */
+/* Sets STEP and BASE for induction variable IV. */
static void
-set_iv (struct ivopts_data *data, tree iv, tree base, tree step,
- bool no_overflow)
+set_iv (struct ivopts_data *data, tree iv, tree base, tree step)
{
struct version_info *info = name_info (data, iv);
gcc_assert (!info->iv);
bitmap_set_bit (data->relevant, SSA_NAME_VERSION (iv));
- info->iv = alloc_iv (base, step, no_overflow);
+ info->iv = alloc_iv (base, step);
info->iv->ssa_name = iv;
}
@@ -1074,12 +1070,31 @@ get_iv (struct ivopts_data *data, tree var)
if (!bb
|| !flow_bb_inside_loop_p (data->current_loop, bb))
- set_iv (data, var, var, build_int_cst (type, 0), true);
+ set_iv (data, var, var, build_int_cst (type, 0));
}
return name_info (data, var)->iv;
}
+/* Determines the step of a biv defined in PHI. Returns NULL if PHI does
+ not define a simple affine biv with nonzero step. */
+
+static tree
+determine_biv_step (gphi *phi)
+{
+ struct loop *loop = gimple_bb (phi)->loop_father;
+ tree name = PHI_RESULT (phi);
+ affine_iv iv;
+
+ if (virtual_operand_p (name))
+ return NULL_TREE;
+
+ if (!simple_iv (loop, loop, name, &iv, true))
+ return NULL_TREE;
+
+ return integer_zerop (iv.step) ? NULL_TREE : iv.step;
+}
+
/* Return the first non-invariant ssa var found in EXPR. */
static tree
@@ -1113,7 +1128,6 @@ static bool
find_bivs (struct ivopts_data *data)
{
gphi *phi;
- affine_iv iv;
tree step, type, base, stop;
bool found = false;
struct loop *loop = data->current_loop;
@@ -1126,16 +1140,10 @@ find_bivs (struct ivopts_data *data)
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)))
continue;
- if (virtual_operand_p (PHI_RESULT (phi)))
- continue;
-
- if (!simple_iv (loop, loop, PHI_RESULT (phi), &iv, true))
+ step = determine_biv_step (phi);
+ if (!step)
continue;
- if (integer_zerop (iv.step))
- continue;
-
- step = iv.step;
base = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (loop));
/* Stop expanding iv base at the first ssa var referred by iv step.
Ideally we should stop at any ssa var, because that's expensive
@@ -1158,7 +1166,7 @@ find_bivs (struct ivopts_data *data)
step = fold_convert (type, step);
}
- set_iv (data, PHI_RESULT (phi), base, step, iv.no_overflow);
+ set_iv (data, PHI_RESULT (phi), base, step);
found = true;
}
@@ -1261,7 +1269,7 @@ find_givs_in_stmt (struct ivopts_data *data, gimple stmt)
if (!find_givs_in_stmt_scev (data, stmt, &iv))
return;
- set_iv (data, gimple_assign_lhs (stmt), iv.base, iv.step, iv.no_overflow);
+ set_iv (data, gimple_assign_lhs (stmt), iv.base, iv.step);
}
/* Finds general ivs in basic block BB. */
@@ -1325,7 +1333,7 @@ find_induction_variables (struct ivopts_data *data)
EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i, bi)
{
if (ver_info (data, i)->iv)
- dump_iv (dump_file, ver_info (data, i)->iv, true);
+ dump_iv (dump_file, ver_info (data, i)->iv);
}
}
@@ -1355,6 +1363,10 @@ record_use (struct ivopts_data *data, tree *use_p, struct iv *iv,
use->addr_base = addr_base;
use->addr_offset = addr_offset;
+ /* To avoid showing ssa name in the dumps, if it was not reset by the
+ caller. */
+ iv->ssa_name = NULL_TREE;
+
data->iv_uses.safe_push (use);
return use;
@@ -1666,7 +1678,6 @@ idx_find_step (tree base, tree *idx, void *data)
{
struct ifs_ivopts_data *dta = (struct ifs_ivopts_data *) data;
struct iv *iv;
- bool use_overflow_semantics = false;
tree step, iv_base, iv_step, lbound, off;
struct loop *loop = dta->ivopts_data->current_loop;
@@ -1726,12 +1737,9 @@ idx_find_step (tree base, tree *idx, void *data)
iv_base = iv->base;
iv_step = iv->step;
- if (iv->no_overflow && nowrap_type_p (TREE_TYPE (iv_step)))
- use_overflow_semantics = true;
-
if (!convert_affine_scev (dta->ivopts_data->current_loop,
sizetype, &iv_base, &iv_step, dta->stmt,
- use_overflow_semantics))
+ false))
{
/* The index might wrap. */
return false;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index aab2cea358f..3ebb0f9b45c 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -31,7 +31,6 @@ along with GCC; see the file COPYING3. If not see
#include "wide-int.h"
#include "inchash.h"
#include "tree.h"
-#include "stor-layout.h"
#include "fold-const.h"
#include "calls.h"
#include "hashtab.h"
@@ -1453,7 +1452,6 @@ number_of_iterations_lt (tree type, affine_iv *iv0, affine_iv *iv1,
niter->niter = delta;
niter->max = widest_int::from (wi::from_mpz (niter_type, bnds->up, false),
TYPE_SIGN (niter_type));
- niter->control.no_overflow = true;
return true;
}
@@ -2239,9 +2237,6 @@ number_of_iterations_exit (struct loop *loop, edge exit,
return false;
niter->assumptions = boolean_false_node;
- niter->control.base = NULL_TREE;
- niter->control.step = NULL_TREE;
- niter->control.no_overflow = false;
last = last_stmt (exit->src);
if (!last)
return false;
@@ -3021,29 +3016,6 @@ record_estimate (struct loop *loop, tree bound, const widest_int &i_bound,
record_niter_bound (loop, new_i_bound, realistic, upper);
}
-/* Records the control iv analyzed in NITER for LOOP if the iv is valid
- and doesn't overflow. */
-
-static void
-record_control_iv (struct loop *loop, struct tree_niter_desc *niter)
-{
- struct control_iv *iv;
-
- if (!niter->control.base || !niter->control.step)
- return;
-
- if (!integer_onep (niter->assumptions) || !niter->control.no_overflow)
- return;
-
- iv = ggc_alloc<control_iv> ();
- iv->base = niter->control.base;
- iv->step = niter->control.step;
- iv->next = loop->control_ivs;
- loop->control_ivs = iv;
-
- return;
-}
-
/* Record the estimate on number of iterations of LOOP based on the fact that
the induction variable BASE + STEP * i evaluated in STMT does not wrap and
its values belong to the range <LOW, HIGH>. REALISTIC is true if the
@@ -3767,7 +3739,6 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
record_estimate (loop, niter, niter_desc.max,
last_stmt (ex->src),
true, ex == likely_exit, true);
- record_control_iv (loop, &niter_desc);
}
exits.release ();
@@ -4074,194 +4045,6 @@ nowrap_type_p (tree type)
return false;
}
-/* Return true if we can prove LOOP is exited before evolution of induction
- variabled {BASE, STEP} overflows with respect to its type bound. */
-
-static bool
-loop_exits_before_overflow (tree base, tree step,
- gimple at_stmt, struct loop *loop)
-{
- widest_int niter;
- struct control_iv *civ;
- struct nb_iter_bound *bound;
- tree e, delta, step_abs, unsigned_base;
- tree type = TREE_TYPE (step);
- tree unsigned_type, valid_niter;
-
- /* Don't issue signed overflow warnings. */
- fold_defer_overflow_warnings ();
-
- /* Compute the number of iterations before we reach the bound of the
- type, and verify that the loop is exited before this occurs. */
- unsigned_type = unsigned_type_for (type);
- unsigned_base = fold_convert (unsigned_type, base);
-
- if (tree_int_cst_sign_bit (step))
- {
- tree extreme = fold_convert (unsigned_type,
- lower_bound_in_type (type, type));
- delta = fold_build2 (MINUS_EXPR, unsigned_type, unsigned_base, extreme);
- step_abs = fold_build1 (NEGATE_EXPR, unsigned_type,
- fold_convert (unsigned_type, step));
- }
- else
- {
- tree extreme = fold_convert (unsigned_type,
- upper_bound_in_type (type, type));
- delta = fold_build2 (MINUS_EXPR, unsigned_type, extreme, unsigned_base);
- step_abs = fold_convert (unsigned_type, step);
- }
-
- valid_niter = fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step_abs);
-
- estimate_numbers_of_iterations_loop (loop);
-
- if (max_loop_iterations (loop, &niter)
- && wi::fits_to_tree_p (niter, TREE_TYPE (valid_niter))
- && (e = fold_binary (GT_EXPR, boolean_type_node, valid_niter,
- wide_int_to_tree (TREE_TYPE (valid_niter),
- niter))) != NULL
- && integer_nonzerop (e))
- {
- fold_undefer_and_ignore_overflow_warnings ();
- return true;
- }
- if (at_stmt)
- for (bound = loop->bounds; bound; bound = bound->next)
- {
- if (n_of_executions_at_most (at_stmt, bound, valid_niter))
- {
- fold_undefer_and_ignore_overflow_warnings ();
- return true;
- }
- }
- fold_undefer_and_ignore_overflow_warnings ();
-
- /* Try to prove loop is exited before {base, step} overflows with the
- help of analyzed loop control IV. This is done only for IVs with
- constant step because otherwise we don't have the information. */
- if (TREE_CODE (step) == INTEGER_CST)
- for (civ = loop->control_ivs; civ; civ = civ->next)
- {
- enum tree_code code;
- tree stepped, extreme, civ_type = TREE_TYPE (civ->step);
-
- /* Have to consider type difference because operand_equal_p ignores
- that for constants. */
- if (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (civ_type)
- || element_precision (type) != element_precision (civ_type))
- continue;
-
- /* Only consider control IV with same step. */
- if (!operand_equal_p (step, civ->step, 0))
- continue;
-
- /* Done proving if this is a no-overflow control IV. */
- if (operand_equal_p (base, civ->base, 0))
- return true;
-
- /* If this is a before stepping control IV, in other words, we have
-
- {civ_base, step} = {base + step, step}
-
- Because civ {base + step, step} doesn't overflow during loop
- iterations, {base, step} will not overflow if we can prove the
- operation "base + step" does not overflow. Specifically, we try
- to prove below conditions are satisfied:
-
- base <= UPPER_BOUND (type) - step ;;step > 0
- base >= LOWER_BOUND (type) - step ;;step < 0
-
- by proving the reverse conditions are false using loop's initial
- condition. */
- if (POINTER_TYPE_P (TREE_TYPE (base)))
- code = POINTER_PLUS_EXPR;
- else
- code = PLUS_EXPR;
-
- stepped = fold_build2 (code, TREE_TYPE (base), base, step);
- if (operand_equal_p (stepped, civ->base, 0))
- {
- if (tree_int_cst_sign_bit (step))
- {
- code = LT_EXPR;
- extreme = lower_bound_in_type (type, type);
- }
- else
- {
- code = GT_EXPR;
- extreme = upper_bound_in_type (type, type);
- }
- extreme = fold_build2 (MINUS_EXPR, type, extreme, step);
- e = fold_build2 (code, boolean_type_node, base, extreme);
- e = simplify_using_initial_conditions (loop, e);
- if (integer_zerop (e))
- return true;
-
- continue;
- }
-
- /* Similar to above, only in this case we have:
-
- {civ_base, step} = {(signed T)((unsigned T)base + step), step}
- && TREE_TYPE (civ_base) = signed T.
-
- We prove that below condition is satisfied:
-
- (signed T)((unsigned T)base + step)
- == (signed T)(unsigned T)base + step
- == base + step
-
- because of exact the same reason as above. This also proves
- there is no overflow in the operation "base + step", thus the
- induction variable {base, step} during loop iterations.
-
- This is necessary to handle cases as below:
-
- int foo (int *a, signed char s, signed char l)
- {
- signed char i;
- for (i = s; i < l; i++)
- a[i] = 0;
- return 0;
- }
-
- The variable I is firstly converted to type unsigned char,
- incremented, then converted back to type signed char. */
- if (!CONVERT_EXPR_P (civ->base) || TREE_TYPE (civ->base) != type)
- continue;
- e = TREE_OPERAND (civ->base, 0);
- if (TREE_CODE (e) != PLUS_EXPR
- || TREE_CODE (TREE_OPERAND (e, 1)) != INTEGER_CST
- || !operand_equal_p (step,
- fold_convert (type,
- TREE_OPERAND (e, 1)), 0))
- continue;
- e = TREE_OPERAND (e, 0);
- if (!CONVERT_EXPR_P (e) || !operand_equal_p (e, unsigned_base, 0))
- continue;
- e = TREE_OPERAND (e, 0);
- gcc_assert (operand_equal_p (e, base, 0));
- if (tree_int_cst_sign_bit (step))
- {
- code = LT_EXPR;
- extreme = lower_bound_in_type (type, type);
- }
- else
- {
- code = GT_EXPR;
- extreme = upper_bound_in_type (type, type);
- }
- extreme = fold_build2 (MINUS_EXPR, type, extreme, step);
- e = fold_build2 (code, boolean_type_node, base, extreme);
- e = simplify_using_initial_conditions (loop, e);
- if (integer_zerop (e))
- return true;
- }
-
- return false;
-}
-
/* Return false only when the induction variable BASE + STEP * I is
known to not overflow: i.e. when the number of iterations is small
enough with respect to the step and initial condition in order to
@@ -4277,6 +4060,13 @@ scev_probably_wraps_p (tree base, tree step,
gimple at_stmt, struct loop *loop,
bool use_overflow_semantics)
{
+ tree delta, step_abs;
+ tree unsigned_type, valid_niter;
+ tree type = TREE_TYPE (step);
+ tree e;
+ widest_int niter;
+ struct nb_iter_bound *bound;
+
/* FIXME: We really need something like
http://gcc.gnu.org/ml/gcc-patches/2005-06/msg02025.html.
@@ -4310,8 +4100,56 @@ scev_probably_wraps_p (tree base, tree step,
if (TREE_CODE (step) != INTEGER_CST)
return true;
- if (loop_exits_before_overflow (base, step, at_stmt, loop))
- return false;
+ /* Don't issue signed overflow warnings. */
+ fold_defer_overflow_warnings ();
+
+ /* Otherwise, compute the number of iterations before we reach the
+ bound of the type, and verify that the loop is exited before this
+ occurs. */
+ unsigned_type = unsigned_type_for (type);
+ base = fold_convert (unsigned_type, base);
+
+ if (tree_int_cst_sign_bit (step))
+ {
+ tree extreme = fold_convert (unsigned_type,
+ lower_bound_in_type (type, type));
+ delta = fold_build2 (MINUS_EXPR, unsigned_type, base, extreme);
+ step_abs = fold_build1 (NEGATE_EXPR, unsigned_type,
+ fold_convert (unsigned_type, step));
+ }
+ else
+ {
+ tree extreme = fold_convert (unsigned_type,
+ upper_bound_in_type (type, type));
+ delta = fold_build2 (MINUS_EXPR, unsigned_type, extreme, base);
+ step_abs = fold_convert (unsigned_type, step);
+ }
+
+ valid_niter = fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step_abs);
+
+ estimate_numbers_of_iterations_loop (loop);
+
+ if (max_loop_iterations (loop, &niter)
+ && wi::fits_to_tree_p (niter, TREE_TYPE (valid_niter))
+ && (e = fold_binary (GT_EXPR, boolean_type_node, valid_niter,
+ wide_int_to_tree (TREE_TYPE (valid_niter),
+ niter))) != NULL
+ && integer_nonzerop (e))
+ {
+ fold_undefer_and_ignore_overflow_warnings ();
+ return false;
+ }
+ if (at_stmt)
+ for (bound = loop->bounds; bound; bound = bound->next)
+ {
+ if (n_of_executions_at_most (at_stmt, bound, valid_niter))
+ {
+ fold_undefer_and_ignore_overflow_warnings ();
+ return false;
+ }
+ }
+
+ fold_undefer_and_ignore_overflow_warnings ();
/* At this point we still don't have a proof that the iv does not
overflow: give up. */
@@ -4323,26 +4161,17 @@ scev_probably_wraps_p (tree base, tree step,
void
free_numbers_of_iterations_estimates_loop (struct loop *loop)
{
- struct control_iv *civ;
- struct nb_iter_bound *bound;
+ struct nb_iter_bound *bound, *next;
loop->nb_iterations = NULL;
loop->estimate_state = EST_NOT_COMPUTED;
- for (bound = loop->bounds; bound;)
+ for (bound = loop->bounds; bound; bound = next)
{
- struct nb_iter_bound *next = bound->next;
+ next = bound->next;
ggc_free (bound);
- bound = next;
}
- loop->bounds = NULL;
- for (civ = loop->control_ivs; civ;)
- {
- struct control_iv *next = civ->next;
- ggc_free (civ);
- civ = next;
- }
- loop->control_ivs = NULL;
+ loop->bounds = NULL;
}
/* Frees the information on upper bounds on numbers of iterations of loops. */
diff --git a/gcc/tree-ssa-loop-niter.h b/gcc/tree-ssa-loop-niter.h
index 8d4f799c090..7134906dd80 100644
--- a/gcc/tree-ssa-loop-niter.h
+++ b/gcc/tree-ssa-loop-niter.h
@@ -41,7 +41,6 @@ extern void estimate_numbers_of_iterations (void);
extern bool stmt_dominates_stmt_p (gimple, gimple);
extern bool nowrap_type_p (tree);
extern bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool);
-extern void free_loop_control_ivs (struct loop *);
extern void free_numbers_of_iterations_estimates_loop (struct loop *);
extern void free_numbers_of_iterations_estimates (void);
extern void substitute_in_loop_info (struct loop *, tree, tree);