Add rules to strip away unneeded type casts in expressions
authorTamar Christina <tamar.christina@arm.com>
Fri, 26 Jul 2019 13:05:39 +0000 (13:05 +0000)
committerTamar Christina <tnfchris@gcc.gnu.org>
Fri, 26 Jul 2019 13:05:39 +0000 (13:05 +0000)
This patch moves part of the type conversion code from convert.c to match.pd
because match.pd is able to apply these transformations in the presence of
intermediate temporary variables.

Concretely it makes both these cases behave the same

  float e = (float)a * (float)b;
  *c = (_Float16)e;

and

  *c = (_Float16)((float)a * (float)b);

gcc/ChangeLog:

* convert.c (convert_to_real_1): Move part of conversion code...
* match.pd: ...To here.

gcc/testsuite/ChangeLog:

* gcc.dg/type-convert-var.c: New test.

From-SVN: r273826

gcc/ChangeLog
gcc/convert.c
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/type-convert-var.c [new file with mode: 0644]

index e5ef2ebf407624d5795d6fc696bd150da1df4e48..301030fef3d853f30e61377d3a0b881c7b711dd8 100644 (file)
@@ -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
index a8f2bd049ba0cd83865ba0a5f7d74f9cdbad0d09..7f0d933f4d9e29719acb27eb1b32a9e540d93073 100644 (file)
@@ -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;
       }
index c5c6a041cfce8a0b24e0cfc63a28a8f9792f31c2..0317bc704f771f626ab72189b3a54de00087ad5a 100644 (file)
@@ -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
index ca3596deda04f2d2e4ea860218613c1b0c6efb3a..f899b5bb0aa8f039a7f0541a7d5f8bc6cc5137f1 100644 (file)
@@ -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 (file)
index 0000000..88d74e2
--- /dev/null
@@ -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" } } */