aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/convert.c86
-rw-r--r--gcc/match.pd134
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/type-convert-var.c9
5 files changed, 121 insertions, 117 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e5ef2eb..301030f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2019-07-26 Tamar Christina <tamar.christina@arm.com>
+
+ * convert.c (convert_to_real_1): Move part of conversion code...
+ * match.pd: ...To here.
+
2019-07-26 Martin Jambor <mjambor@suse.cz>
PR ipa/89330
diff --git a/gcc/convert.c b/gcc/convert.c
index a8f2bd0..7f0d933 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -298,92 +298,6 @@ convert_to_real_1 (tree type, tree expr, bool fold_p)
return build1 (TREE_CODE (expr), type, arg);
}
break;
- /* Convert (outertype)((innertype0)a+(innertype1)b)
- into ((newtype)a+(newtype)b) where newtype
- is the widest mode from all of these. */
- case PLUS_EXPR:
- case MINUS_EXPR:
- case MULT_EXPR:
- case RDIV_EXPR:
- {
- tree arg0 = strip_float_extensions (TREE_OPERAND (expr, 0));
- tree arg1 = strip_float_extensions (TREE_OPERAND (expr, 1));
-
- if (FLOAT_TYPE_P (TREE_TYPE (arg0))
- && FLOAT_TYPE_P (TREE_TYPE (arg1))
- && DECIMAL_FLOAT_TYPE_P (itype) == DECIMAL_FLOAT_TYPE_P (type))
- {
- tree newtype = type;
-
- if (TYPE_MODE (TREE_TYPE (arg0)) == SDmode
- || TYPE_MODE (TREE_TYPE (arg1)) == SDmode
- || TYPE_MODE (type) == SDmode)
- newtype = dfloat32_type_node;
- if (TYPE_MODE (TREE_TYPE (arg0)) == DDmode
- || TYPE_MODE (TREE_TYPE (arg1)) == DDmode
- || TYPE_MODE (type) == DDmode)
- newtype = dfloat64_type_node;
- if (TYPE_MODE (TREE_TYPE (arg0)) == TDmode
- || TYPE_MODE (TREE_TYPE (arg1)) == TDmode
- || TYPE_MODE (type) == TDmode)
- newtype = dfloat128_type_node;
- if (newtype == dfloat32_type_node
- || newtype == dfloat64_type_node
- || newtype == dfloat128_type_node)
- {
- expr = build2 (TREE_CODE (expr), newtype,
- convert_to_real_1 (newtype, arg0,
- fold_p),
- convert_to_real_1 (newtype, arg1,
- fold_p));
- if (newtype == type)
- return expr;
- break;
- }
-
- if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (newtype))
- newtype = TREE_TYPE (arg0);
- if (TYPE_PRECISION (TREE_TYPE (arg1)) > TYPE_PRECISION (newtype))
- newtype = TREE_TYPE (arg1);
- /* Sometimes this transformation is safe (cannot
- change results through affecting double rounding
- cases) and sometimes it is not. If NEWTYPE is
- wider than TYPE, e.g. (float)((long double)double
- + (long double)double) converted to
- (float)(double + double), the transformation is
- unsafe regardless of the details of the types
- involved; double rounding can arise if the result
- of NEWTYPE arithmetic is a NEWTYPE value half way
- between two representable TYPE values but the
- exact value is sufficiently different (in the
- right direction) for this difference to be
- visible in ITYPE arithmetic. If NEWTYPE is the
- same as TYPE, however, the transformation may be
- safe depending on the types involved: it is safe
- if the ITYPE has strictly more than twice as many
- mantissa bits as TYPE, can represent infinities
- and NaNs if the TYPE can, and has sufficient
- exponent range for the product or ratio of two
- values representable in the TYPE to be within the
- range of normal values of ITYPE. */
- if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype)
- && (flag_unsafe_math_optimizations
- || (TYPE_PRECISION (newtype) == TYPE_PRECISION (type)
- && real_can_shorten_arithmetic (TYPE_MODE (itype),
- TYPE_MODE (type))
- && !excess_precision_type (newtype))))
- {
- expr = build2 (TREE_CODE (expr), newtype,
- convert_to_real_1 (newtype, arg0,
- fold_p),
- convert_to_real_1 (newtype, arg1,
- fold_p));
- if (newtype == type)
- return expr;
- }
- }
- }
- break;
default:
break;
}
diff --git a/gcc/match.pd b/gcc/match.pd
index c5c6a04..0317bc7 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4938,37 +4938,109 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
the C/C++ front-ends by shorten_binary_op and shorten_compare. Long
term we want to move all that code out of the front-ends into here. */
-/* If we have a narrowing conversion of an arithmetic operation where
- both operands are widening conversions from the same type as the outer
- narrowing conversion. Then convert the innermost operands to a suitable
- unsigned type (to avoid introducing undefined behavior), perform the
- operation and convert the result to the desired type. */
-(for op (plus minus)
- (simplify
- (convert (op:s (convert@2 @0) (convert?@3 @1)))
- (if (INTEGRAL_TYPE_P (type)
- /* We check for type compatibility between @0 and @1 below,
- so there's no need to check that @1/@3 are integral types. */
- && INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && INTEGRAL_TYPE_P (TREE_TYPE (@2))
- /* The precision of the type of each operand must match the
- precision of the mode of each operand, similarly for the
- result. */
- && type_has_mode_precision_p (TREE_TYPE (@0))
- && type_has_mode_precision_p (TREE_TYPE (@1))
- && type_has_mode_precision_p (type)
- /* The inner conversion must be a widening conversion. */
- && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
- && types_match (@0, type)
- && (types_match (@0, @1)
- /* Or the second operand is const integer or converted const
- integer from valueize. */
- || TREE_CODE (@1) == INTEGER_CST))
- (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
- (op @0 (convert @1))
- (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
- (convert (op (convert:utype @0)
- (convert:utype @1))))))))
+/* Convert (outertype)((innertype0)a+(innertype1)b)
+ into ((newtype)a+(newtype)b) where newtype
+ is the widest mode from all of these. */
+(for op (plus minus mult rdiv)
+ (simplify
+ (convert (op:s@0 (convert1?@3 @1) (convert2?@4 @2)))
+ /* If we have a narrowing conversion of an arithmetic operation where
+ both operands are widening conversions from the same type as the outer
+ narrowing conversion. Then convert the innermost operands to a
+ suitable unsigned type (to avoid introducing undefined behavior),
+ perform the operation and convert the result to the desired type. */
+ (if (INTEGRAL_TYPE_P (type)
+ && op != MULT_EXPR
+ && op != RDIV_EXPR
+ /* We check for type compatibility between @0 and @1 below,
+ so there's no need to check that @2/@4 are integral types. */
+ && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@3))
+ /* The precision of the type of each operand must match the
+ precision of the mode of each operand, similarly for the
+ result. */
+ && type_has_mode_precision_p (TREE_TYPE (@1))
+ && type_has_mode_precision_p (TREE_TYPE (@2))
+ && type_has_mode_precision_p (type)
+ /* The inner conversion must be a widening conversion. */
+ && TYPE_PRECISION (TREE_TYPE (@3)) > TYPE_PRECISION (TREE_TYPE (@1))
+ && types_match (@1, type)
+ && (types_match (@1, @2)
+ /* Or the second operand is const integer or converted const
+ integer from valueize. */
+ || TREE_CODE (@2) == INTEGER_CST))
+ (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
+ (op @1 (convert @2))
+ (with { tree utype = unsigned_type_for (TREE_TYPE (@1)); }
+ (convert (op (convert:utype @1)
+ (convert:utype @2)))))
+ (if (FLOAT_TYPE_P (type)
+ && DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0))
+ == DECIMAL_FLOAT_TYPE_P (type))
+ (with { tree arg0 = strip_float_extensions (@1);
+ tree arg1 = strip_float_extensions (@2);
+ tree itype = TREE_TYPE (@0);
+ tree ty1 = TREE_TYPE (arg0);
+ tree ty2 = TREE_TYPE (arg1);
+ enum tree_code code = TREE_CODE (itype); }
+ (if (FLOAT_TYPE_P (ty1)
+ && FLOAT_TYPE_P (ty2))
+ (with { tree newtype = type;
+ if (TYPE_MODE (ty1) == SDmode
+ || TYPE_MODE (ty2) == SDmode
+ || TYPE_MODE (type) == SDmode)
+ newtype = dfloat32_type_node;
+ if (TYPE_MODE (ty1) == DDmode
+ || TYPE_MODE (ty2) == DDmode
+ || TYPE_MODE (type) == DDmode)
+ newtype = dfloat64_type_node;
+ if (TYPE_MODE (ty1) == TDmode
+ || TYPE_MODE (ty2) == TDmode
+ || TYPE_MODE (type) == TDmode)
+ newtype = dfloat128_type_node; }
+ (if ((newtype == dfloat32_type_node
+ || newtype == dfloat64_type_node
+ || newtype == dfloat128_type_node)
+ && newtype == type
+ && types_match (newtype, type))
+ (op (convert:newtype @1) (convert:newtype @2))
+ (with { if (TYPE_PRECISION (ty1) > TYPE_PRECISION (newtype))
+ newtype = ty1;
+ if (TYPE_PRECISION (ty2) > TYPE_PRECISION (newtype))
+ newtype = ty2; }
+ /* Sometimes this transformation is safe (cannot
+ change results through affecting double rounding
+ cases) and sometimes it is not. If NEWTYPE is
+ wider than TYPE, e.g. (float)((long double)double
+ + (long double)double) converted to
+ (float)(double + double), the transformation is
+ unsafe regardless of the details of the types
+ involved; double rounding can arise if the result
+ of NEWTYPE arithmetic is a NEWTYPE value half way
+ between two representable TYPE values but the
+ exact value is sufficiently different (in the
+ right direction) for this difference to be
+ visible in ITYPE arithmetic. If NEWTYPE is the
+ same as TYPE, however, the transformation may be
+ safe depending on the types involved: it is safe
+ if the ITYPE has strictly more than twice as many
+ mantissa bits as TYPE, can represent infinities
+ and NaNs if the TYPE can, and has sufficient
+ exponent range for the product or ratio of two
+ values representable in the TYPE to be within the
+ range of normal values of ITYPE. */
+ (if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype)
+ && (flag_unsafe_math_optimizations
+ || (TYPE_PRECISION (newtype) == TYPE_PRECISION (type)
+ && real_can_shorten_arithmetic (TYPE_MODE (itype),
+ TYPE_MODE (type))
+ && !excess_precision_type (newtype)))
+ && !types_match (itype, newtype))
+ (convert:type (op (convert:newtype @1)
+ (convert:newtype @2)))
+ )))) )
+ ))
+)))
/* This is another case of narrowing, specifically when there's an outer
BIT_AND_EXPR which masks off bits outside the type of the innermost
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ca3596d..f899b5b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2018-07-24 Tamar Christina <tamar.christina@arm.com>
+
+ * gcc.dg/type-convert-var.c: New test.
+
2019-07-26 Martin Jambor <mjambor@suse.cz>
PR ipa/89330
diff --git a/gcc/testsuite/gcc.dg/type-convert-var.c b/gcc/testsuite/gcc.dg/type-convert-var.c
new file mode 100644
index 0000000..88d74e2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/type-convert-var.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O1 -fdump-tree-optimized" } */
+void foo (float a, float b, float *c)
+{
+ double e = (double)a * (double)b;
+ *c = (float)e;
+}
+
+/* { dg-final { scan-tree-dump-not {double} "optimized" } } */