From be17328916770319a04f236f42aaf12404bad162 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Tue, 10 May 2011 09:57:50 +0000 Subject: [PATCH] tree-ssa-forwprop.c (combine_conversions): Pattern-match a series of conversions and apply foldings similar to what... 2011-05-10 Richard Guenther * 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 --- gcc/ChangeLog | 7 + gcc/testsuite/ChangeLog | 9 ++ gcc/testsuite/gcc.dg/tree-ssa/scev-cast.c | 22 +-- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-2.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-3.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-4.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-5.c | 2 +- gcc/tree-ssa-forwprop.c | 167 ++++++++++++++++++++++ 8 files changed, 199 insertions(+), 14 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b98c1231760..7e5d7b957d3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2011-05-10 Richard Guenther + + * 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 PR tree-optimization/48611 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c63b45e58b5..f57c040561e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2011-05-10 Richard Guenther + + * 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 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 2cf245460ee..8120dad7fe9 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 9bf9525d502..f85c06139f2 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 e68c9eb7bc4..6813b432302 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 b69b3f654d1..96738305bbc 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 2685d91b12e..e6010ca0318 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 7990c5b5598..65e058d7231 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); } -- 2.30.2