/* PR libstdc++/85466 */
/* { dg-do run } */
/* { dg-options "-O2 -fno-math-errno -fno-trapping-math -fdump-tree-optimized" } */
/* { dg-add-options ieee } */
/* { dg-skip-if "not IEEE float" { "pdp11-*-*" } } */
/* { dg-final { scan-tree-dump-not "nextafter" "optimized" } } */
/* { dg-final { scan-tree-dump-not "nexttoward" "optimized" } } */

#ifndef _NEXT_AFTER_2
float nextafterf (float, float);
double nextafter (double, double);
long double nextafterl (long double, long double);
float nexttowardf (float, long double);
double nexttoward (double, long double);
long double nexttowardl (long double, long double);
#endif

#define CHECK(x) if (!(x)) __builtin_abort ()

#ifndef NEED_ERRNO
#define NEED_ERRNO 0
#endif
#ifndef NEED_EXC
#define NEED_EXC 0
#endif
#ifndef NO_LONG_DOUBLE
#define NO_LONG_DOUBLE (__LDBL_MANT_DIG__ == 106)
#endif

#define TEST(name, fn, type, L1, L2, l1, l2, MIN1,			     \
	     MAX1, DENORM_MIN1, EPSILON1, MIN2, MAX2, DENORM_MIN2)	     \
void									     \
name (void)								     \
{									     \
  const type a = fn (0.0##L1, 0.0##L2);					     \
  CHECK (a == 0.0##L1 && !__builtin_signbit (a));			     \
  const type b = fn (0.0##L1, -0.0##L2);				     \
  CHECK (b == 0.0##L1 && __builtin_signbit (b));			     \
  const type c = fn (__builtin_nan##l1 (""), 0.0##L2);			     \
  CHECK (__builtin_isnan##l1 (c));					     \
  const type d = fn (2.0##L1, __builtin_nan##l2 (""));			     \
  CHECK (__builtin_isnan##l1 (d));					     \
  const type e = NEED_EXC ? DENORM_MIN1 : fn (0.0##L1, 8.0##L2);	     \
  CHECK (e == DENORM_MIN1);						     \
  const type f = fn (1.0##L1, 8.0##L2);					     \
  CHECK (f == 1.0##L1 + EPSILON1);					     \
  const type g = fn (1.0##L1, -8.0##L2);				     \
  CHECK (g == 1.0##L1 - EPSILON1 / 2.0##L1);				     \
  const type h = fn (__builtin_inf (), 0.0##L2);			     \
  CHECK (h == MAX1);							     \
  const type i = fn (-1.0##L1, -__builtin_inf ());			     \
  CHECK (i == -1.0##L1 - EPSILON1);					     \
  const type j = fn (1.5##L1, __builtin_inf ());			     \
  CHECK (j == 1.5##L1 + EPSILON1);					     \
  const type k = fn (1.5##L1 - EPSILON1, 100.0##L2);			     \
  CHECK (k == 1.5##L1);							     \
  const type l								     \
    = (NEED_EXC || NEED_ERRNO) ? 0.0##L1 : fn (DENORM_MIN1, 0.0##L2);	     \
  CHECK (l == 0.0##L1 && !__builtin_signbit (l));			     \
  const type m								     \
    = (NEED_EXC || NEED_ERRNO) ? __builtin_inf##l1 ()			     \
      : fn (MAX1, __builtin_inf ());					     \
  CHECK (__builtin_isinf##l1 (m) && !__builtin_signbit (m));		     \
  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								     \
    = (NEED_EXC || NEED_ERRNO) ? 3.0##L1 * DENORM_MIN1			     \
      : fn (n, 24.0##L2);						     \
  CHECK (o == 3.0##L1 * DENORM_MIN1);					     \
  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								     \
    = (NEED_EXC || NEED_ERRNO) ? DENORM_MIN1				     \
      : fn (2.0##L1 * DENORM_MIN1, -__builtin_inf ());			     \
  CHECK (q == DENORM_MIN1);						     \
  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								     \
    = (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								     \
    = (NEED_EXC || NEED_ERRNO) ? MIN1 - DENORM_MIN1			     \
      : fn (MIN1, 0.0##L2);						     \
  CHECK (t == MIN1 - DENORM_MIN1);					     \
  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								     \
    = (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);							     \
  const type x = fn (MIN1, 17.0##L2);					     \
  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								     \
    = (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								     \
    = (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);				     \
  const type ac = fn (MIN1 * 4.0##L1, MIN2);				     \
  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								     \
    = (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								     \
    = (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);						     \
  const type ah = fn (MIN1 * 4.0##L1 - 2.0##L1 * DENORM_MIN1, 100.0##L2);    \
  CHECK (ah == MIN1 * 4.0##L1);						     \
  const type ai = fn (MIN1 * 64.0##L1 - 32.0##L1 * DENORM_MIN1, 100.0##L2);  \
  CHECK (ai == MIN1 * 64.0##L1);					     \
  const type aj = fn (MIN1 * 64.0##L1, 100.0##L2);			     \
  CHECK (aj == MIN1 * 64.0##L1 + 64.0##L1 * DENORM_MIN1);		     \
  const type ak = fn (MIN1 * 64.0##L1 + DENORM_MIN1 * 64.0##L1, 1024.0##L2); \
  CHECK (ak == MIN1 * 64.0##L1 + 128.0##L1 * DENORM_MIN1);		     \
  const type al = fn (128.0##L1, 128.0##L2);				     \
  CHECK (al == 128.0##L1);						     \
  const type am = fn (128.0##L1, 129.0##L2);				     \
  CHECK (am == 128.0##L1 + 128.0##L1 * EPSILON1);			     \
  const type an = fn (-128.0##L1 + -128.0##L1 * EPSILON1, -130.0##L2);	     \
  CHECK (an == -128.0##L1 - 256.0##L1 * EPSILON1);			     \
  const type ao = fn (128.0##L1 + 256.0##L1 * EPSILON1, 256.0##L2);	     \
  CHECK (ao == 128.0##L1 + 384.0##L1 * EPSILON1);			     \
  const type ap = fn (128.0##L1 + 384.0##L1 * EPSILON1, -0.0##L2);	     \
  CHECK (ap == 128.0##L1 + 256.0##L1 * EPSILON1);			     \
  const type aq = fn (128.0##L1 + 256.0##L1 * EPSILON1, 1.0##L2);	     \
  CHECK (aq == 128.0##L1 + 128.0##L1 * EPSILON1);			     \
  const type ar = fn (128.0##L1 + 128.0##L1 * EPSILON1, 0.0##L2);	     \
  CHECK (ar == 128.0##L1);						     \
  const type as = fn (128.0##L1, 0.0##L2);				     \
  CHECK (as == 128.0##L1 - 64.0##L1 * EPSILON1);			     \
  const type at = fn (128.0##L1 - 64.0##L1 * EPSILON1, 5.0##L2);	     \
  CHECK (at == 128.0##L1 - 128.0##L1 * EPSILON1);			     \
}

TEST (test1, nextafterf, float, F, F, f, f, __FLT_MIN__, __FLT_MAX__,
      __FLT_DENORM_MIN__, __FLT_EPSILON__, __FLT_MIN__, __FLT_MAX__,
      __FLT_DENORM_MIN__)
TEST (test2, nextafter, double, , , , , __DBL_MIN__, __DBL_MAX__,
      __DBL_DENORM_MIN__, __DBL_EPSILON__, __DBL_MIN__, __DBL_MAX__,
      __DBL_DENORM_MIN__)
#if !NO_LONG_DOUBLE
TEST (test3, nextafterl, long double, L, L, l, l, __LDBL_MIN__, __LDBL_MAX__,
      __LDBL_DENORM_MIN__, __LDBL_EPSILON__, __LDBL_MIN__, __LDBL_MAX__,
      __LDBL_DENORM_MIN__)
TEST (test4, nexttowardf, float, F, L, f, l, __FLT_MIN__, __FLT_MAX__,
      __FLT_DENORM_MIN__, __FLT_EPSILON__, __LDBL_MIN__, __LDBL_MAX__,
      __LDBL_DENORM_MIN__)
TEST (test5, nexttoward, double, , L, , l, __DBL_MIN__, __DBL_MAX__,
      __DBL_DENORM_MIN__, __DBL_EPSILON__, __LDBL_MIN__, __LDBL_MAX__,
      __LDBL_DENORM_MIN__)
TEST (test6, nexttowardl, long double, L, L, l, l, __LDBL_MIN__, __LDBL_MAX__,
      __LDBL_DENORM_MIN__, __LDBL_EPSILON__, __LDBL_MIN__, __LDBL_MAX__,
      __LDBL_DENORM_MIN__)
#endif

int
main ()
{
  test1 ();
  test2 ();
#if !NO_LONG_DOUBLE
  test3 ();
  test4 ();
  test5 ();
  test6 ();
#endif
  return 0;
}
