aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2011-05-10 09:57:50 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2011-05-10 09:57:50 +0000
commitbe17328916770319a04f236f42aaf12404bad162 (patch)
tree29206a7d5e93403b2d8ad01b15c16501a9d9603c /gcc
parent6ae70ea2e6f12a97415896b4721bf4df536e3b09 (diff)
downloadgcc-be17328916770319a04f236f42aaf12404bad162.zip
gcc-be17328916770319a04f236f42aaf12404bad162.tar.gz
gcc-be17328916770319a04f236f42aaf12404bad162.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c22
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c2
-rw-r--r--gcc/tree-ssa-forwprop.c167
8 files changed, 199 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b98c123..7e5d7b9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c63b45e..f57c040 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c
index 2cf2454..8120dad 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c
index 9bf9525..f85c061 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c
index e68c9eb..6813b43 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c
index b69b3f6..9673830 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c
@@ -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. */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c
index 2685d91..e6010ca 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c
@@ -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. */
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index 7990c5b..65e058d 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -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);
}