From 1e51d0a29dbfebe6c0df58739562644c1a50f3c3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Sun, 9 Nov 2014 11:27:00 +0000 Subject: [PATCH] match.pd: Add patterns convering two conversions in a row from fold-const.c. 2014-11-09 Richard Biener * match.pd: Add patterns convering two conversions in a row from fold-const.c. * fold-const.c (fold_unary_loc): Remove them here. * tree-ssa-forwprop.c (combine_conversions): Likewise. * genmatch.c (dt_node::gen_kids): Check whether we may follow SSA use-def chains. * g++.dg/cpp0x/constexpr-reinterpret1.C: XFAIL. * gcc.dg/tree-ssa/pr21031.c: XFAIL. From-SVN: r217260 --- gcc/ChangeLog | 9 ++ gcc/fold-const.c | 88 ------------------ gcc/genmatch.c | 3 +- gcc/match.pd | 93 +++++++++++++++++++ gcc/testsuite/ChangeLog | 5 + .../g++.dg/cpp0x/constexpr-reinterpret1.C | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr21031.c | 2 +- gcc/tree-ssa-forwprop.c | 89 ------------------ 8 files changed, 111 insertions(+), 180 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4a513935160..5f7edb2f69f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2014-11-09 Richard Biener + + * match.pd: Add patterns convering two conversions in a row + from fold-const.c. + * fold-const.c (fold_unary_loc): Remove them here. + * tree-ssa-forwprop.c (combine_conversions): Likewise. + * genmatch.c (dt_node::gen_kids): Check whether we may + follow SSA use-def chains. + 2014-11-08 Richard Sandiford * config/aarch64/aarch64.c: Include rtl-iter.h. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index c712213444c..13faf0c524a 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -7692,94 +7692,6 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) constant_boolean_node (false, type)); } - /* Handle cases of two conversions in a row. */ - if (CONVERT_EXPR_P (op0)) - { - tree inside_type = TREE_TYPE (TREE_OPERAND (op0, 0)); - 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 (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (type) - && (((inter_int || inter_ptr) && final_int) - || (inter_float && final_float)) - && inter_prec >= final_prec) - return fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 0)); - - /* 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_PRECISION (TYPE_MODE (type)) - && TYPE_MODE (type) == TYPE_MODE (inter_type)) - && ! final_ptr - && (! final_vec || inter_prec == inside_prec)) - return fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 0)); - - /* If we have a sign-extension of a zero-extended value, we can - replace that by a single zero-extension. Likewise if the - final conversion does not change precision we can drop the - intermediate conversion. */ - if (inside_int && inter_int && final_int - && ((inside_prec < inter_prec && inter_prec < final_prec - && inside_unsignedp && !inter_unsignedp) - || final_prec == inter_prec)) - return fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 0)); - - /* 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_PRECISION (TYPE_MODE (type)) - && TYPE_MODE (type) == TYPE_MODE (inter_type))) - return fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 0)); - } - /* Handle (T *)&A.B.C for A being of type T and B and C living at offset zero. This occurs frequently in C++ upcasting and then accessing the base. */ diff --git a/gcc/genmatch.c b/gcc/genmatch.c index e01f7b31e52..723de193ad5 100644 --- a/gcc/genmatch.c +++ b/gcc/genmatch.c @@ -1615,7 +1615,7 @@ dt_operand::gen_gimple_expr (FILE *f) else fprintf (f, "tree %s = gimple_call_arg (def_stmt, %u);\n", child_opname, i); - fprintf (f, "if ((%s = do_valueize (valueize, %s)) != 0)\n", + fprintf (f, "if ((%s = do_valueize (valueize, %s)))\n", child_opname, child_opname); fprintf (f, "{\n"); } @@ -1726,6 +1726,7 @@ dt_node::gen_kids (FILE *f, bool gimple) if (exprs_len || fns_len) { fprintf (f, "case SSA_NAME:\n"); + fprintf (f, "if (do_valueize (valueize, %s) != NULL_TREE)\n", kid_opname); fprintf (f, "{\n"); fprintf (f, "gimple def_stmt = SSA_NAME_DEF_STMT (%s);\n", kid_opname); diff --git a/gcc/match.pd b/gcc/match.pd index 1c8b8db4658..a847e820f6d 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -319,3 +319,96 @@ along with GCC; see the file COPYING3. If not see (simplify (paren (paren@1 @0)) @1) + +/* Handle cases of two conversions in a row. */ +(for ocvt (convert float fix_trunc) + (for icvt (convert float) + (simplify + (ocvt (icvt@1 @0)) + (with + { + tree inside_type = TREE_TYPE (@0); + tree inter_type = TREE_TYPE (@1); + 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 (((GIMPLE && useless_type_conversion_p (type, inside_type)) + || (GENERIC + && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (inside_type))) + && (((inter_int || inter_ptr) && final_int) + || (inter_float && final_float)) + && inter_prec >= final_prec) + (ocvt @0)) + + /* 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_PRECISION (TYPE_MODE (type)) + && TYPE_MODE (type) == TYPE_MODE (inter_type)) + && ! final_ptr + && (! final_vec || inter_prec == inside_prec)) + (ocvt @0)) + + /* If we have a sign-extension of a zero-extended value, we can + replace that by a single zero-extension. Likewise if the + final conversion does not change precision we can drop the + intermediate conversion. */ + (if (inside_int && inter_int && final_int + && ((inside_prec < inter_prec && inter_prec < final_prec + && inside_unsignedp && !inter_unsignedp) + || final_prec == inter_prec)) + (ocvt @0)) + + /* 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_PRECISION (TYPE_MODE (type)) + && TYPE_MODE (type) == TYPE_MODE (inter_type))) + (ocvt @0)))))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1a3d6f6f33e..f4eb87671ce 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-11-09 Richard Biener + + * g++.dg/cpp0x/constexpr-reinterpret1.C: XFAIL. + * gcc.dg/tree-ssa/pr21031.c: XFAIL. + 2014-11-07 Andrew Pinski * gcc.c-torture/execute/20141107-1.c: New testcase. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C index 69db98bc772..26c92937f47 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C @@ -18,7 +18,7 @@ public: { /* I am surprised this is considered a constexpr */ return *((Inner *)4); - } // { dg-error "reinterpret_cast" } + } // { dg-error "reinterpret_cast" "" { xfail *-*-* } } }; B B::instance; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr21031.c b/gcc/testsuite/gcc.dg/tree-ssa/pr21031.c index df200d564d3..251b84e82ef 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr21031.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr21031.c @@ -16,5 +16,5 @@ foo (int a) return 0; } -/* { dg-final { scan-tree-dump-times "Replaced" 2 "forwprop1"} } */ +/* { dg-final { scan-tree-dump-times "Replaced" 2 "forwprop1" { xfail *-*-* } } } */ /* { dg-final { cleanup-tree-dump "forwprop1" } } */ diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 58f38981e93..2f4998cdb56 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -2386,109 +2386,20 @@ combine_conversions (gimple_stmt_iterator *gsi) 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); /* Don't propagate ssa names that occur in abnormal phis. */ if (TREE_CODE (defop0) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (defop0)) return 0; - /* 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 remove_prop_source_from_use (op0) ? 2 : 1; - } - - /* 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_PRECISION (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 remove_prop_source_from_use (op0) ? 2 : 1; - } - - /* If we have a sign-extension of a zero-extended value, we can - replace that by a single zero-extension. Likewise if the - final conversion does not change precision we can drop the - intermediate conversion. */ - if (inside_int && inter_int && final_int - && ((inside_prec < inter_prec && inter_prec < final_prec - && inside_unsignedp && !inter_unsignedp) - || final_prec == inter_prec)) - { - gimple_assign_set_rhs1 (stmt, defop0); - update_stmt (stmt); - return remove_prop_source_from_use (op0) ? 2 : 1; - } - - /* 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_PRECISION (TYPE_MODE (type)) - && TYPE_MODE (type) == TYPE_MODE (inter_type))) - { - gimple_assign_set_rhs1 (stmt, defop0); - update_stmt (stmt); - return remove_prop_source_from_use (op0) ? 2 : 1; - } - /* A truncation to an unsigned type should be canonicalized as bitwise and of a mask. */ if (final_int && inter_int && inside_int -- 2.30.2