diff mbox series

Builtin fadd variants folding implementation

Message ID CACMrGjAEVb+3OKAPFB-_X=U+Up37MfSu_VXS2cVAwipbNL1mJA@mail.gmail.com
State New
Headers show
Series Builtin fadd variants folding implementation | expand

Commit Message

Tejas Joshi Sept. 11, 2019, 1:17 p.m. UTC
Hi.
This patch includes implementation of fadd, faddl, daddl functions.
The patch boostraps on x86_64-linux-gnu and passes regression tests.

Thanks,
Tejas

gcc/ChangeLog:

2019-09-11  Tejas Joshi  <tejasjoshi9673@gmail.com>

    * builtin-types.def: Define narrowing function types.
    * builtins.def: Define fadd variants builtin functions.
    * fold-const-call.c (fold_const_narrow_binary): New. Folding calls
    and conditions for standard arithmetic functions.
    (fold_const_call): Add case for fadd variants.

gcc/testsuite/ChangeLog:

2019-09-11  Tejas Joshi  <tejasjoshi9673@gmail.com>

    * gcc.dg/builtin-fadd-1.c: New test.
    * gcc.dg/builtin-fadd-2.c: New test.
    * gcc.dg/builtin-fadd-3.c: New test.
    * gcc.dg/builtin-fadd-4.c: New test.
    * gcc.dg/builtin-fadd-5.c: New test.
    * gcc.dg/builtin-fadd-6.c: New test.

Comments

Martin Jambor Oct. 2, 2019, 4:10 p.m. UTC | #1
Hi Joseph,

could you please have a look at this latest version of the patch
introducing fadd et al.?  There already is a pre-approved folllow-up
somewhere expanding it on power but we need to get this in first.

Thanks,

Martin


On Wed, Sep 11 2019, Tejas Joshi wrote:
> Hi.
> This patch includes implementation of fadd, faddl, daddl functions.
> The patch boostraps on x86_64-linux-gnu and passes regression tests.
>
> Thanks,
> Tejas
>
> gcc/ChangeLog:
>
> 2019-09-11  Tejas Joshi  <tejasjoshi9673@gmail.com>
>
>     * builtin-types.def: Define narrowing function types.
>     * builtins.def: Define fadd variants builtin functions.
>     * fold-const-call.c (fold_const_narrow_binary): New. Folding calls
>     and conditions for standard arithmetic functions.
>     (fold_const_call): Add case for fadd variants.
>
> gcc/testsuite/ChangeLog:
>
> 2019-09-11  Tejas Joshi  <tejasjoshi9673@gmail.com>
>
>     * gcc.dg/builtin-fadd-1.c: New test.
>     * gcc.dg/builtin-fadd-2.c: New test.
>     * gcc.dg/builtin-fadd-3.c: New test.
>     * gcc.dg/builtin-fadd-4.c: New test.
>     * gcc.dg/builtin-fadd-5.c: New test.
>     * gcc.dg/builtin-fadd-6.c: New test.
> diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
> index e5c9e063c48..6bc552fa71a 100644
> --- a/gcc/builtin-types.def
> +++ b/gcc/builtin-types.def
> @@ -387,8 +387,14 @@ DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_PTR,
>  		     BT_VOID, BT_UINT, BT_PTR)
>  DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT_FLOAT_FLOAT,
>  		     BT_FLOAT, BT_FLOAT, BT_FLOAT)
> +DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT_DOUBLE_DOUBLE,
> +		     BT_FLOAT, BT_DOUBLE, BT_DOUBLE)
> +DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT_LONGDOUBLE_LONGDOUBLE,
> +		     BT_FLOAT, BT_LONGDOUBLE, BT_LONGDOUBLE)
>  DEF_FUNCTION_TYPE_2 (BT_FN_DOUBLE_DOUBLE_DOUBLE,
>  		     BT_DOUBLE, BT_DOUBLE, BT_DOUBLE)
> +DEF_FUNCTION_TYPE_2 (BT_FN_DOUBLE_LONGDOUBLE_LONGDOUBLE,
> +		     BT_DOUBLE, BT_LONGDOUBLE, BT_LONGDOUBLE)
>  DEF_FUNCTION_TYPE_2 (BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE,
>  		     BT_LONGDOUBLE, BT_LONGDOUBLE, BT_LONGDOUBLE)
>  DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT16_FLOAT16_FLOAT16,
> diff --git a/gcc/builtins.def b/gcc/builtins.def
> index 8bb7027aac7..2df616c477e 100644
> --- a/gcc/builtins.def
> +++ b/gcc/builtins.def
> @@ -355,6 +355,9 @@ DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_FABS, "fabs", FABS_TYPE, ATTR_CONST_NOT
>  DEF_GCC_BUILTIN        (BUILT_IN_FABSD32, "fabsd32", BT_FN_DFLOAT32_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_FABSD64, "fabsd64", BT_FN_DFLOAT64_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_FADD, "fadd", BT_FN_FLOAT_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_FADDL, "faddl", BT_FN_FLOAT_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_DADDL, "daddl", BT_FN_DOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_C99_BUILTIN        (BUILT_IN_FDIM, "fdim", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
>  DEF_C99_BUILTIN        (BUILT_IN_FDIMF, "fdimf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
>  DEF_C99_BUILTIN        (BUILT_IN_FDIML, "fdiml", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
> diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
> index 3a14d2a41c1..f6b4508a101 100644
> --- a/gcc/fold-const-call.c
> +++ b/gcc/fold-const-call.c
> @@ -570,6 +570,44 @@ fold_const_nextafter (real_value *result, const real_value *arg0,
>    return true;
>  }
>  
> +/* Try to evaluate:
> +
> +      *RESULT = add (*ARG0, *ARG1)
> +
> +   in format FORMAT.  Return true on success.  */
> +
> +static bool
> +fold_const_narrow_binary (real_value *result, const real_value *arg0,
> +			  int icode, const real_value *arg1,
> +			  const real_format *format)
> +{
> +  if (REAL_VALUE_ISSIGNALING_NAN (*arg0)
> +      || REAL_VALUE_ISSIGNALING_NAN (*arg1))
> +    return false;
> +
> +  real_arithmetic (result, icode, arg0, arg1);
> +  /* Underflow condition.  */
> +  if (flag_errno_math
> +      && result->cl == rvc_normal
> +      && REAL_EXP (result) < format->emin)
> +    return false;
> +
> +  if (!exact_real_truncate (format, result)
> +      && (flag_rounding_math || flag_trapping_math))
> +    return false;
> +
> +  real_convert (result, format, result);
> +  /* Overflow condition.  */
> +  if (!real_isfinite (result) && flag_errno_math)
> +    return false;
> +
> +  if (REAL_VALUE_ISNAN (*result)
> +      && (flag_errno_math || flag_trapping_math))
> +    return false;
> +
> +  return true;
> +}
> +
>  /* Try to evaluate:
>  
>        *RESULT = ldexp (*ARG0, ARG1)
> @@ -1674,6 +1712,25 @@ fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
>      case CFN_FOLD_LEFT_PLUS:
>        return fold_const_fold_left (type, arg0, arg1, PLUS_EXPR);
>  
> +    case CFN_BUILT_IN_FADD:
> +    case CFN_BUILT_IN_FADDL:
> +    case CFN_BUILT_IN_DADDL:
> +      {
> +	if (real_cst_p (arg0)
> +	    && real_cst_p (arg1))
> +	  {
> +	    machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0));
> +	    gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode));
> +	    REAL_VALUE_TYPE result;
> +	    machine_mode mode = TYPE_MODE (type);
> +	    if (fold_const_narrow_binary (&result, TREE_REAL_CST_PTR (arg0),
> +					  PLUS_EXPR, TREE_REAL_CST_PTR (arg1),
> +					  REAL_MODE_FORMAT (mode)))
> +	      return build_real (type, result);
> +	  }
> +      }
> +      return NULL_TREE;
> +
>      default:
>        return fold_const_call_1 (fn, type, arg0, arg1);
>      }
> diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-1.c b/gcc/testsuite/gcc.dg/builtin-fadd-1.c
> new file mode 100644
> index 00000000000..66280e9f72b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-fadd-1.c
> @@ -0,0 +1,54 @@
> +/* { dg-do link } */
> +/* { dg-options "-O2 -fno-trapping-math" } */
> +
> +extern int link_error (int);
> +
> +#define TEST(FN, VAL1, VAL2, RESULT) \
> +  if (__builtin_##FN (VAL1, VAL2) != RESULT) link_error (__LINE__);
> +
> +int
> +main (void)
> +{
> +  TEST(fadd, 0, 0, 0.0F);
> +  TEST(fadd, 1, -1, 0.0F);
> +  TEST(fadd, -1, -1.5, -2.5F);
> +  TEST(fadd, 1.4, 1.6, 3.0F);
> +  TEST(fadd, 2.5, 1.5, 4.0F);
> +  
> +  TEST(fadd, 1, 1.1, 2.1F);
> +  TEST(fadd, 2, 4.3, 6.3F);
> +  TEST(fadd, -3, -3.6, -6.6F); 
> +  TEST(fadd, 8, 0.8, 8.8F);
> +
> +  if (__builtin_fadd (0x1.000001p0, __FLT_MIN__)
> +      == (float) (0x1.000001p0 + __FLT_MIN__))
> +    link_error (__LINE__);
> +
> +  TEST(faddl, 0.0L, 0.0L, 0.0F);
> +  TEST(faddl, 1.0L, -1.0L, 0.0F);
> +  TEST(faddl, -1.0L, -1.5L, -2.5F);
> +  TEST(faddl, 1.4L, 1.6L, 3.0F);
> +  TEST(faddl, 2.5L, 1.5L, 4.0F);
> +
> +  TEST(faddl, 1.0L, 1.1L, 2.1F);
> +  TEST(faddl, 2.0L, 4.3L, 6.3F);
> +  TEST(faddl, -3.0L, -3.6L, -6.6F); 
> +  TEST(faddl, 8.0L, 0.8L, 8.8F);
> +
> +  if (__builtin_faddl (0x1.000001p0, __FLT_MIN__)
> +      == (float) (0x1.000001p0 + __FLT_MIN__))
> +    link_error (__LINE__);
> +
> +  TEST(daddl, 0L, 0L, 0.0);
> +  TEST(daddl, 1.0L, -1.0L, 0.0);
> +  TEST(daddl, -1.0L, -1.5L, -2.5);
> +  TEST(daddl, 1.4L, 1.6L, 3.0);
> +  TEST(daddl, 2.5L, 1.5L, 4.0);
> +  
> +  TEST(daddl, 1.0L, 1.1L, 2.1);
> +  TEST(daddl, 2.0L, 4.3L, 6.3);
> +  TEST(daddl, -3.0L, -3.6L, -6.6); 
> +  TEST(daddl, 8.0L, 0.8L, 8.8);
> +  
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-2.c b/gcc/testsuite/gcc.dg/builtin-fadd-2.c
> new file mode 100644
> index 00000000000..006f1c6d21b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-fadd-2.c
> @@ -0,0 +1,29 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
> +/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
> +/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
> +
> +#define TEST(FN, VAL1, VAL2, RESULT) \
> +  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
> +
> +int
> +main (void)
> +{
> +  TEST(fadd, 1, 1.1, 2.1F);
> +  TEST(fadd, 2, 4.3, 6.3F);
> +  TEST(fadd, -3, -3.6, -6.6F); 
> +  TEST(fadd, 8, 0.8, 8.8F);
> +
> +  TEST(faddl, 1.0L, 1.1L, 2.1F);
> +  TEST(faddl, 2.0L, 4.3L, 6.3F);
> +  TEST(faddl, -3.0L, -3.6L, -6.6F); 
> +  TEST(faddl, 8.0L, 0.8L, 8.8F);
> +
> +  TEST(daddl, 1.0L, 1.1L, 2.1);
> +  TEST(daddl, 2.0L, 4.3L, 6.3);
> +  TEST(daddl, -3.0L, -3.6L, -6.6); 
> +  TEST(daddl, 8.0L, 0.8L, 8.8);
> +
> +  return 0;
> +} 
> diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-3.c b/gcc/testsuite/gcc.dg/builtin-fadd-3.c
> new file mode 100644
> index 00000000000..dd8a2040cb7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-fadd-3.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-trapping-math -frounding-math -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
> +/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
> +/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
> +
> +#define TEST(FN, VAL1, VAL2, RESULT) \
> +  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
> +
> +#include "builtin-fadd-2.c"
> diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-4.c b/gcc/testsuite/gcc.dg/builtin-fadd-4.c
> new file mode 100644
> index 00000000000..9091be49b9b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-fadd-4.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -frounding-math -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
> +/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
> +/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
> +
> +#define TEST(FN, VAL1, VAL2, RESULT) \
> +  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
> +
> +#include "builtin-fadd-2.c"
> diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-5.c b/gcc/testsuite/gcc.dg/builtin-fadd-5.c
> new file mode 100644
> index 00000000000..ac3b547724c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-fadd-5.c
> @@ -0,0 +1,26 @@
> +/* { dg-do link } */
> +/* { dg-options "-O2 -fno-trapping-math -fno-math-errno" } */
> +
> +extern int link_error (int);
> +
> +#define TEST(FN, VAL1, VAL2, RESULT) \
> +  if (__builtin_##FN (VAL1, VAL2) != RESULT) link_error (__LINE__);
> +
> +int
> +main (void)
> +{
> +  TEST(fadd, __DBL_MAX__, __DBL_MAX__, __builtin_inff());
> +  TEST(fadd, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
> +  TEST(fadd, __DBL_MIN__, __DBL_MIN__, 0.0);
> +
> +  TEST(faddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inff());
> +  TEST(faddl, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
> +  TEST(faddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
> +
> +  TEST(daddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inf());
> +  TEST(daddl, __DBL_MAX__, __DBL_MAX__, __builtin_inf());
> +  TEST(daddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
> +
> +  return 0;
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-6.c b/gcc/testsuite/gcc.dg/builtin-fadd-6.c
> new file mode 100644
> index 00000000000..11c63f06463
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-fadd-6.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-trapping-math -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
> +/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
> +/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
> +
> +#define TEST(FN, VAL1, VAL2, RESULT) \
> +  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
> +
> +int
> +main (void)
> +{
> +  TEST(fadd, __DBL_MAX__, __DBL_MAX__, __builtin_inff());
> +  TEST(fadd, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
> +  TEST(fadd, __DBL_MIN__, __DBL_MIN__, 0.0);
> +
> +  TEST(faddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inff());
> +  TEST(faddl, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
> +  TEST(faddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
> +
> +  TEST(daddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inf());
> +  TEST(daddl, __DBL_MAX__, __DBL_MAX__, __builtin_inf());
> +  TEST(daddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
> +
> +  return 0;
> +}
> +
Joseph Myers Oct. 2, 2019, 9:38 p.m. UTC | #2
On Wed, 11 Sep 2019, Tejas Joshi wrote:

> diff --git a/gcc/builtins.def b/gcc/builtins.def
> index 8bb7027aac7..2df616c477e 100644
> --- a/gcc/builtins.def
> +++ b/gcc/builtins.def
> @@ -355,6 +355,9 @@ DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_FABS, "fabs", FABS_TYPE, ATTR_CONST_NOT
>  DEF_GCC_BUILTIN        (BUILT_IN_FABSD32, "fabsd32", BT_FN_DFLOAT32_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_FABSD64, "fabsd64", BT_FN_DFLOAT64_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST)
>  DEF_GCC_BUILTIN        (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_FADD, "fadd", BT_FN_FLOAT_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_FADDL, "faddl", BT_FN_FLOAT_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
> +DEF_EXT_LIB_BUILTIN    (BUILT_IN_DADDL, "daddl", BT_FN_DOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)

I think these should all use ATTR_MATHFN_FPROUNDING_ERRNO instead of 
ATTR_CONST_NOTHROW_LEAF_LIST.  That way the attributes depend properly on 
the command-line options.

>  DEF_C99_BUILTIN        (BUILT_IN_FDIM, "fdim", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
>  DEF_C99_BUILTIN        (BUILT_IN_FDIMF, "fdimf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
>  DEF_C99_BUILTIN        (BUILT_IN_FDIML, "fdiml", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
> diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
> index 3a14d2a41c1..f6b4508a101 100644
> --- a/gcc/fold-const-call.c
> +++ b/gcc/fold-const-call.c
> @@ -570,6 +570,44 @@ fold_const_nextafter (real_value *result, const real_value *arg0,
>    return true;
>  }
>  
> +/* Try to evaluate:
> +
> +      *RESULT = add (*ARG0, *ARG1)
> +
> +   in format FORMAT.  Return true on success.  */

It's not specifically "add".  It's an operation determined by ICODE.

> +
> +static bool
> +fold_const_narrow_binary (real_value *result, const real_value *arg0,
> +			  int icode, const real_value *arg1,
> +			  const real_format *format)
> +{
> +  if (REAL_VALUE_ISSIGNALING_NAN (*arg0)
> +      || REAL_VALUE_ISSIGNALING_NAN (*arg1))
> +    return false;
> +
> +  real_arithmetic (result, icode, arg0, arg1);
> +  /* Underflow condition.  */
> +  if (flag_errno_math
> +      && result->cl == rvc_normal
> +      && REAL_EXP (result) < format->emin)
> +    return false;
> +
> +  if (!exact_real_truncate (format, result)
> +      && (flag_rounding_math || flag_trapping_math))
> +    return false;
> +
> +  real_convert (result, format, result);
> +  /* Overflow condition.  */
> +  if (!real_isfinite (result) && flag_errno_math)
> +    return false;

For overflow, this should be checking for real_isinf, not for 
!real_isfinite.  And specifically for real_isinf with both arguments 
finite, it's not an overflow to have an infinite result from an infinite 
argument.  (Strictly, infinite result with finite arguments could be 
either overflow or divide-by-zero, depending on whether it's an exact or 
inexact infinite result, but both those cases should be handled the same 
here.)

> +  if (REAL_VALUE_ISNAN (*result)
> +      && (flag_errno_math || flag_trapping_math))
> +    return false;

This last condition should only apply if neither argument is NaN; it's 
fine to fold to a NaN result when one or both arguments is a quiet NaN 
(and signaling NaNs were handled above).

There is one other case that also needs excluding in this function.  If 
both arguments are zero, and the operation is either adding two zeroes of 
different sign, or subtracting two zeroes of the same sign, it's not valid 
to fold if flag_rounding_math, because the sign of the result of 0 - 0 
depends on the rounding mode.

> diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-5.c b/gcc/testsuite/gcc.dg/builtin-fadd-5.c
> new file mode 100644
> index 00000000000..ac3b547724c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-fadd-5.c
> @@ -0,0 +1,26 @@
> +/* { dg-do link } */
> +/* { dg-options "-O2 -fno-trapping-math -fno-math-errno" } */
> +
> +extern int link_error (int);
> +
> +#define TEST(FN, VAL1, VAL2, RESULT) \
> +  if (__builtin_##FN (VAL1, VAL2) != RESULT) link_error (__LINE__);
> +
> +int
> +main (void)
> +{
> +  TEST(fadd, __DBL_MAX__, __DBL_MAX__, __builtin_inff());
> +  TEST(fadd, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
> +  TEST(fadd, __DBL_MIN__, __DBL_MIN__, 0.0);
> +
> +  TEST(faddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inff());
> +  TEST(faddl, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
> +  TEST(faddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
> +
> +  TEST(daddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inf());
> +  TEST(daddl, __DBL_MAX__, __DBL_MAX__, __builtin_inf());
> +  TEST(daddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);

In the case where long double = double, this last test isn't correct, as 
LDBL_MIN + LDBL_MIN == DBL_MIN + DBL_MIN and isn't zero.

The same also applies to the last test in builtin-fadd-6.c.
diff mbox series

Patch

diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index e5c9e063c48..6bc552fa71a 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -387,8 +387,14 @@  DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_PTR,
 		     BT_VOID, BT_UINT, BT_PTR)
 DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT_FLOAT_FLOAT,
 		     BT_FLOAT, BT_FLOAT, BT_FLOAT)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT_DOUBLE_DOUBLE,
+		     BT_FLOAT, BT_DOUBLE, BT_DOUBLE)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT_LONGDOUBLE_LONGDOUBLE,
+		     BT_FLOAT, BT_LONGDOUBLE, BT_LONGDOUBLE)
 DEF_FUNCTION_TYPE_2 (BT_FN_DOUBLE_DOUBLE_DOUBLE,
 		     BT_DOUBLE, BT_DOUBLE, BT_DOUBLE)
+DEF_FUNCTION_TYPE_2 (BT_FN_DOUBLE_LONGDOUBLE_LONGDOUBLE,
+		     BT_DOUBLE, BT_LONGDOUBLE, BT_LONGDOUBLE)
 DEF_FUNCTION_TYPE_2 (BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE,
 		     BT_LONGDOUBLE, BT_LONGDOUBLE, BT_LONGDOUBLE)
 DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT16_FLOAT16_FLOAT16,
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 8bb7027aac7..2df616c477e 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -355,6 +355,9 @@  DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_FABS, "fabs", FABS_TYPE, ATTR_CONST_NOT
 DEF_GCC_BUILTIN        (BUILT_IN_FABSD32, "fabsd32", BT_FN_DFLOAT32_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_FABSD64, "fabsd64", BT_FN_DFLOAT64_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_FADD, "fadd", BT_FN_FLOAT_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_FADDL, "faddl", BT_FN_FLOAT_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_DADDL, "daddl", BT_FN_DOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_FDIM, "fdim", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_FDIMF, "fdimf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_FDIML, "fdiml", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index 3a14d2a41c1..f6b4508a101 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -570,6 +570,44 @@  fold_const_nextafter (real_value *result, const real_value *arg0,
   return true;
 }
 
+/* Try to evaluate:
+
+      *RESULT = add (*ARG0, *ARG1)
+
+   in format FORMAT.  Return true on success.  */
+
+static bool
+fold_const_narrow_binary (real_value *result, const real_value *arg0,
+			  int icode, const real_value *arg1,
+			  const real_format *format)
+{
+  if (REAL_VALUE_ISSIGNALING_NAN (*arg0)
+      || REAL_VALUE_ISSIGNALING_NAN (*arg1))
+    return false;
+
+  real_arithmetic (result, icode, arg0, arg1);
+  /* Underflow condition.  */
+  if (flag_errno_math
+      && result->cl == rvc_normal
+      && REAL_EXP (result) < format->emin)
+    return false;
+
+  if (!exact_real_truncate (format, result)
+      && (flag_rounding_math || flag_trapping_math))
+    return false;
+
+  real_convert (result, format, result);
+  /* Overflow condition.  */
+  if (!real_isfinite (result) && flag_errno_math)
+    return false;
+
+  if (REAL_VALUE_ISNAN (*result)
+      && (flag_errno_math || flag_trapping_math))
+    return false;
+
+  return true;
+}
+
 /* Try to evaluate:
 
       *RESULT = ldexp (*ARG0, ARG1)
@@ -1674,6 +1712,25 @@  fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
     case CFN_FOLD_LEFT_PLUS:
       return fold_const_fold_left (type, arg0, arg1, PLUS_EXPR);
 
+    case CFN_BUILT_IN_FADD:
+    case CFN_BUILT_IN_FADDL:
+    case CFN_BUILT_IN_DADDL:
+      {
+	if (real_cst_p (arg0)
+	    && real_cst_p (arg1))
+	  {
+	    machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0));
+	    gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode));
+	    REAL_VALUE_TYPE result;
+	    machine_mode mode = TYPE_MODE (type);
+	    if (fold_const_narrow_binary (&result, TREE_REAL_CST_PTR (arg0),
+					  PLUS_EXPR, TREE_REAL_CST_PTR (arg1),
+					  REAL_MODE_FORMAT (mode)))
+	      return build_real (type, result);
+	  }
+      }
+      return NULL_TREE;
+
     default:
       return fold_const_call_1 (fn, type, arg0, arg1);
     }
diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-1.c b/gcc/testsuite/gcc.dg/builtin-fadd-1.c
new file mode 100644
index 00000000000..66280e9f72b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-1.c
@@ -0,0 +1,54 @@ 
+/* { dg-do link } */
+/* { dg-options "-O2 -fno-trapping-math" } */
+
+extern int link_error (int);
+
+#define TEST(FN, VAL1, VAL2, RESULT) \
+  if (__builtin_##FN (VAL1, VAL2) != RESULT) link_error (__LINE__);
+
+int
+main (void)
+{
+  TEST(fadd, 0, 0, 0.0F);
+  TEST(fadd, 1, -1, 0.0F);
+  TEST(fadd, -1, -1.5, -2.5F);
+  TEST(fadd, 1.4, 1.6, 3.0F);
+  TEST(fadd, 2.5, 1.5, 4.0F);
+  
+  TEST(fadd, 1, 1.1, 2.1F);
+  TEST(fadd, 2, 4.3, 6.3F);
+  TEST(fadd, -3, -3.6, -6.6F); 
+  TEST(fadd, 8, 0.8, 8.8F);
+
+  if (__builtin_fadd (0x1.000001p0, __FLT_MIN__)
+      == (float) (0x1.000001p0 + __FLT_MIN__))
+    link_error (__LINE__);
+
+  TEST(faddl, 0.0L, 0.0L, 0.0F);
+  TEST(faddl, 1.0L, -1.0L, 0.0F);
+  TEST(faddl, -1.0L, -1.5L, -2.5F);
+  TEST(faddl, 1.4L, 1.6L, 3.0F);
+  TEST(faddl, 2.5L, 1.5L, 4.0F);
+
+  TEST(faddl, 1.0L, 1.1L, 2.1F);
+  TEST(faddl, 2.0L, 4.3L, 6.3F);
+  TEST(faddl, -3.0L, -3.6L, -6.6F); 
+  TEST(faddl, 8.0L, 0.8L, 8.8F);
+
+  if (__builtin_faddl (0x1.000001p0, __FLT_MIN__)
+      == (float) (0x1.000001p0 + __FLT_MIN__))
+    link_error (__LINE__);
+
+  TEST(daddl, 0L, 0L, 0.0);
+  TEST(daddl, 1.0L, -1.0L, 0.0);
+  TEST(daddl, -1.0L, -1.5L, -2.5);
+  TEST(daddl, 1.4L, 1.6L, 3.0);
+  TEST(daddl, 2.5L, 1.5L, 4.0);
+  
+  TEST(daddl, 1.0L, 1.1L, 2.1);
+  TEST(daddl, 2.0L, 4.3L, 6.3);
+  TEST(daddl, -3.0L, -3.6L, -6.6); 
+  TEST(daddl, 8.0L, 0.8L, 8.8);
+  
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-2.c b/gcc/testsuite/gcc.dg/builtin-fadd-2.c
new file mode 100644
index 00000000000..006f1c6d21b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-2.c
@@ -0,0 +1,29 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
+/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
+/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
+
+#define TEST(FN, VAL1, VAL2, RESULT) \
+  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
+
+int
+main (void)
+{
+  TEST(fadd, 1, 1.1, 2.1F);
+  TEST(fadd, 2, 4.3, 6.3F);
+  TEST(fadd, -3, -3.6, -6.6F); 
+  TEST(fadd, 8, 0.8, 8.8F);
+
+  TEST(faddl, 1.0L, 1.1L, 2.1F);
+  TEST(faddl, 2.0L, 4.3L, 6.3F);
+  TEST(faddl, -3.0L, -3.6L, -6.6F); 
+  TEST(faddl, 8.0L, 0.8L, 8.8F);
+
+  TEST(daddl, 1.0L, 1.1L, 2.1);
+  TEST(daddl, 2.0L, 4.3L, 6.3);
+  TEST(daddl, -3.0L, -3.6L, -6.6); 
+  TEST(daddl, 8.0L, 0.8L, 8.8);
+
+  return 0;
+} 
diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-3.c b/gcc/testsuite/gcc.dg/builtin-fadd-3.c
new file mode 100644
index 00000000000..dd8a2040cb7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-3.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-trapping-math -frounding-math -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
+/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
+/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
+
+#define TEST(FN, VAL1, VAL2, RESULT) \
+  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
+
+#include "builtin-fadd-2.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-4.c b/gcc/testsuite/gcc.dg/builtin-fadd-4.c
new file mode 100644
index 00000000000..9091be49b9b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-4.c
@@ -0,0 +1,10 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -frounding-math -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
+/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
+/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
+
+#define TEST(FN, VAL1, VAL2, RESULT) \
+  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
+
+#include "builtin-fadd-2.c"
diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-5.c b/gcc/testsuite/gcc.dg/builtin-fadd-5.c
new file mode 100644
index 00000000000..ac3b547724c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-5.c
@@ -0,0 +1,26 @@ 
+/* { dg-do link } */
+/* { dg-options "-O2 -fno-trapping-math -fno-math-errno" } */
+
+extern int link_error (int);
+
+#define TEST(FN, VAL1, VAL2, RESULT) \
+  if (__builtin_##FN (VAL1, VAL2) != RESULT) link_error (__LINE__);
+
+int
+main (void)
+{
+  TEST(fadd, __DBL_MAX__, __DBL_MAX__, __builtin_inff());
+  TEST(fadd, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
+  TEST(fadd, __DBL_MIN__, __DBL_MIN__, 0.0);
+
+  TEST(faddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inff());
+  TEST(faddl, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
+  TEST(faddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
+
+  TEST(daddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inf());
+  TEST(daddl, __DBL_MAX__, __DBL_MAX__, __builtin_inf());
+  TEST(daddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/builtin-fadd-6.c b/gcc/testsuite/gcc.dg/builtin-fadd-6.c
new file mode 100644
index 00000000000..11c63f06463
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-6.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-trapping-math -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump "fadd" "optimized" } } */
+/* { dg-final { scan-tree-dump "faddl" "optimized" } } */
+/* { dg-final { scan-tree-dump "daddl" "optimized" } } */
+
+#define TEST(FN, VAL1, VAL2, RESULT) \
+  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
+
+int
+main (void)
+{
+  TEST(fadd, __DBL_MAX__, __DBL_MAX__, __builtin_inff());
+  TEST(fadd, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
+  TEST(fadd, __DBL_MIN__, __DBL_MIN__, 0.0);
+
+  TEST(faddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inff());
+  TEST(faddl, __FLT_MAX__, __FLT_MAX__, __builtin_inff());
+  TEST(faddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
+
+  TEST(daddl, __LDBL_MAX__, __LDBL_MAX__, __builtin_inf());
+  TEST(daddl, __DBL_MAX__, __DBL_MAX__, __builtin_inf());
+  TEST(daddl, __LDBL_MIN__, __LDBL_MIN__, 0.0);
+
+  return 0;
+}
+