tree-ssa-forwprop.c (combine_conversions): Pattern-match a series of conversions and apply foldings similar to what...

2011-05-10  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-forwprop.c (combine_conversions): Pattern-match
	a series of conversions and apply foldings similar to what
	fold-const does.
	(tree_ssa_forward_propagate_single_use_vars): Call it.

	* gcc.dg/tree-ssa/ssa-fre-2.c: Disable forwprop.
	* gcc.dg/tree-ssa/ssa-fre-3.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-4.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-5.c: Likewise.
	* gcc.dg/tree-ssa/scev-cast.c: Adjust.  Note what transformation
	applies.

From-SVN: r173612
This commit is contained in:
Richard Guenther 2011-05-10 09:57:50 +00:00 committed by Richard Biener
parent 6ae70ea2e6
commit be17328916
8 changed files with 199 additions and 14 deletions

View File

@ -1,3 +1,10 @@
2011-05-10 Richard Guenther <rguenther@suse.de>
* tree-ssa-forwprop.c (combine_conversions): Pattern-match
a series of conversions and apply foldings similar to what
fold-const does.
(tree_ssa_forward_propagate_single_use_vars): Call it.
2011-05-10 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/48611

View File

@ -1,3 +1,12 @@
2011-05-10 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/ssa-fre-2.c: Disable forwprop.
* gcc.dg/tree-ssa/ssa-fre-3.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-4.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-5.c: Likewise.
* gcc.dg/tree-ssa/scev-cast.c: Adjust. Note what transformation
applies.
2011-05-10 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/48611

View File

@ -3,24 +3,26 @@
/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
void blas (char xxx);
void blas (signed char xxx);
void blau (unsigned char xxx);
void tst(void)
{
unsigned i;
for (i = 0; i < 128; i++) /* This cast to char has to be preserved. */
blas ((char) i);
for (i = 0; i < 127; i++) /* And this one does not. */
blas ((char) i);
for (i = 0; i < 255; i++) /* This cast is not necessary. */
for (i = 0; i < 129; i++) /* This truncation to char has to be preserved. */
blas ((signed char) i);
for (i = 0; i < 128; i++) /* This one is not necessary, but nothing eliminates it. */
blas ((signed char) i);
for (i = 0; i < 127; i++) /* This one is not necessary, IVOPTS eliminates it. */
blas ((signed char) i);
for (i = 0; i < 256; i++) /* This one is not necessary, VRP eliminates it. */
blau ((unsigned char) i);
for (i = 0; i < 257; i++) /* This one is necessary. */
blau ((unsigned char) i);
for (i = 0; i < 256; i++)
blau ((unsigned char) i); /* This one is necessary. */
}
/* { dg-final { scan-tree-dump-times "= \\(unsigned char\\)" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "= \\(char\\)" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "& 255" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "= \\(signed char\\)" 2 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-fre1-details" } */
/* { dg-options "-O -fno-tree-forwprop -fdump-tree-fre1-details" } */
/* From PR14287. */

View File

@ -6,7 +6,7 @@
When the condition is true, we distribute "(int) (a + b)" as
"(int) a + (int) b", otherwise we keep the original. */
/* { dg-do compile { target { { ! mips64 } && { ! spu-*-* } } } } */
/* { dg-options "-O -fwrapv -fdump-tree-fre1-details" } */
/* { dg-options "-O -fno-tree-forwprop -fwrapv -fdump-tree-fre1-details" } */
/* From PR14844. */

View File

@ -1,7 +1,7 @@
/* If the target returns false for TARGET_PROMOTE_PROTOTYPES, then there
will be no casts for FRE to eliminate and the test will fail. */
/* { dg-do compile { target i?86-*-* x86_64-*-* hppa*-*-* mips*-*-* m68k*-*-* } } */
/* { dg-options "-O -fdump-tree-fre1-details" } */
/* { dg-options "-O -fno-tree-forwprop -fdump-tree-fre1-details" } */
/* From PR21608. */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-fre1-details" } */
/* { dg-options "-O -fno-tree-forwprop -fdump-tree-fre1-details" } */
/* From PR19792. */

View File

@ -1938,6 +1938,166 @@ out:
return false;
}
/* Combine two conversions in a row for the second conversion at *GSI.
Returns true if there were any changes made. */
static bool
combine_conversions (gimple_stmt_iterator *gsi)
{
gimple stmt = gsi_stmt (*gsi);
gimple def_stmt;
tree op0, lhs;
enum tree_code code = gimple_assign_rhs_code (stmt);
gcc_checking_assert (CONVERT_EXPR_CODE_P (code)
|| code == FLOAT_EXPR
|| code == FIX_TRUNC_EXPR);
lhs = gimple_assign_lhs (stmt);
op0 = gimple_assign_rhs1 (stmt);
if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (op0)))
{
gimple_assign_set_rhs_code (stmt, TREE_CODE (op0));
return true;
}
if (TREE_CODE (op0) != SSA_NAME)
return false;
def_stmt = SSA_NAME_DEF_STMT (op0);
if (!is_gimple_assign (def_stmt))
return false;
if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
{
tree defop0 = gimple_assign_rhs1 (def_stmt);
tree type = TREE_TYPE (lhs);
tree inside_type = TREE_TYPE (defop0);
tree inter_type = TREE_TYPE (op0);
int inside_int = INTEGRAL_TYPE_P (inside_type);
int inside_ptr = POINTER_TYPE_P (inside_type);
int inside_float = FLOAT_TYPE_P (inside_type);
int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
unsigned int inside_prec = TYPE_PRECISION (inside_type);
int inside_unsignedp = TYPE_UNSIGNED (inside_type);
int inter_int = INTEGRAL_TYPE_P (inter_type);
int inter_ptr = POINTER_TYPE_P (inter_type);
int inter_float = FLOAT_TYPE_P (inter_type);
int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
unsigned int inter_prec = TYPE_PRECISION (inter_type);
int inter_unsignedp = TYPE_UNSIGNED (inter_type);
int final_int = INTEGRAL_TYPE_P (type);
int final_ptr = POINTER_TYPE_P (type);
int final_float = FLOAT_TYPE_P (type);
int final_vec = TREE_CODE (type) == VECTOR_TYPE;
unsigned int final_prec = TYPE_PRECISION (type);
int final_unsignedp = TYPE_UNSIGNED (type);
/* In addition to the cases of two conversions in a row
handled below, if we are converting something to its own
type via an object of identical or wider precision, neither
conversion is needed. */
if (useless_type_conversion_p (type, inside_type)
&& (((inter_int || inter_ptr) && final_int)
|| (inter_float && final_float))
&& inter_prec >= final_prec)
{
gimple_assign_set_rhs1 (stmt, unshare_expr (defop0));
gimple_assign_set_rhs_code (stmt, TREE_CODE (defop0));
update_stmt (stmt);
return true;
}
/* Likewise, if the intermediate and initial types are either both
float or both integer, we don't need the middle conversion if the
former is wider than the latter and doesn't change the signedness
(for integers). Avoid this if the final type is a pointer since
then we sometimes need the middle conversion. Likewise if the
final type has a precision not equal to the size of its mode. */
if (((inter_int && inside_int)
|| (inter_float && inside_float)
|| (inter_vec && inside_vec))
&& inter_prec >= inside_prec
&& (inter_float || inter_vec
|| inter_unsignedp == inside_unsignedp)
&& ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_type))
&& ! final_ptr
&& (! final_vec || inter_prec == inside_prec))
{
gimple_assign_set_rhs1 (stmt, defop0);
update_stmt (stmt);
return true;
}
/* If we have a sign-extension of a zero-extended value, we can
replace that by a single zero-extension. */
if (inside_int && inter_int && final_int
&& inside_prec < inter_prec && inter_prec < final_prec
&& inside_unsignedp && !inter_unsignedp)
{
gimple_assign_set_rhs1 (stmt, defop0);
update_stmt (stmt);
return true;
}
/* Two conversions in a row are not needed unless:
- some conversion is floating-point (overstrict for now), or
- some conversion is a vector (overstrict for now), or
- the intermediate type is narrower than both initial and
final, or
- the intermediate type and innermost type differ in signedness,
and the outermost type is wider than the intermediate, or
- the initial type is a pointer type and the precisions of the
intermediate and final types differ, or
- the final type is a pointer type and the precisions of the
initial and intermediate types differ. */
if (! inside_float && ! inter_float && ! final_float
&& ! inside_vec && ! inter_vec && ! final_vec
&& (inter_prec >= inside_prec || inter_prec >= final_prec)
&& ! (inside_int && inter_int
&& inter_unsignedp != inside_unsignedp
&& inter_prec < final_prec)
&& ((inter_unsignedp && inter_prec > inside_prec)
== (final_unsignedp && final_prec > inter_prec))
&& ! (inside_ptr && inter_prec != final_prec)
&& ! (final_ptr && inside_prec != inter_prec)
&& ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_type)))
{
gimple_assign_set_rhs1 (stmt, defop0);
update_stmt (stmt);
return true;
}
/* A truncation to an unsigned type should be canonicalized as
bitwise and of a mask. */
if (final_int && inter_int && inside_int
&& final_prec == inside_prec
&& final_prec > inter_prec
&& inter_unsignedp)
{
tree tem;
tem = fold_build2 (BIT_AND_EXPR, inside_type,
defop0,
double_int_to_tree
(inside_type, double_int_mask (inter_prec)));
if (!useless_type_conversion_p (type, inside_type))
{
tem = force_gimple_operand_gsi (gsi, tem, true, NULL_TREE, true,
GSI_SAME_STMT);
gimple_assign_set_rhs1 (stmt, tem);
}
else
gimple_assign_set_rhs_from_tree (gsi, tem);
update_stmt (gsi_stmt (*gsi));
return true;
}
}
return false;
}
/* Main entry point for the forward propagation optimizer. */
static unsigned int
@ -2061,6 +2221,13 @@ tree_ssa_forward_propagate_single_use_vars (void)
cfg_changed |= associate_plusminus (stmt);
gsi_next (&gsi);
}
else if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
|| gimple_assign_rhs_code (stmt) == FLOAT_EXPR
|| gimple_assign_rhs_code (stmt) == FIX_TRUNC_EXPR)
{
if (!combine_conversions (&gsi))
gsi_next (&gsi);
}
else
gsi_next (&gsi);
}