Hello.
I have made changes in the patch according to the above corrections.
However, I didn't understand how these following testcases are
supposed to handle. Will you please elaborate some more?

> (E.g. fadd (0x1.000001p0, FLT_MIN), as an example from the glibc
> tests: cases where an intermediate rounding produces a result half way
> between two values of the narrower type, but the exact value is such that
> the result of fadd should end up with last bit odd whereas double rounding
> would result in last bit even in such half-way cases.)

> Then you should have some tests of what does *not* get optimized with
> given compiler options if possible.  (Such a test might e.g. define a
> static fadd function locally that checks it gets called as expected, or
> else check the exceptions / errno if you rely on a suitable libm being
> available.)

Given that the changes yet to be done on testcases and some more
changes if any on this patch reviewed, it won't take much time to get
it done with sub/mul/div functions. When FADD folding patches along
with expansion on powerpc (including QP float, etc) are finalized, I
will complete the others as soon as possible.

Thanks,
Tejas


On Wed, 21 Aug 2019 at 22:25, Joseph Myers <jos...@codesourcery.com> wrote:
>
> On Thu, 8 Aug 2019, Tejas Joshi wrote:
>
> > +/* Try to evaluate:
> > +
> > +      *RESULT = fadd (*ARG0, *ARG1)
> > +
> > +   in format FORMAT.  Return true on success.  */
> > +
> > +static bool
> > +fold_const_fadd (real_value *result, const real_value *arg0,
> > +              const real_value *arg1, const real_format *format)
> > +{
> > +  if (REAL_VALUE_ISSIGNALING_NAN (*arg0)
> > +      || REAL_VALUE_ISSIGNALING_NAN (*arg1))
> > +    return false;
> > +
> > +  if (real_fadd (result, format, arg0, arg1)
> > +      && !flag_errno_math)
> > +    return false;
>
> I think that rather than having a real_fadd function, you should just call
> real_arithmetic with a PLUS_EXPR argument and then move the overflow etc.
> checks out to here.
>
> That way, rather than having a fold_const_fadd function and then similar
> functions for fsub / fmul / fdiv, you can have one function that covers
> all four binary narrowing operations, which all have very similar logic,
> with an argument that is PLUS_EXPR etc. passed to the
> fold_const_narrow_binary (or whatever you call it) function.
>
> > +  if (!exact_real_truncate (format, result)
> > +      && !(flag_rounding_math && flag_trapping_math))
> > +    return false;
>
> I don't think the logic is right here.  What you want is: don't fold for
> inexact results if flag_rounding_math || flag_trapping_math.  I.e.:
>
>   if (!exact_real_truncate (format, result)
>       && (flag_rounding_math || flag_trapping_math))
>
> > +/* Perform addition of X and Y and place the result in R to narrowed
> > +   down type. Return TRUE if result involves overflow/underflow.  */
> > +
> > +bool
> > +real_fadd (REAL_VALUE_TYPE *r, format_helper fmt,
> > +        const REAL_VALUE_TYPE *x, const REAL_VALUE_TYPE *y)
> > +{
> > +  do_add (r, x, y, 0);
> > +
> > +  /* Overflow/underflow check.  */
> > +  if (REAL_EXP (r) > fmt->emax)
> > +  {
> > +    get_inf (r, r->sign);
> > +    return true;
> > +  }
>
> This isn't the right way to check for overflow.  You can have a result
> that's within the exponent range of the narrower format before rounding,
> but overflows after the rounding is done.  The right way to check for
> overflow (given that the result is inexact, and !flag_rounding_math &&
> !flag_trapping_math && flag_errno_math so that inexact results are OK but
> not if they overflow) would be to check after rounding whether the result
> is Inf when the arguments were finite.  (When you get only fdiv, that also
> becomes relevant for exact cases; fdiv (1.0, 0.0) produces an exact
> infinity but can't be folded if flag_errno_math || flag_trapping_math.)
>
> As well as overflow you also need to consider the case of fadd (Inf, -Inf)
> which would set errno to EDOM and raise "invalid" so, although exact, is
> also not allowed to be folded if flag_errno_math || flag_trapping_math.
> The generic logic there is: if the arguments are not NaN but the result is
> NaN, you can't fold if flag_errno_math || flag_trapping_math (but
> flag_rounding_math is irrelevant in that case).
>
> > 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..958d5a019d7
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/builtin-fadd-1.c
> > @@ -0,0 +1,31 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-O2" } */
> > +
> > +#define TEST(FN, VAL1, VAL2, RESULT) \
> > +  if (__builtin_##FN (VAL1, VAL2) != RESULT) __builtin_abort ();
>
> The tests ought to be tests of what gets optimized away (so causing link
> failures, as in the roundeven tests, if the calls don't get optimized or
> get optimized incorrectly).
>
> The tests should include cases that demonstrate there is only a single
> rounding involved: that there is no intermediate rounding to the wider
> type.  (E.g. fadd (0x1.000001p0, FLT_MIN), as an example from the glibc
> tests: cases where an intermediate rounding produces a result half way
> between two values of the narrower type, but the exact value is such that
> the result of fadd should end up with last bit odd whereas double rounding
> would result in last bit even in such half-way cases.)
>
> > +  TEST(fadd, __FLT_MAX__, __FLT_MAX__/2, 3*__FLT_MAX__/2);
>
> It would seem better to write the expected result here as __builtin_inff
> ().
>
> Then you should have some tests of what does *not* get optimized with
> given compiler options if possible.  (Such a test might e.g. define a
> static fadd function locally that checks it gets called as expected, or
> else check the exceptions / errno if you rely on a suitable libm being
> available.)
>
> --
> Joseph S. Myers
> jos...@codesourcery.com
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..abf8cfc9131 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -570,6 +570,37 @@ fold_const_nextafter (real_value *result, const real_value *arg0,
   return true;
 }
 
+/* Try to evaluate:
+
+      *RESULT = add/sub/mul/div (*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;
+
+  if (real_arithmetic (result, icode, arg0, arg1)
+      && (flag_rounding_math || flag_trapping_math))
+    return false;
+
+  real_convert (result, format, result);
+  /* Overflow/underflow 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 +1705,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..4e652d0ee59
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-1.c
@@ -0,0 +1,33 @@
+/* { dg-do link } */
+/* { dg-require-effective-target inf } */
+
+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, __FLT_MAX__, __FLT_MAX__/2, __builtin_inff ());
+  
+  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, __FLT_MAX__, __FLT_MAX__/2, __builtin_inff ());
+
+  TEST(daddl, 0L, 0L, 0.0);
+  TEST(daddl, 1L, -1L, 0.0);
+  TEST(daddl, -1L, -1.5L, -2.5);
+  TEST(daddl, 1.4L, 1.6L, 3.0);
+  TEST(daddl, 2.5L, 1.5L, 4.0);
+  TEST(daddl, __DBL_MAX__, __DBL_MAX__/2, __builtin_inf ());
+  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..ffec19570ac
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-fadd-2.c
@@ -0,0 +1,40 @@
+/* { dg-do link } */
+/* { dg-options "-O2 -frounding-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, 1, 1.1, 2.1F);
+  TEST(fadd, 3, 4.2, 7.2F);
+  TEST(fadd, 2, 4.3, 6.3F);
+  TEST(fadd, -2, -2.4, -4.4F);
+  TEST(fadd, -3, -3.6, -6.6F); 
+  TEST(fadd, -5.3, -5.4, -10.7F);
+  TEST(fadd, 8, 0.8, 8.8F);
+  TEST(fadd, 0.5, 0.4, 0.9F);
+
+  TEST(faddl, 1.0L, 1.1L, 2.1F);
+  TEST(faddl, 3.0L, 4.2L, 7.2F);
+  TEST(faddl, 2.0L, 4.3L, 6.3F);
+  TEST(faddl, -2.0L, -2.4L, -4.4F);
+  TEST(faddl, -3.0L, -3.6L, -6.6F); 
+  TEST(faddl, -5.3L, -5.4L, -10.7F);
+  TEST(faddl, 8.0L, 0.8L, 8.8F);
+  TEST(faddl, 0.5L, 0.4L, 0.9F);
+
+  TEST(daddl, 1.0L, 1.1L, 2.1);
+  TEST(daddl, 3.0L, 4.2L, 7.2);
+  TEST(daddl, 2.0L, 4.3L, 6.3);
+  TEST(daddl, -2.0L, -2.4L, -4.4);
+  TEST(daddl, -3.0L, -3.6L, -6.6); 
+  TEST(daddl, -5.3L, -5.4L, -10.7);
+  TEST(daddl, 8.0L, 0.8L, 8.8);
+  TEST(daddl, 0.5L, 0.4L, 0.9);
+
+  return 0;
+} 

Reply via email to