diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-09 11:27:00 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-09 11:27:00 +0000 |
commit | c434260f696108b748a69fbc9bae8a0826492d6f (patch) | |
tree | 7253af53d7de307a8f840ca8e90e5e0acc5fa293 /gcc/match.pd | |
parent | ec9bdbf76d1c412a3b8e3afb8ff9347665ff53f1 (diff) | |
download | gcc-c434260f696108b748a69fbc9bae8a0826492d6f.tar.gz |
2014-11-09 Richard Biener <rguenther@suse.de>
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217260 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/match.pd')
-rw-r--r-- | gcc/match.pd | 93 |
1 files changed, 93 insertions, 0 deletions
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)))))) |