diff options
author | Christophe Lyon <christophe.lyon@linaro.org> | 2016-01-07 14:42:05 +0100 |
---|---|---|
committer | Linaro Code Review <review@review.linaro.org> | 2016-01-12 11:49:08 +0000 |
commit | b3cbd8a6d7b6a56e2b99e80561ad72a263c38e23 (patch) | |
tree | 0d5b64558786063ba59da28a77f86bf27abca271 | |
parent | ceed650db42cc32a57d536f612afb3dc639d52d7 (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.h | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr65447.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr66449.c | 18 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/scev-10.c | 23 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/scev-3.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/scev-4.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/scev-8.c | 62 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/scev-9.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/vect/pr48052.c | 26 | ||||
-rw-r--r-- | gcc/tree-chrec.c | 104 | ||||
-rw-r--r-- | gcc/tree-chrec.h | 4 | ||||
-rw-r--r-- | gcc/tree-scalar-evolution.c | 138 | ||||
-rw-r--r-- | gcc/tree-scalar-evolution.h | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-ivopts.c | 72 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-niter.c | 293 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-niter.h | 1 |
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); |