re PR testsuite/52563 (FAIL: gcc.dg/tree-ssa/scev-[3,4].c scan-tree-dump-times optimized "&a" 1)

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/ChangeLog
	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.

From-SVN: r224009
This commit is contained in:
Bin Cheng 2015-06-02 03:33:35 +00:00 committed by Bin Cheng
parent 81371eff9b
commit c70ed622fc
9 changed files with 212 additions and 142 deletions

View File

@ -1,3 +1,34 @@
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.
2015-06-01 Eric Botcazou <ebotcazou@adacore.com> 2015-06-01 Eric Botcazou <ebotcazou@adacore.com>
* gimplify.c (gimplify_modify_expr_rhs): Use simple test on the size. * gimplify.c (gimplify_modify_expr_rhs): Use simple test on the size.

View File

@ -1,3 +1,10 @@
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.
2015-06-01 Eric Botcazou <ebotcazou@adacore.com> 2015-06-01 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/specs/varsize_return2.ads: New test. * gnat.dg/specs/varsize_return2.ads: New test.

View File

@ -15,4 +15,4 @@ f(int k)
} }
} }
/* { dg-final { scan-tree-dump-times "&a" 1 "optimized" { xfail { lp64 || llp64 } } } } */ /* { dg-final { scan-tree-dump-times "&a" 1 "optimized" } } */

View File

@ -20,4 +20,4 @@ f(int k)
} }
} }
/* { dg-final { scan-tree-dump-times "&a" 1 "optimized" { xfail { lp64 || llp64 } } } } */ /* { dg-final { scan-tree-dump-times "&a" 1 "optimized" } } */

View File

@ -1178,8 +1178,6 @@ 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 /* 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 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 evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume that
@ -1254,8 +1252,7 @@ convert_affine_scev (struct loop *loop, tree type,
use_overflow_semantics)) use_overflow_semantics))
return false; return false;
new_base = chrec_convert_1 (type, *base, at_stmt, new_base = chrec_convert (type, *base, at_stmt, use_overflow_semantics);
use_overflow_semantics);
/* The step must be sign extended, regardless of the signedness /* The step must be sign extended, regardless of the signedness
of CT and TYPE. This only needs to be handled specially when of CT and TYPE. This only needs to be handled specially when
CT is unsigned -- to avoid e.g. unsigned char [100, +, 255] CT is unsigned -- to avoid e.g. unsigned char [100, +, 255]
@ -1266,10 +1263,11 @@ convert_affine_scev (struct loop *loop, tree type,
if (TYPE_PRECISION (step_type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct)) if (TYPE_PRECISION (step_type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct))
{ {
tree signed_ct = build_nonstandard_integer_type (TYPE_PRECISION (ct), 0); tree signed_ct = build_nonstandard_integer_type (TYPE_PRECISION (ct), 0);
new_step = chrec_convert_1 (signed_ct, new_step, at_stmt, new_step = chrec_convert (signed_ct, new_step, at_stmt,
use_overflow_semantics); use_overflow_semantics);
} }
new_step = chrec_convert_1 (step_type, new_step, at_stmt, use_overflow_semantics); new_step = chrec_convert (step_type, new_step, at_stmt,
use_overflow_semantics);
if (automatically_generated_chrec_p (new_base) if (automatically_generated_chrec_p (new_base)
|| automatically_generated_chrec_p (new_step)) || automatically_generated_chrec_p (new_step))
@ -1299,36 +1297,6 @@ chrec_convert_rhs (tree type, tree chrec, gimple at_stmt)
return chrec_convert (type, chrec, at_stmt); return chrec_convert (type, chrec, at_stmt);
} }
/* 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}
*/
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 /* Convert CHREC to TYPE. When the analyzer knows the context in
which the CHREC is built, it sets AT_STMT to the statement that which the CHREC is built, it sets AT_STMT to the statement that
contains the definition of the analyzed variable, otherwise the contains the definition of the analyzed variable, otherwise the
@ -1420,15 +1388,53 @@ keep_cast:
return res; return res;
} }
/* Convert CHREC to TYPE, without regard to signed overflows. Returns the new /* Convert CHREC to TYPE. When the analyzer knows the context in
chrec if something else than what chrec_convert would do happens, NULL_TREE which the CHREC is built, it sets AT_STMT to the statement that
otherwise. */ 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 tree
chrec_convert_aggressive (tree type, tree chrec) 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. */
tree
chrec_convert_aggressive (tree type, tree chrec, bool *fold_conversions)
{ {
tree inner_type, left, right, lc, rc, rtype; tree inner_type, left, right, lc, rc, rtype;
gcc_assert (fold_conversions != NULL);
if (automatically_generated_chrec_p (chrec) if (automatically_generated_chrec_p (chrec)
|| TREE_CODE (chrec) != POLYNOMIAL_CHREC) || TREE_CODE (chrec) != POLYNOMIAL_CHREC)
return NULL_TREE; return NULL_TREE;
@ -1437,17 +1443,33 @@ chrec_convert_aggressive (tree type, tree chrec)
if (TYPE_PRECISION (type) > TYPE_PRECISION (inner_type)) if (TYPE_PRECISION (type) > TYPE_PRECISION (inner_type))
return NULL_TREE; 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; rtype = POINTER_TYPE_P (type) ? sizetype : type;
left = CHREC_LEFT (chrec); left = CHREC_LEFT (chrec);
right = CHREC_RIGHT (chrec); right = CHREC_RIGHT (chrec);
lc = chrec_convert_aggressive (type, left); lc = chrec_convert_aggressive (type, left, fold_conversions);
if (!lc) if (!lc)
lc = chrec_convert (type, left, NULL); lc = chrec_convert (type, left, NULL);
rc = chrec_convert_aggressive (rtype, right); rc = chrec_convert_aggressive (rtype, right, fold_conversions);
if (!rc) if (!rc)
rc = chrec_convert (rtype, right, NULL); rc = chrec_convert (rtype, right, NULL);
*fold_conversions = true;
return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc); return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc);
} }

View File

@ -59,9 +59,9 @@ enum ev_direction scev_direction (const_tree);
extern tree chrec_fold_plus (tree, tree, tree); extern tree chrec_fold_plus (tree, tree, tree);
extern tree chrec_fold_minus (tree, tree, tree); extern tree chrec_fold_minus (tree, tree, tree);
extern tree chrec_fold_multiply (tree, tree, tree); extern tree chrec_fold_multiply (tree, tree, tree);
extern tree chrec_convert (tree, tree, gimple); extern tree chrec_convert (tree, tree, gimple, bool = true);
extern tree chrec_convert_rhs (tree, tree, gimple); extern tree chrec_convert_rhs (tree, tree, gimple);
extern tree chrec_convert_aggressive (tree, tree); extern tree chrec_convert_aggressive (tree, tree, bool *);
/* Operations. */ /* Operations. */
extern tree chrec_apply (unsigned, tree, tree); extern tree chrec_apply (unsigned, tree, tree);

View File

@ -2145,7 +2145,7 @@ analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop,
/* We cannot just do /* We cannot just do
tmp = analyze_scalar_evolution (use_loop, version); tmp = analyze_scalar_evolution (use_loop, version);
ev = resolve_mixers (wrto_loop, tmp); ev = resolve_mixers (wrto_loop, tmp, folded_casts);
as resolve_mixers would query the scalar evolution with respect to as resolve_mixers would query the scalar evolution with respect to
wrto_loop. For example, in the situation described in the function wrto_loop. For example, in the situation described in the function
@ -2154,9 +2154,9 @@ analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop,
analyze_scalar_evolution (use_loop, version) = k2 analyze_scalar_evolution (use_loop, version) = k2
and resolve_mixers (loop1, k2) finds that the value of k2 in loop 1 and resolve_mixers (loop1, k2, folded_casts) finds that the value of
is 100, which is a wrong result, since we are interested in the k2 in loop 1 is 100, which is a wrong result, since we are interested
value in loop 3. in the value in loop 3.
Instead, we need to proceed from use_loop to wrto_loop loop by loop, 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. */ each time checking that there is no evolution in the inner loop. */
@ -2166,10 +2166,7 @@ analyze_scalar_evolution_in_loop (struct loop *wrto_loop, struct loop *use_loop,
while (1) while (1)
{ {
tmp = analyze_scalar_evolution (use_loop, ev); tmp = analyze_scalar_evolution (use_loop, ev);
ev = resolve_mixers (use_loop, tmp); ev = resolve_mixers (use_loop, tmp, folded_casts);
if (folded_casts && tmp != ev)
*folded_casts = true;
if (use_loop == wrto_loop) if (use_loop == wrto_loop)
return ev; return ev;
@ -2292,7 +2289,7 @@ loop_closed_phi_def (tree var)
} }
static tree instantiate_scev_r (basic_block, struct loop *, struct loop *, 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 /* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
and EVOLUTION_LOOP, that were left under a symbolic form. and EVOLUTION_LOOP, that were left under a symbolic form.
@ -2301,9 +2298,10 @@ static tree instantiate_scev_r (basic_block, struct loop *, struct loop *,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2312,7 +2310,7 @@ static tree
instantiate_scev_name (basic_block instantiate_below, instantiate_scev_name (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree chrec,
bool fold_conversions, bool *fold_conversions,
int size_expr) int size_expr)
{ {
tree res; tree res;
@ -2406,9 +2404,10 @@ instantiate_scev_name (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2416,7 +2415,7 @@ instantiate_scev_name (basic_block instantiate_below,
static tree static tree
instantiate_scev_poly (basic_block instantiate_below, instantiate_scev_poly (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *, 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 op1;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
@ -2450,9 +2449,10 @@ instantiate_scev_poly (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2462,7 +2462,7 @@ instantiate_scev_binary (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, enum tree_code code, tree chrec, enum tree_code code,
tree type, tree c0, tree c1, tree type, tree c0, tree c1,
bool fold_conversions, int size_expr) bool *fold_conversions, int size_expr)
{ {
tree op1; tree op1;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, inner_loop, tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, inner_loop,
@ -2508,9 +2508,10 @@ instantiate_scev_binary (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2518,7 +2519,7 @@ instantiate_scev_binary (basic_block instantiate_below,
static tree static tree
instantiate_array_ref (basic_block instantiate_below, instantiate_array_ref (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, 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 res;
tree index = TREE_OPERAND (chrec, 1); tree index = TREE_OPERAND (chrec, 1);
@ -2545,9 +2546,10 @@ instantiate_array_ref (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2556,7 +2558,7 @@ static tree
instantiate_scev_convert (basic_block instantiate_below, instantiate_scev_convert (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree type, tree op, 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, tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
inner_loop, op, inner_loop, op,
@ -2567,19 +2569,21 @@ instantiate_scev_convert (basic_block instantiate_below,
if (fold_conversions) if (fold_conversions)
{ {
tree tmp = chrec_convert_aggressive (type, op0); tree tmp = chrec_convert_aggressive (type, op0, fold_conversions);
if (tmp) if (tmp)
return tmp; return tmp;
}
if (chrec && op0 == op)
return chrec;
/* If we used chrec_convert_aggressive, we can no longer assume that /* If we used chrec_convert_aggressive, we can no longer assume that
signed chrecs do not overflow, as chrec_convert does, so avoid signed chrecs do not overflow, as chrec_convert does, so avoid
calling it in that case. */ calling it in that case. */
if (fold_conversions) if (*fold_conversions)
{
if (chrec && op0 == op)
return chrec;
return fold_convert (type, op0); return fold_convert (type, op0);
}
}
return chrec_convert (type, op0, NULL); return chrec_convert (type, op0, NULL);
} }
@ -2593,9 +2597,10 @@ instantiate_scev_convert (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2605,7 +2610,7 @@ instantiate_scev_not (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree chrec,
enum tree_code code, tree type, tree op, 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, tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
inner_loop, op, inner_loop, op,
@ -2643,9 +2648,10 @@ instantiate_scev_not (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2654,7 +2660,7 @@ static tree
instantiate_scev_3 (basic_block instantiate_below, instantiate_scev_3 (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree chrec,
bool fold_conversions, int size_expr) bool *fold_conversions, int size_expr)
{ {
tree op1, op2; tree op1, op2;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
@ -2691,9 +2697,10 @@ instantiate_scev_3 (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2702,7 +2709,7 @@ static tree
instantiate_scev_2 (basic_block instantiate_below, instantiate_scev_2 (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree chrec,
bool fold_conversions, int size_expr) bool *fold_conversions, int size_expr)
{ {
tree op1; tree op1;
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
@ -2731,9 +2738,10 @@ instantiate_scev_2 (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2742,7 +2750,7 @@ static tree
instantiate_scev_1 (basic_block instantiate_below, instantiate_scev_1 (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree chrec,
bool fold_conversions, int size_expr) bool *fold_conversions, int size_expr)
{ {
tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
inner_loop, TREE_OPERAND (chrec, 0), inner_loop, TREE_OPERAND (chrec, 0),
@ -2764,9 +2772,10 @@ instantiate_scev_1 (basic_block instantiate_below,
CACHE is the cache of already instantiated values. CACHE is the cache of already instantiated values.
FOLD_CONVERSIONS should be set to true when the conversions that Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
may wrap in signed/pointer type are folded, as long as the value of conversions that may wrap in signed/pointer type are folded, as long
the chrec is preserved. as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
then we don't do such fold.
SIZE_EXPR is used for computing the size of the expression to be SIZE_EXPR is used for computing the size of the expression to be
instantiated, and to stop if it exceeds some limit. */ instantiated, and to stop if it exceeds some limit. */
@ -2775,7 +2784,7 @@ static tree
instantiate_scev_r (basic_block instantiate_below, instantiate_scev_r (basic_block instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop, struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, 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. */ /* Give up if the expression is larger than the MAX that we allow. */
if (size_expr++ > PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) if (size_expr++ > PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
@ -2900,7 +2909,7 @@ instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop,
} }
res = instantiate_scev_r (instantiate_below, evolution_loop, res = instantiate_scev_r (instantiate_below, evolution_loop,
NULL, chrec, false, 0); NULL, chrec, NULL, 0);
if (destr) if (destr)
{ {
@ -2924,9 +2933,10 @@ instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop,
of an expression. */ of an expression. */
tree tree
resolve_mixers (struct loop *loop, tree chrec) resolve_mixers (struct loop *loop, tree chrec, bool *folded_casts)
{ {
bool destr = false; bool destr = false;
bool fold_conversions = false;
if (!global_cache) if (!global_cache)
{ {
global_cache = new instantiate_cache_type; global_cache = new instantiate_cache_type;
@ -2934,7 +2944,10 @@ resolve_mixers (struct loop *loop, tree chrec)
} }
tree ret = instantiate_scev_r (block_before_loop (loop), loop, NULL, tree ret = instantiate_scev_r (block_before_loop (loop), loop, NULL,
chrec, true, 0); chrec, &fold_conversions, 0);
if (folded_casts && !*folded_casts)
*folded_casts = fold_conversions;
if (destr) if (destr)
{ {
@ -3387,7 +3400,8 @@ scev_const_prop (void)
&& !INTEGRAL_TYPE_P (type)) && !INTEGRAL_TYPE_P (type))
continue; continue;
ev = resolve_mixers (loop, analyze_scalar_evolution (loop, name)); ev = resolve_mixers (loop, analyze_scalar_evolution (loop, name),
NULL);
if (!is_gimple_min_invariant (ev) if (!is_gimple_min_invariant (ev)
|| !may_propagate_copy (name, ev)) || !may_propagate_copy (name, ev))
continue; continue;

View File

@ -31,7 +31,7 @@ extern void scev_reset_htab (void);
extern void scev_finalize (void); extern void scev_finalize (void);
extern tree analyze_scalar_evolution (struct loop *, tree); extern tree analyze_scalar_evolution (struct loop *, tree);
extern tree instantiate_scev (basic_block, struct loop *, tree); extern tree instantiate_scev (basic_block, struct loop *, tree);
extern tree resolve_mixers (struct loop *, tree); extern tree resolve_mixers (struct loop *, tree, bool *);
extern void gather_stats_on_scev_database (void); extern void gather_stats_on_scev_database (void);
extern unsigned int scev_const_prop (void); extern unsigned int scev_const_prop (void);
extern bool expression_expensive_p (tree); extern bool expression_expensive_p (tree);

View File

@ -171,9 +171,10 @@ struct iv
tree base_object; /* A memory object to that the induction variable points. */ tree base_object; /* A memory object to that the induction variable points. */
tree step; /* Step of the iv (constant only). */ tree step; /* Step of the iv (constant only). */
tree ssa_name; /* The ssa name with the value. */ 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 biv_p; /* Is it a biv? */
bool have_use_for; /* Do we already have a use for it? */ bool have_use_for; /* Do we already have a use for it? */
unsigned use_id; /* The identifier in the use if it is the case. */ bool no_overflow; /* True if the iv doesn't overflow. */
}; };
/* Per-ssa version information (induction variable descriptions, etc.). */ /* Per-ssa version information (induction variable descriptions, etc.). */
@ -1005,10 +1006,10 @@ contain_complex_addr_expr (tree expr)
} }
/* Allocates an induction variable with given initial value BASE and step STEP /* Allocates an induction variable with given initial value BASE and step STEP
for loop LOOP. */ for loop LOOP. NO_OVERFLOW implies the iv doesn't overflow. */
static struct iv * static struct iv *
alloc_iv (tree base, tree step) alloc_iv (tree base, tree step, bool no_overflow = false)
{ {
tree expr = base; tree expr = base;
struct iv *iv = XCNEW (struct iv); struct iv *iv = XCNEW (struct iv);
@ -1035,21 +1036,24 @@ alloc_iv (tree base, tree step)
iv->have_use_for = false; iv->have_use_for = false;
iv->use_id = 0; iv->use_id = 0;
iv->ssa_name = NULL_TREE; iv->ssa_name = NULL_TREE;
iv->no_overflow = no_overflow;
return iv; return iv;
} }
/* Sets STEP and BASE for induction variable IV. */ /* Sets STEP and BASE for induction variable IV. NO_OVERFLOW implies the IV
doesn't overflow. */
static void static void
set_iv (struct ivopts_data *data, tree iv, tree base, tree step) set_iv (struct ivopts_data *data, tree iv, tree base, tree step,
bool no_overflow)
{ {
struct version_info *info = name_info (data, iv); struct version_info *info = name_info (data, iv);
gcc_assert (!info->iv); gcc_assert (!info->iv);
bitmap_set_bit (data->relevant, SSA_NAME_VERSION (iv)); bitmap_set_bit (data->relevant, SSA_NAME_VERSION (iv));
info->iv = alloc_iv (base, step); info->iv = alloc_iv (base, step, no_overflow);
info->iv->ssa_name = iv; info->iv->ssa_name = iv;
} }
@ -1071,31 +1075,12 @@ get_iv (struct ivopts_data *data, tree var)
if (!bb if (!bb
|| !flow_bb_inside_loop_p (data->current_loop, bb)) || !flow_bb_inside_loop_p (data->current_loop, bb))
set_iv (data, var, var, build_int_cst (type, 0)); set_iv (data, var, var, build_int_cst (type, 0), true);
} }
return name_info (data, var)->iv; 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. */ /* Return the first non-invariant ssa var found in EXPR. */
static tree static tree
@ -1129,6 +1114,7 @@ static bool
find_bivs (struct ivopts_data *data) find_bivs (struct ivopts_data *data)
{ {
gphi *phi; gphi *phi;
affine_iv iv;
tree step, type, base, stop; tree step, type, base, stop;
bool found = false; bool found = false;
struct loop *loop = data->current_loop; struct loop *loop = data->current_loop;
@ -1141,10 +1127,16 @@ find_bivs (struct ivopts_data *data)
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi))) if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)))
continue; continue;
step = determine_biv_step (phi); if (virtual_operand_p (PHI_RESULT (phi)))
if (!step)
continue; continue;
if (!simple_iv (loop, loop, PHI_RESULT (phi), &iv, true))
continue;
if (integer_zerop (iv.step))
continue;
step = iv.step;
base = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (loop)); base = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (loop));
/* Stop expanding iv base at the first ssa var referred by iv step. /* 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 Ideally we should stop at any ssa var, because that's expensive
@ -1167,7 +1159,7 @@ find_bivs (struct ivopts_data *data)
step = fold_convert (type, step); step = fold_convert (type, step);
} }
set_iv (data, PHI_RESULT (phi), base, step); set_iv (data, PHI_RESULT (phi), base, step, iv.no_overflow);
found = true; found = true;
} }
@ -1270,7 +1262,7 @@ find_givs_in_stmt (struct ivopts_data *data, gimple stmt)
if (!find_givs_in_stmt_scev (data, stmt, &iv)) if (!find_givs_in_stmt_scev (data, stmt, &iv))
return; return;
set_iv (data, gimple_assign_lhs (stmt), iv.base, iv.step); set_iv (data, gimple_assign_lhs (stmt), iv.base, iv.step, iv.no_overflow);
} }
/* Finds general ivs in basic block BB. */ /* Finds general ivs in basic block BB. */
@ -1683,6 +1675,7 @@ idx_find_step (tree base, tree *idx, void *data)
{ {
struct ifs_ivopts_data *dta = (struct ifs_ivopts_data *) data; struct ifs_ivopts_data *dta = (struct ifs_ivopts_data *) data;
struct iv *iv; struct iv *iv;
bool use_overflow_semantics = false;
tree step, iv_base, iv_step, lbound, off; tree step, iv_base, iv_step, lbound, off;
struct loop *loop = dta->ivopts_data->current_loop; struct loop *loop = dta->ivopts_data->current_loop;
@ -1742,9 +1735,12 @@ idx_find_step (tree base, tree *idx, void *data)
iv_base = iv->base; iv_base = iv->base;
iv_step = iv->step; 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, if (!convert_affine_scev (dta->ivopts_data->current_loop,
sizetype, &iv_base, &iv_step, dta->stmt, sizetype, &iv_base, &iv_step, dta->stmt,
false)) use_overflow_semantics))
{ {
/* The index might wrap. */ /* The index might wrap. */
return false; return false;