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  <ja...@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

Reply via email to