diff --git a/lib/msun/tests/cexp_test.c b/lib/msun/tests/cexp_test.c --- a/lib/msun/tests/cexp_test.c +++ b/lib/msun/tests/cexp_test.c @@ -63,7 +63,7 @@ volatile long double complex _d = z; \ volatile type complex _r = result; \ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ - ATF_CHECK(cfpequal_cs((func)(_d), (_r), (checksign))); \ + CHECK_CFPEQUAL_CS((func)(_d), (_r), (checksign)); \ CHECK_FP_EXCEPTIONS_MSG(excepts, exceptmask, "for %s(%s)", \ #func, #z); \ } while (0) @@ -75,10 +75,9 @@ test_t(float, func, z, result, exceptmask, excepts, checksign) /* Test within a given tolerance. */ -#define test_tol(func, z, result, tol) do { \ - volatile long double complex _d = z; \ - ATF_CHECK(cfpequal_tol((func)(_d), (result), (tol), \ - FPE_ABS_ZERO | CS_BOTH)); \ +#define test_tol(func, z, result, tol) do { \ + CHECK_CFPEQUAL_TOL((func)(z), (result), (tol), \ + FPE_ABS_ZERO | CS_BOTH); \ } while (0) /* Test all the functions that compute cexp(x). */ diff --git a/lib/msun/tests/conj_test.c b/lib/msun/tests/conj_test.c --- a/lib/msun/tests/conj_test.c +++ b/lib/msun/tests/conj_test.c @@ -82,12 +82,12 @@ __imag__ in = tests[2 * i + 1]; __imag__ expected = -cimag(in); - ATF_REQUIRE(fpequal(libcrealf(in), __real__ in)); - ATF_REQUIRE(fpequal(libcreal(in), __real__ in)); - ATF_REQUIRE(fpequal(libcreall(in), __real__ in)); - ATF_REQUIRE(fpequal(libcimagf(in), __imag__ in)); - ATF_REQUIRE(fpequal(libcimag(in), __imag__ in)); - ATF_REQUIRE(fpequal(libcimagl(in), __imag__ in)); + ATF_REQUIRE(fpequal_cs(libcrealf(in), __real__ in, true)); + ATF_REQUIRE(fpequal_cs(libcreal(in), __real__ in, true)); + ATF_REQUIRE(fpequal_cs(libcreall(in), __real__ in, true)); + ATF_REQUIRE(fpequal_cs(libcimagf(in), __imag__ in, true)); + ATF_REQUIRE(fpequal_cs(libcimag(in), __imag__ in, true)); + ATF_REQUIRE(fpequal_cs(libcimagl(in), __imag__ in, true)); ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); ATF_REQUIRE_MSG( diff --git a/lib/msun/tests/csqrt_test.c b/lib/msun/tests/csqrt_test.c --- a/lib/msun/tests/csqrt_test.c +++ b/lib/msun/tests/csqrt_test.c @@ -67,12 +67,7 @@ * Compare d1 and d2 using special rules: NaN == NaN and +0 != -0. * Fail an assertion if they differ. */ -static void -assert_equal(long double complex d1, long double complex d2) -{ - - ATF_CHECK(cfpequal(d1, d2)); -} +#define assert_equal(d1, d2) CHECK_CFPEQUAL_CS(d1, d2, CS_BOTH) /* * Test csqrt for some finite arguments where the answer is exact. diff --git a/lib/msun/tests/ctrig_test.c b/lib/msun/tests/ctrig_test.c --- a/lib/msun/tests/ctrig_test.c +++ b/lib/msun/tests/ctrig_test.c @@ -62,11 +62,7 @@ debug(" testing %s(%Lg + %Lg I) == %Lg + %Lg I\n", #func, \ creall(_d), cimagl(_d), creall(result), cimagl(result)); \ ATF_CHECK(feclearexcept(FE_ALL_EXCEPT) == 0); \ - volatile long double complex _r = (func)(_d); \ - ATF_CHECK_MSG(cfpequal_cs(_r, (result), (checksign)), \ - "%s (%Lg + %Lg I) != expected (%Lg + %Lg I)", \ - __XSTRING((func)(_d)), creall(_r), cimagl(_r), \ - creall(result), cimagl(result)); \ + CHECK_CFPEQUAL_CS((func)(_d), (result), (checksign)); \ volatile int _e = fetestexcept(exceptmask); \ ATF_CHECK_MSG(_e == (excepts), \ "%s fetestexcept(%s) (%#x) != %#x", __XSTRING(func), \ @@ -79,10 +75,9 @@ * of _EPSILON. */ #define test_p_tol(func, z, result, tol) do { \ - volatile long double complex _d = z; \ debug(" testing %s(%Lg + %Lg I) ~= %Lg + %Lg I\n", #func, \ - creall(_d), cimagl(_d), creall(result), cimagl(result)); \ - ATF_CHECK(cfpequal_tol((func)(_d), (result), (tol), FPE_ABS_ZERO)); \ + creall(z), cimagl(z), creall(result), cimagl(result)); \ + CHECK_CFPEQUAL_TOL((func)(z), (result), (tol), FPE_ABS_ZERO); \ } while (0) /* These wrappers apply the identities f(conj(z)) = conj(f(z)). */ diff --git a/lib/msun/tests/exponential_test.c b/lib/msun/tests/exponential_test.c --- a/lib/msun/tests/exponential_test.c +++ b/lib/msun/tests/exponential_test.c @@ -60,7 +60,7 @@ #define test(func, x, result, exceptmask, excepts) do { \ volatile long double _d = x; \ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ - ATF_CHECK(fpequal((func)(_d), (result))); \ + CHECK_FPEQUAL((func)(_d), (result)); \ CHECK_FP_EXCEPTIONS_MSG(excepts, exceptmask, "for %s(%s)", \ #func, #x); \ } while (0) diff --git a/lib/msun/tests/fenv_test.c b/lib/msun/tests/fenv_test.c --- a/lib/msun/tests/fenv_test.c +++ b/lib/msun/tests/fenv_test.c @@ -248,7 +248,7 @@ fexcept_t flag; int excepts, i; - ATF_CHECK_EQ(0, fetestexcept(FE_ALL_EXCEPT)); + CHECK_FP_EXCEPTIONS(0, FE_ALL_EXCEPT); for (i = 0; i < 1 << NEXCEPTS; i++) { excepts = std_except_sets[i]; diff --git a/lib/msun/tests/fma_test.c b/lib/msun/tests/fma_test.c --- a/lib/msun/tests/fma_test.c +++ b/lib/msun/tests/fma_test.c @@ -55,7 +55,7 @@ #define test(func, x, y, z, result, exceptmask, excepts) do { \ volatile long double _vx = (x), _vy = (y), _vz = (z); \ ATF_CHECK(feclearexcept(FE_ALL_EXCEPT) == 0); \ - ATF_CHECK(fpequal((func)(_vx, _vy, _vz), (result))); \ + CHECK_FPEQUAL((func)(_vx, _vy, _vz), (result)); \ CHECK_FP_EXCEPTIONS_MSG(excepts, exceptmask, "for %s(%s)", \ #func, #x); \ } while (0) diff --git a/lib/msun/tests/fmaxmin_test.c b/lib/msun/tests/fmaxmin_test.c --- a/lib/msun/tests/fmaxmin_test.c +++ b/lib/msun/tests/fmaxmin_test.c @@ -51,7 +51,7 @@ long double __result = func((__x), (__y)); \ CHECK_FP_EXCEPTIONS_MSG(0, ALL_STD_EXCEPT, \ #func "(%.20Lg, %.20Lg) rmode%d", (x), (y), rmode); \ - ATF_CHECK_MSG(fpequal(__result, (expected)), \ + ATF_CHECK_MSG(fpequal_cs(__result, (expected), true), \ #func "(%.20Lg, %.20Lg) rmode%d = %.20Lg, expected %.20Lg\n", \ (x), (y), rmode, __result, (expected)); \ } while (0) diff --git a/lib/msun/tests/invctrig_test.c b/lib/msun/tests/invctrig_test.c --- a/lib/msun/tests/invctrig_test.c +++ b/lib/msun/tests/invctrig_test.c @@ -61,7 +61,7 @@ debug(" testing %s(%Lg + %Lg I) == %Lg + %Lg I\n", #func, \ creall(_d), cimagl(_d), creall(result), cimagl(result)); \ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ - ATF_CHECK(cfpequal_cs((func)(_d), (result), (checksign))); \ + CHECK_CFPEQUAL_CS((func)(_d), (result), (checksign)); \ CHECK_FP_EXCEPTIONS_MSG(excepts, exceptmask, "for %s(%s)", \ #func, #z); \ } while (0) @@ -71,10 +71,9 @@ * in ulps. */ #define test_p_tol(func, z, result, tol) do { \ - volatile long double complex _d = z; \ debug(" testing %s(%Lg + %Lg I) ~= %Lg + %Lg I\n", #func, \ - creall(_d), cimagl(_d), creall(result), cimagl(result)); \ - ATF_CHECK(cfpequal_tol((func)(_d), (result), (tol), CS_BOTH)); \ + creall(z), cimagl(z), creall(result), cimagl(result)); \ + CHECK_CFPEQUAL_TOL((func)(z), (result), (tol), CS_BOTH); \ } while (0) /* These wrappers apply the identities f(conj(z)) = conj(f(z)). */ diff --git a/lib/msun/tests/invtrig_test.c b/lib/msun/tests/invtrig_test.c --- a/lib/msun/tests/invtrig_test.c +++ b/lib/msun/tests/invtrig_test.c @@ -54,7 +54,7 @@ #define test_tol(func, x, result, tol, excepts) do { \ volatile long double _in = (x), _out = (result); \ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ - ATF_CHECK(fpequal_tol(func(_in), _out, (tol), CS_BOTH)); \ + CHECK_FPEQUAL_TOL(func(_in), _out, (tol), CS_BOTH); \ CHECK_FP_EXCEPTIONS_MSG(excepts, ALL_STD_EXCEPT, "for %s(%s)", \ #func, #x); \ } while (0) @@ -84,7 +84,7 @@ #define test2_tol(func, y, x, result, tol, excepts) do { \ volatile long double _iny = (y), _inx = (x), _out = (result); \ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ - ATF_CHECK(fpequal_tol(func(_iny, _inx), _out, (tol), CS_BOTH)); \ + CHECK_FPEQUAL_TOL(func(_iny, _inx), _out, (tol), CS_BOTH); \ CHECK_FP_EXCEPTIONS_MSG(excepts, ALL_STD_EXCEPT, "for %s(%s)", \ #func, #x); \ } while (0) diff --git a/lib/msun/tests/logarithm_test.c b/lib/msun/tests/logarithm_test.c --- a/lib/msun/tests/logarithm_test.c +++ b/lib/msun/tests/logarithm_test.c @@ -61,7 +61,7 @@ #define test(func, x, result, exceptmask, excepts) do { \ volatile long double _d = x; \ ATF_CHECK_EQ(0, feclearexcept(FE_ALL_EXCEPT)); \ - ATF_CHECK(fpequal((func)(_d), (result))); \ + CHECK_FPEQUAL((func)(_d), (result)); \ CHECK_FP_EXCEPTIONS_MSG(excepts, exceptmask, "for %s(%s)", \ #func, #x); \ } while (0) @@ -69,7 +69,7 @@ #define test_tol(func, z, result, tol) do { \ volatile long double _d = z; \ debug(" testing %6s(%15La) ~= % .36Le\n", #func, _d, result); \ - ATF_CHECK(fpequal_tol((func)(_d), (result), (tol), CS_BOTH)); \ + CHECK_FPEQUAL_TOL((func)(_d), (result), (tol), CS_BOTH); \ } while (0) /* Test all the functions that compute log(x). */ @@ -207,7 +207,7 @@ 1.29556709996247903756734359702926363e0L }, { 19.75 * 0x1p100, 1.043037807481771029244272863419411534e2L, - 7.229787154734166181706169344438271459e1L, + 72.29787154734166181706169344438271459357255439172762452L, 3.139856666636059855894123306947856631e1L }, }; unsigned i; diff --git a/lib/msun/tests/lrint_test.c b/lib/msun/tests/lrint_test.c --- a/lib/msun/tests/lrint_test.c +++ b/lib/msun/tests/lrint_test.c @@ -42,16 +42,14 @@ #include "test-utils.h" -/* - * XXX The volatile here is to avoid gcc's bogus constant folding and work - * around the lack of support for the FENV_ACCESS pragma. - */ -#define test(func, x, result, excepts) do { \ - volatile double _d = x; \ - ATF_CHECK(feclearexcept(FE_ALL_EXCEPT) == 0); \ - ATF_CHECK((func)(_d) == (result) || fetestexcept(FE_INVALID)); \ - CHECK_FP_EXCEPTIONS_MSG(excepts, FE_ALL_EXCEPT & ALL_STD_EXCEPT,\ - "for %s(%s)", #func, #x); \ +#define test(func, x, result, excepts) do { \ + ATF_CHECK(feclearexcept(FE_ALL_EXCEPT) == 0); \ + long long _r = (func)(x); \ + ATF_CHECK_MSG(_r == (result) || fetestexcept(FE_INVALID), \ + #func "(%Lg) returned %lld, expected %lld", (long double)x, _r, \ + (long long)(result)); \ + CHECK_FP_EXCEPTIONS_MSG(excepts, FE_ALL_EXCEPT & ALL_STD_EXCEPT, \ + "for %s(%s)", #func, #x); \ } while (0) #define testall(x, result, excepts) do { \ diff --git a/lib/msun/tests/nearbyint_test.c b/lib/msun/tests/nearbyint_test.c --- a/lib/msun/tests/nearbyint_test.c +++ b/lib/msun/tests/nearbyint_test.c @@ -97,16 +97,16 @@ in = tests[testindex].in; out = get_output(testindex, i, 0); - ATF_CHECK(fpequal(out, libnearbyintf(in))); - ATF_CHECK(fpequal(out, nearbyint(in))); - ATF_CHECK(fpequal(out, nearbyintl(in))); + CHECK_FPEQUAL(out, libnearbyintf(in)); + CHECK_FPEQUAL(out, nearbyint(in)); + CHECK_FPEQUAL(out, nearbyintl(in)); CHECK_FP_EXCEPTIONS(0, ALL_STD_EXCEPT); in = -tests[testindex].in; out = get_output(testindex, i, 1); - ATF_CHECK(fpequal(out, nearbyintf(in))); - ATF_CHECK(fpequal(out, nearbyint(in))); - ATF_CHECK(fpequal(out, nearbyintl(in))); + CHECK_FPEQUAL(out, nearbyintf(in)); + CHECK_FPEQUAL(out, nearbyint(in)); + CHECK_FPEQUAL(out, nearbyintl(in)); CHECK_FP_EXCEPTIONS(0, ALL_STD_EXCEPT); } } @@ -130,24 +130,24 @@ isinf(ipart_expected) ? 0.0 : in - ipart_expected, in); ipartl = ipart = ipartf = 42.0; - ATF_CHECK(fpequal(out, modff(in, &ipartf))); - ATF_CHECK(fpequal(ipart_expected, ipartf)); - ATF_CHECK(fpequal(out, modf(in, &ipart))); - ATF_CHECK(fpequal(ipart_expected, ipart)); - ATF_CHECK(fpequal(out, modfl(in, &ipartl))); - ATF_CHECK(fpequal(ipart_expected, ipartl)); + CHECK_FPEQUAL(out, modff(in, &ipartf)); + CHECK_FPEQUAL(ipart_expected, ipartf); + CHECK_FPEQUAL(out, modf(in, &ipart)); + CHECK_FPEQUAL(ipart_expected, ipart); + CHECK_FPEQUAL(out, modfl(in, &ipartl)); + CHECK_FPEQUAL(ipart_expected, ipartl); CHECK_FP_EXCEPTIONS(0, ALL_STD_EXCEPT); in = -in; ipart_expected = -ipart_expected; out = -out; ipartl = ipart = ipartf = 42.0; - ATF_CHECK(fpequal(out, modff(in, &ipartf))); - ATF_CHECK(fpequal(ipart_expected, ipartf)); - ATF_CHECK(fpequal(out, modf(in, &ipart))); - ATF_CHECK(fpequal(ipart_expected, ipart)); - ATF_CHECK(fpequal(out, modfl(in, &ipartl))); - ATF_CHECK(fpequal(ipart_expected, ipartl)); + CHECK_FPEQUAL(out, modff(in, &ipartf)); + CHECK_FPEQUAL(ipart_expected, ipartf); + CHECK_FPEQUAL(out, modf(in, &ipart)); + CHECK_FPEQUAL(ipart_expected, ipart); + CHECK_FPEQUAL(out, modfl(in, &ipartl)); + CHECK_FPEQUAL(ipart_expected, ipartl); CHECK_FP_EXCEPTIONS(0, ALL_STD_EXCEPT); } } diff --git a/lib/msun/tests/next_test.c b/lib/msun/tests/next_test.c --- a/lib/msun/tests/next_test.c +++ b/lib/msun/tests/next_test.c @@ -247,7 +247,7 @@ int actual_except; actual_except = fetestexcept(ALL_STD_EXCEPT); - if (!fpequal(actual, expected)) { + if (!fpequal_cs(actual, expected, true)) { atf_tc_fail_check(__FILE__, line, "%s returned %La, expecting %La\n", exp, actual, expected); } diff --git a/lib/msun/tests/test-utils.h b/lib/msun/tests/test-utils.h --- a/lib/msun/tests/test-utils.h +++ b/lib/msun/tests/test-utils.h @@ -31,6 +31,7 @@ #include #include +#include #include @@ -90,34 +91,21 @@ } #endif -static int fpequal(long double, long double) __used; -static int cfpequal(long double complex, long double complex) __used; -static int cfpequal_cs(long double complex, long double complex, - int) __used; -static int cfpequal_tol(long double complex, long double complex, - long double, unsigned int) __used; - /* - * Compare d1 and d2 using special rules: NaN == NaN and +0 != -0. - * Fail an assertion if they differ. + * The compiler-rt fp128 builtins do not update FP exceptions. + * See https://llvm.org/PR34126 */ -static int -fpequal(long double d1, long double d2) -{ - if (d1 != d2) - return (isnan(d1) && isnan(d2)); - return (copysignl(1.0, d1) == copysignl(1.0, d2)); -} +static int cfpequal(long double complex, long double complex) __used; /* * Determine whether x and y are equal, with two special rules: * +0.0 != -0.0 * NaN == NaN - * If checksign is 0, we compare the absolute values instead. + * If checksign is false, we compare the absolute values instead. */ -static int -fpequal_cs(long double x, long double y, int checksign) +static inline int +fpequal_cs(long double x, long double y, bool checksign) { if (isnan(x) && isnan(y)) return (1); @@ -127,7 +115,7 @@ return (fabsl(x) == fabsl(y)); } -static int +static inline int fpequal_tol(long double x, long double y, long double tol, unsigned int flags) { @@ -158,32 +146,54 @@ return (ret); } -static int +#define CHECK_FPEQUAL(x, y) CHECK_FPEQUAL_CS(x, y, true) + +#define CHECK_FPEQUAL_CS(x, y, checksign) do { \ + long double _x = x; \ + long double _y = y; \ + ATF_CHECK_MSG(fpequal_cs(_x, _y, checksign), \ + "%s (%.25Lg) ~= %s (%.25Lg)", #x, _x, #y, _y); \ +} while (0) + +#define CHECK_FPEQUAL_TOL(x, y, tol, flags) do { \ + long double _x = x; \ + long double _y = y; \ + bool eq = fpequal_tol(_x, _y, tol, flags); \ + long double _diff = eq ? 0.0L : fabsl(_x - _y); \ + ATF_CHECK_MSG(eq, "%s (%.25Lg) ~= %s (%.25Lg), diff=%Lg, maxdiff=%Lg,", \ + #x, _x, #y, _y, _diff, fabsl(_y * tol)); \ +} while (0) + +static inline int cfpequal(long double complex d1, long double complex d2) { - return (fpequal(creall(d1), creall(d2)) && - fpequal(cimagl(d1), cimagl(d2))); + return (fpequal_cs(creall(d1), creall(d2), true) && + fpequal_cs(cimagl(d1), cimagl(d2), true)); } -static int -cfpequal_cs(long double complex x, long double complex y, int checksign) -{ - return (fpequal_cs(creal(x), creal(y), checksign) - && fpequal_cs(cimag(x), cimag(y), checksign)); -} - -static int -cfpequal_tol(long double complex x, long double complex y, long double tol, - unsigned int flags) -{ - return (fpequal_tol(creal(x), creal(y), tol, flags) - && fpequal_tol(cimag(x), cimag(y), tol, flags)); -} +#define CHECK_CFPEQUAL_CS(x, y, checksign) do { \ + long double _x = x; \ + long double _y = y; \ + bool equal_cs = \ + fpequal_cs(creal(_x), creal(_y), (checksign & CS_REAL) != 0) && \ + fpequal_cs(cimag(_x), cimag(_y), (checksign & CS_IMAG) != 0); \ + ATF_CHECK_MSG(equal_cs, "%s (%Lg + %Lg I) ~= %s (%Lg + %Lg I)", \ + #x, creall(_x), cimagl(_x), #y, creall(_y), cimagl(_y)); \ +} while (0) + +#define CHECK_CFPEQUAL_TOL(x, y, tol, flags) do { \ + long double _x = x; \ + long double _y = y; \ + bool equal_tol = (fpequal_tol(creal(_x), creal(_y), tol, flags) && \ + fpequal_tol(cimag(_x), cimag(_y), tol, flags)); \ + ATF_CHECK_MSG(equal_tol, "%s (%Lg + %Lg I) ~= %s (%Lg + %Lg I)", \ + #x, creall(_x), cimagl(_x), #y, creall(_y), cimagl(_y)); \ +} while (0) #define CHECK_FP_EXCEPTIONS(excepts, exceptmask) \ ATF_CHECK_EQ_MSG((excepts), fetestexcept(exceptmask), \ - "unexpected exception flags: %#x not %#x", \ + "unexpected exception flags: got %#x not %#x", \ fetestexcept(exceptmask), (excepts)) #define CHECK_FP_EXCEPTIONS_MSG(excepts, exceptmask, fmt, ...) \ ATF_CHECK_EQ_MSG((excepts), fetestexcept(exceptmask), \ diff --git a/lib/msun/tests/trig_test.c b/lib/msun/tests/trig_test.c --- a/lib/msun/tests/trig_test.c +++ b/lib/msun/tests/trig_test.c @@ -63,7 +63,7 @@ #define test(func, x, result, exceptmask, excepts) do { \ volatile long double _d = x; \ ATF_CHECK(feclearexcept(FE_ALL_EXCEPT) == 0); \ - ATF_CHECK(fpequal((func)(_d), (result))); \ + CHECK_FPEQUAL((func)(_d), (result)); \ CHECK_FP_EXCEPTIONS_MSG(excepts, exceptmask, "for %s(%s)", \ #func, #x); \ } while (0)