public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Don't fold nextafter/nexttoward if -ftrapping-math or -fmath-errno if they produce denormal results (PR c/86420)
@ 2018-07-07  8:08 Jakub Jelinek
  2018-07-07  9:55 ` Marc Glisse
  2018-07-09  9:46 ` Richard Biener
  0 siblings, 2 replies; 6+ messages in thread
From: Jakub Jelinek @ 2018-07-07  8:08 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

Hi!

So, apparently I've misread when exceptions are raised by
nextafter/nexttoward (and errno set).
        if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
           ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     /* y is nan */
           return x+y;
I believe the above only raises exception if either operand is sNaN and thus
we should handle it:
  if (REAL_VALUE_ISSIGNALING_NAN (*arg0)
      || REAL_VALUE_ISSIGNALING_NAN (*arg1))
    return false;
Then:
        if(x==y) return y;              /* x=y, return y */
If arguments are equal, no exception is raised even if it is denormal,
we handle this with:
  /* If x == y, return y cast to target type.  */
  if (cmp == 0)
    {
      real_convert (r, fmt, y);
      return false;
    }
Next:
        if((ix|lx)==0) {                        /* x == 0 */
            double u;
            INSERT_WORDS(x,hy&0x80000000,1);    /* return +-minsubnormal */
            u = math_opt_barrier (x);
            u = u*u;
            math_force_eval (u);                /* raise underflow flag */
            return x;
        }
going from zero to +/- ulp should only raise underflow, but not set errno,
handled with:
  /* Similarly for nextafter (0, 1) raising underflow.  */
  else if (flag_trapping_math
           && arg0->cl == rvc_zero
           && result->cl != rvc_zero)
    return false;
Then overflow:
        hy = hx&0x7ff00000;
        if(hy>=0x7ff00000) {
          double u = x+x;       /* overflow  */
          math_force_eval (u);
          __set_errno (ERANGE);
        }
should be handled with:
          if (REAL_EXP (r) > fmt->emax)
            {
              get_inf (r, x->sign);
              return true;
            }
And finally there is:
        if(hy<0x00100000) {
            double u = x*x;                     /* underflow */
            math_force_eval (u);                /* raise underflow flag */
          __set_errno (ERANGE);
        }
which I've misread as raising exception and setting errno only if
the result is 0 and first arg isn't:
  return r->cl == rvc_zero;
but actually it is true also for all denormal returns except for the x == y
case, so the following patch uses:
  return r->cl == rvc_zero || REAL_EXP (r) < fmt->emin;
instead.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-07-07  Jakub Jelinek  <jakub@redhat.com>

	PR c/86420
	* real.c (real_nextafter): Return true if result is denormal.

	* gcc.dg/nextafter-1.c (TEST): Adjust the tests that expect denormals
	to be returned and when first argument is not 0, so that they don't do
	anything for NEED_EXC or NEED_ERRNO.

--- gcc/real.c.jj	2018-05-06 23:12:49.211619736 +0200
+++ gcc/real.c	2018-07-06 18:42:44.761026632 +0200
@@ -5141,7 +5141,7 @@ real_nextafter (REAL_VALUE_TYPE *r, form
       get_zero (r, x->sign);
       return true;
     }
-  return r->cl == rvc_zero;
+  return r->cl == rvc_zero || REAL_EXP (r) < fmt->emin;
 }
 
 /* Write into BUF the maximum representable finite floating-point
--- gcc/testsuite/gcc.dg/nextafter-1.c.jj	2018-05-10 09:38:03.040250709 +0200
+++ gcc/testsuite/gcc.dg/nextafter-1.c	2018-07-06 19:17:55.138355524 +0200
@@ -58,23 +58,41 @@ name (void)								     \
     = (NEED_EXC || NEED_ERRNO) ? __builtin_inf##l1 ()			     \
       : fn (MAX1, __builtin_inf ());					     \
   CHECK (__builtin_isinf##l1 (m) && !__builtin_signbit (m));		     \
-  const type n = fn (DENORM_MIN1, 12.0##L2);				     \
+  const type n								     \
+    = (NEED_EXC || NEED_ERRNO) ? 2.0##L1 * DENORM_MIN1			     \
+      : fn (DENORM_MIN1, 12.0##L2);					     \
   CHECK (n == 2.0##L1 * DENORM_MIN1);					     \
-  const type o = fn (n, 24.0##L2);					     \
+  const type o								     \
+    = (NEED_EXC || NEED_ERRNO) ? 3.0##L1 * DENORM_MIN1			     \
+      : fn (n, 24.0##L2);						     \
   CHECK (o == 3.0##L1 * DENORM_MIN1);					     \
-  const type p = fn (o, 132.0##L2);					     \
+  const type p								     \
+    = (NEED_EXC || NEED_ERRNO) ? 4.0##L1 * DENORM_MIN1			     \
+      : fn (o, 132.0##L2);						     \
   CHECK (p == 4.0##L1 * DENORM_MIN1);					     \
-  const type q = fn (2.0##L1 * DENORM_MIN1, -__builtin_inf ());		     \
+  const type q								     \
+    = (NEED_EXC || NEED_ERRNO) ? DENORM_MIN1				     \
+      : fn (2.0##L1 * DENORM_MIN1, -__builtin_inf ());			     \
   CHECK (q == DENORM_MIN1);						     \
-  const type r = fn (3.0##L1 * DENORM_MIN1, DENORM_MIN2);		     \
+  const type r								     \
+    = (NEED_EXC || NEED_ERRNO) ? 2.0##L1 * DENORM_MIN1			     \
+      : fn (3.0##L1 * DENORM_MIN1, DENORM_MIN2);			     \
   CHECK (r == 2.0##L1 * DENORM_MIN1);					     \
-  const type s = fn (4.0##L1 * DENORM_MIN1, 2.0##L2 * DENORM_MIN2);	     \
+  const type s								     \
+    = (NEED_EXC || NEED_ERRNO) ? 3.0##L1 * DENORM_MIN1			     \
+      : fn (4.0##L1 * DENORM_MIN1, 2.0##L2 * DENORM_MIN2);		     \
   CHECK (s == 3.0##L1 * DENORM_MIN1);					     \
-  const type t = fn (MIN1, 0.0##L2);					     \
+  const type t								     \
+    = (NEED_EXC || NEED_ERRNO) ? MIN1 - DENORM_MIN1			     \
+      : fn (MIN1, 0.0##L2);						     \
   CHECK (t == MIN1 - DENORM_MIN1);					     \
-  const type u = fn (MIN1 - DENORM_MIN1, -MIN2);			     \
+  const type u								     \
+    = (NEED_EXC || NEED_ERRNO) ? MIN1 - 2.0##L1 * DENORM_MIN1		     \
+      : fn (MIN1 - DENORM_MIN1, -MIN2);					     \
   CHECK (u == MIN1 - 2.0##L1 * DENORM_MIN1);				     \
-  const type v = fn (MIN1 - 2.0##L1 * DENORM_MIN1, 100.0##L2);		     \
+  const type v								     \
+    = (NEED_EXC || NEED_ERRNO) ? MIN1 - DENORM_MIN1			     \
+      : fn (MIN1 - 2.0##L1 * DENORM_MIN1, 100.0##L2);			     \
   CHECK (v == MIN1 - DENORM_MIN1);					     \
   const type w = fn (MIN1 - DENORM_MIN1, MAX2);				     \
   CHECK (w == MIN1);							     \
@@ -82,9 +100,13 @@ name (void)								     \
   CHECK (x == MIN1 + DENORM_MIN1);					     \
   const type y = fn (MIN1 + DENORM_MIN1, __builtin_inf##l2 ());		     \
   CHECK (y == MIN1 + 2.0##L1 * DENORM_MIN1);				     \
-  const type z = fn (MIN1 / 2.0##L1, -MIN2);				     \
+  const type z								     \
+    = (NEED_EXC || NEED_ERRNO) ? MIN1 / 2.0##L1 - DENORM_MIN1		     \
+      : fn (MIN1 / 2.0##L1, -MIN2);					     \
   CHECK (z == MIN1 / 2.0##L1 - DENORM_MIN1);				     \
-  const type aa = fn (-MIN1 / 4.0##L1, MIN2);				     \
+  const type aa								     \
+    = (NEED_EXC || NEED_ERRNO) ? -MIN1 / 4.0##L1 + DENORM_MIN1		     \
+      : fn (-MIN1 / 4.0##L1, MIN2);					     \
   CHECK (aa == -MIN1 / 4.0##L1 + DENORM_MIN1);				     \
   const type ab = fn (MIN1 * 2.0##L1, -MIN2);				     \
   CHECK (ab == MIN1 * 2.0##L1 - DENORM_MIN1);				     \
@@ -92,9 +114,13 @@ name (void)								     \
   CHECK (ac == MIN1 * 4.0##L1 - DENORM_MIN1 * 2.0##L1);			     \
   const type ad = fn (MIN1 * 64.0##L1, MIN2);				     \
   CHECK (ad == MIN1 * 64.0##L1 - DENORM_MIN1 * 32.0##L1);		     \
-  const type ae = fn (MIN1 / 2.0##L1 - DENORM_MIN1, 100.0##L2);		     \
+  const type ae								     \
+    = (NEED_EXC || NEED_ERRNO) ? MIN1 / 2.0##L1				     \
+      : fn (MIN1 / 2.0##L1 - DENORM_MIN1, 100.0##L2);			     \
   CHECK (ae == MIN1 / 2.0##L1);						     \
-  const type af = fn (-MIN1 / 4 + DENORM_MIN1, -100.0##L2);		     \
+  const type af								     \
+    = (NEED_EXC || NEED_ERRNO) ? -MIN1 / 4.0##L1			     \
+      : fn (-MIN1 / 4 + DENORM_MIN1, -100.0##L2);			     \
   CHECK (af == -MIN1 / 4.0##L1);					     \
   const type ag = fn (MIN1 * 2.0##L1 - DENORM_MIN1, 100.0##L2);		     \
   CHECK (ag == MIN1 * 2.0##L1);						     \

	Jakub

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-07-09  9:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-07  8:08 [PATCH] Don't fold nextafter/nexttoward if -ftrapping-math or -fmath-errno if they produce denormal results (PR c/86420) Jakub Jelinek
2018-07-07  9:55 ` Marc Glisse
2018-07-07 10:13   ` Jakub Jelinek
2018-07-07 11:31     ` Marc Glisse
2018-07-09  9:49   ` Richard Biener
2018-07-09  9:46 ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).