Commit c70ed622 by Bin Cheng Committed by Bin Cheng

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
parent 81371eff
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.
......
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.
......
...@@ -15,4 +15,4 @@ f(int k) ...@@ -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" } } */
...@@ -20,4 +20,4 @@ f(int k) ...@@ -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" } } */
...@@ -1178,8 +1178,6 @@ nb_vars_in_chrec (tree chrec) ...@@ -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, ...@@ -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, ...@@ -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))
...@@ -1306,36 +1304,6 @@ chrec_convert_rhs (tree type, tree chrec, gimple at_stmt) ...@@ -1306,36 +1304,6 @@ chrec_convert_rhs (tree type, tree chrec, gimple at_stmt)
determining a more accurate estimation of the number of iterations. determining a more accurate estimation of the number of iterations.
By default AT_STMT could be safely set to NULL_TREE. 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 USE_OVERFLOW_SEMANTICS is true if this function should assume that
the rules for overflow of the given language apply (e.g., that signed 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 arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
...@@ -1420,15 +1388,53 @@ keep_cast: ...@@ -1420,15 +1388,53 @@ keep_cast:
return res; 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 /* 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 chrec if something else than what chrec_convert would do happens, NULL_TREE
otherwise. */ otherwise. This function set TRUE to variable pointed by FOLD_CONVERSIONS
if the result chrec may overflow. */
tree tree
chrec_convert_aggressive (tree type, tree chrec) 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) ...@@ -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);
} }
......
...@@ -59,9 +59,9 @@ enum ev_direction scev_direction (const_tree); ...@@ -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);
......
...@@ -31,7 +31,7 @@ extern void scev_reset_htab (void); ...@@ -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);
......
...@@ -171,9 +171,10 @@ struct iv ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment