diff --git a/compiler-rt/lib/builtins/aarch64/fp_mode.c b/compiler-rt/lib/builtins/aarch64/fp_mode.c --- a/compiler-rt/lib/builtins/aarch64/fp_mode.c +++ b/compiler-rt/lib/builtins/aarch64/fp_mode.c @@ -18,6 +18,8 @@ AARCH64_DOWNWARD | AARCH64_TOWARDZERO) #define AARCH64_RMODE_SHIFT 22 +#define AARCH64_INVALID 0x1 +#define AARCH64_DIVBYZERO 0x2 #define AARCH64_INEXACT 0x10 #ifndef __ARM_FP @@ -48,11 +50,33 @@ #endif } +int __fe_raise_divbyzero() { +#ifdef __ARM_FP + uint64_t fpsr; + __asm__ __volatile__("mrs %0, fpsr" : "=r"(fpsr)); + __asm__ __volatile__("msr fpsr, %0" : : "ri"(fpsr | AARCH64_DIVBYZERO)); + return 0; +#else + return 0; +#endif +} + int __fe_raise_inexact(void) { #ifdef __ARM_FP uint64_t fpsr; - __asm__ __volatile__("mrs %0, fpsr" : "=r" (fpsr)); - __asm__ __volatile__("msr fpsr, %0" : : "ri" (fpsr | AARCH64_INEXACT)); + __asm__ __volatile__("mrs %0, fpsr" : "=r"(fpsr)); + __asm__ __volatile__("msr fpsr, %0" : : "ri"(fpsr | AARCH64_INEXACT)); + return 0; +#else + return 0; +#endif +} + +int __fe_raise_invalid() { +#ifdef __ARM_FP + uint64_t fpsr; + __asm__ __volatile__("mrs %0, fpsr" : "=r"(fpsr)); + __asm__ __volatile__("msr fpsr, %0" : : "ri"(fpsr | AARCH64_INVALID)); return 0; #else return 0; diff --git a/compiler-rt/lib/builtins/arm/fp_mode.c b/compiler-rt/lib/builtins/arm/fp_mode.c --- a/compiler-rt/lib/builtins/arm/fp_mode.c +++ b/compiler-rt/lib/builtins/arm/fp_mode.c @@ -18,6 +18,8 @@ ARM_DOWNWARD | ARM_TOWARDZERO) #define ARM_RMODE_SHIFT 22 +#define ARM_INVALID 0x01 +#define ARM_DIVBYZERO 0x02 #define ARM_INEXACT 0x10 #ifndef __ARM_FP @@ -48,11 +50,33 @@ #endif } +int __fe_raise_divbyzero() { +#ifdef __ARM_FP + uint32_t fpscr; + __asm__ __volatile__("vmrs %0, fpscr" : "=r"(fpscr)); + __asm__ __volatile__("vmsr fpscr, %0" : : "ri"(fpscr | ARM_DIVBYZERO)); + return 0; +#else + return 0; +#endif +} + int __fe_raise_inexact(void) { #ifdef __ARM_FP uint32_t fpscr; - __asm__ __volatile__("vmrs %0, fpscr" : "=r" (fpscr)); - __asm__ __volatile__("vmsr fpscr, %0" : : "ri" (fpscr | ARM_INEXACT)); + __asm__ __volatile__("vmrs %0, fpscr" : "=r"(fpscr)); + __asm__ __volatile__("vmsr fpscr, %0" : : "ri"(fpscr | ARM_INEXACT)); + return 0; +#else + return 0; +#endif +} + +int __fe_raise_invalid() { +#ifdef __ARM_FP + uint32_t fpscr; + __asm__ __volatile__("vmrs %0, fpscr" : "=r"(fpscr)); + __asm__ __volatile__("vmsr fpscr, %0" : : "ri"(fpscr | ARM_INVALID)); return 0; #else return 0; diff --git a/compiler-rt/lib/builtins/fp_add_impl.inc b/compiler-rt/lib/builtins/fp_add_impl.inc --- a/compiler-rt/lib/builtins/fp_add_impl.inc +++ b/compiler-rt/lib/builtins/fp_add_impl.inc @@ -24,16 +24,27 @@ if (aAbs - REP_C(1) >= infRep - REP_C(1) || bAbs - REP_C(1) >= infRep - REP_C(1)) { // NaN + anything = qNaN - if (aAbs > infRep) + if (aAbs > infRep) { + // Raise invalid if one of the operands is a sNaN (IEEE-754-2019 7.2a). + if ((aRep & quietBit) == 0 || repIsSNaN(bRep)) + __fe_raise_invalid(); return fromRep(toRep(a) | quietBit); + } // anything + NaN = qNaN - if (bAbs > infRep) + if (bAbs > infRep) { + // Raise invalid if one of the operands is a sNaN (IEEE-754-2019 7.2a). + if ((bRep & quietBit) == 0 || repIsSNaN(aRep)) + __fe_raise_invalid(); return fromRep(toRep(b) | quietBit); + } if (aAbs == infRep) { // +/-infinity + -/+infinity = qNaN - if ((toRep(a) ^ toRep(b)) == signBit) + if ((toRep(a) ^ toRep(b)) == signBit) { + // Magnitude subtraction of inf raises invalid (IEEE-754-2019 7.2d). + __fe_raise_invalid(); return fromRep(qnanRep); + } // +/-infinity + anything remaining = +/- infinity else return a; diff --git a/compiler-rt/lib/builtins/fp_div_impl.inc b/compiler-rt/lib/builtins/fp_div_impl.inc --- a/compiler-rt/lib/builtins/fp_div_impl.inc +++ b/compiler-rt/lib/builtins/fp_div_impl.inc @@ -50,16 +50,27 @@ const rep_t bAbs = toRep(b) & absMask; // NaN / anything = qNaN - if (aAbs > infRep) + if (aAbs > infRep) { + // Raise invalid if one of the operands is a sNaN (IEEE-754-2019 7.2a). + if ((toRep(a) & quietBit) == 0 || repIsSNaN(toRep(b))) + __fe_raise_invalid(); return fromRep(toRep(a) | quietBit); + } // anything / NaN = qNaN - if (bAbs > infRep) + if (bAbs > infRep) { + // Raise invalid if one of the operands is a sNaN (IEEE-754-2019 7.2a). + if ((toRep(b) & quietBit) == 0 || repIsSNaN(toRep(a))) + __fe_raise_invalid(); return fromRep(toRep(b) | quietBit); + } if (aAbs == infRep) { // infinity / infinity = NaN - if (bAbs == infRep) + if (bAbs == infRep) { + // infinity / infinity raises invalid (IEEE-754-2019 7.2e). + __fe_raise_invalid(); return fromRep(qnanRep); + } // infinity / anything else = +/- infinity else return fromRep(aAbs | quotientSign); @@ -71,15 +82,23 @@ if (!aAbs) { // zero / zero = NaN - if (!bAbs) + if (!bAbs) { + // zero / zero raises invalid (IEEE-754-2019 7.2e). + __fe_raise_invalid(); return fromRep(qnanRep); + } // zero / anything else = +/- zero else return fromRep(quotientSign); } // anything else / zero = +/- infinity - if (!bAbs) + if (!bAbs) { + // DIVBYZERO if dividend is a finite non-zero number (IEEE-754-2019 7.3). + // We handled the a==infinity, a==zero, and a==Nan cases earlier so + // it must be a finite non-zero number now. + __fe_raise_divbyzero(); return fromRep(infRep | quotientSign); + } // One or both of a or b is denormal. The other (if applicable) is a // normal number. Renormalize one or both of a and b, and set scale to diff --git a/compiler-rt/lib/builtins/fp_fixint_impl.inc b/compiler-rt/lib/builtins/fp_fixint_impl.inc --- a/compiler-rt/lib/builtins/fp_fixint_impl.inc +++ b/compiler-rt/lib/builtins/fp_fixint_impl.inc @@ -28,8 +28,11 @@ return 0; // If the value is too large for the integer type, saturate. - if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT) + if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT) { + // Values that are too large/infinity/NaN raise invalid (IEEE-754-2019 7.2j). + __fe_raise_invalid(); return sign == 1 ? fixint_max : fixint_min; + } // If 0 <= exponent < significandBits, right shift to get the result. // Otherwise, shift left. diff --git a/compiler-rt/lib/builtins/fp_fixuint_impl.inc b/compiler-rt/lib/builtins/fp_fixuint_impl.inc --- a/compiler-rt/lib/builtins/fp_fixuint_impl.inc +++ b/compiler-rt/lib/builtins/fp_fixuint_impl.inc @@ -26,8 +26,11 @@ return 0; // If the value is too large for the integer type, saturate. - if ((unsigned)exponent >= sizeof(fixuint_t) * CHAR_BIT) + if ((unsigned)exponent >= sizeof(fixuint_t) * CHAR_BIT) { + // Values that are too large/infinity/NaN raise invalid (IEEE-754-2019 7.2j). + __fe_raise_invalid(); return ~(fixuint_t)0; + } // If 0 <= exponent < significandBits, right shift to get the result. // Otherwise, shift left. diff --git a/compiler-rt/lib/builtins/fp_lib.h b/compiler-rt/lib/builtins/fp_lib.h --- a/compiler-rt/lib/builtins/fp_lib.h +++ b/compiler-rt/lib/builtins/fp_lib.h @@ -20,6 +20,7 @@ #ifndef FP_LIB_HEADER #define FP_LIB_HEADER +#include "fp_mode.h" #include "int_lib.h" #include "int_math.h" #include @@ -240,6 +241,10 @@ return rep.f; } +static inline bool repIsSNaN(rep_t x) { + return ((x & absMask) > infRep && (x & quietBit) == 0); +} + static __inline int normalize(rep_t *significand) { const int shift = rep_clz(*significand) - rep_clz(implicitBit); *significand <<= shift; @@ -286,7 +291,8 @@ return -x; // -inf: return -x } } else if (x == 0.0) { - // 0.0: return -inf + // 0.0: return -inf and raise divide by zero (IEEE-754-2019 5.3.3 + 7.3) + __fe_raise_divbyzero(); return fromRep(infRep | signBit); } diff --git a/compiler-rt/lib/builtins/fp_mode.h b/compiler-rt/lib/builtins/fp_mode.h --- a/compiler-rt/lib/builtins/fp_mode.h +++ b/compiler-rt/lib/builtins/fp_mode.h @@ -24,6 +24,8 @@ } CRT_FE_ROUND_MODE; CRT_FE_ROUND_MODE __fe_getround(void); +int __fe_raise_divbyzero(void); int __fe_raise_inexact(void); +int __fe_raise_invalid(void); #endif // FP_MODE_H diff --git a/compiler-rt/lib/builtins/fp_mode.c b/compiler-rt/lib/builtins/fp_mode.c --- a/compiler-rt/lib/builtins/fp_mode.c +++ b/compiler-rt/lib/builtins/fp_mode.c @@ -17,6 +17,8 @@ // IEEE-754 default rounding (to nearest, ties to even). CRT_FE_ROUND_MODE __fe_getround(void) { return CRT_FE_TONEAREST; } -int __fe_raise_inexact(void) { - return 0; -} +int __fe_raise_divbyzero() { return 0; } + +int __fe_raise_inexact(void) { return 0; } + +int __fe_raise_invalid() { return 0; } diff --git a/compiler-rt/lib/builtins/fp_mul_impl.inc b/compiler-rt/lib/builtins/fp_mul_impl.inc --- a/compiler-rt/lib/builtins/fp_mul_impl.inc +++ b/compiler-rt/lib/builtins/fp_mul_impl.inc @@ -30,28 +30,40 @@ const rep_t bAbs = toRep(b) & absMask; // NaN * anything = qNaN - if (aAbs > infRep) + if (aAbs > infRep) { + // Raise invalid if one of the operands is a sNaN (IEEE-754-2019 7.2a). + if ((toRep(a) & quietBit) == 0 || repIsSNaN(toRep(b))) + __fe_raise_invalid(); return fromRep(toRep(a) | quietBit); + } // anything * NaN = qNaN - if (bAbs > infRep) + if (bAbs > infRep) { + // Raise invalid if one of the operands is a sNaN (IEEE-754-2019 7.2a). + if ((toRep(b) & quietBit) == 0 || repIsSNaN(toRep(a))) + __fe_raise_invalid(); return fromRep(toRep(b) | quietBit); + } if (aAbs == infRep) { - // infinity * non-zero = +/- infinity - if (bAbs) + if (bAbs) { + // infinity * non-zero = +/- infinity return fromRep(aAbs | productSign); - // infinity * zero = NaN - else + } else { + // infinity * zero = NaN, raises invalid (IEEE-754-2019 7.2b). + __fe_raise_invalid(); return fromRep(qnanRep); + } } if (bAbs == infRep) { - // non-zero * infinity = +/- infinity - if (aAbs) + if (aAbs) { + // non-zero * infinity = +/- infinity return fromRep(bAbs | productSign); - // zero * infinity = NaN - else + } else { + // zero * infinity = NaN, raises invalid (IEEE-754-2019 7.2b). + __fe_raise_invalid(); return fromRep(qnanRep); + } } // zero * anything = +/- zero diff --git a/compiler-rt/lib/builtins/i386/fp_mode.c b/compiler-rt/lib/builtins/i386/fp_mode.c --- a/compiler-rt/lib/builtins/i386/fp_mode.c +++ b/compiler-rt/lib/builtins/i386/fp_mode.c @@ -32,8 +32,20 @@ return CRT_FE_TONEAREST; } +int __fe_raise_divbyzero() { + float f = 1.0f, g = 0.0f; + __asm__ __volatile__("fdivs %1" : "+t"(f) : "m"(g)); + return 0; +} + int __fe_raise_inexact(void) { float f = 1.0f, g = 3.0f; - __asm__ __volatile__ ("fdivs %1" : "+t" (f) : "m" (g)); + __asm__ __volatile__("fdivs %1" : "+t"(f) : "m"(g)); + return 0; +} + +int __fe_raise_invalid() { + float inf = __builtin_inff(); + __asm__ __volatile__("fdivs %1" : "+t"(inf) : "m"(inf)); return 0; } diff --git a/compiler-rt/lib/builtins/riscv/fp_mode.c b/compiler-rt/lib/builtins/riscv/fp_mode.c --- a/compiler-rt/lib/builtins/riscv/fp_mode.c +++ b/compiler-rt/lib/builtins/riscv/fp_mode.c @@ -12,7 +12,11 @@ #define RISCV_DOWNWARD 0x2 #define RISCV_UPWARD 0x3 -#define RISCV_INEXACT 0x1 +#define RISCV_INEXACT 0x01 +#define RISCV_UNDERFLOW 0x02 +#define RISCV_OVERFLOW 0x04 +#define RISCV_DIVBYZERO 0x08 +#define RISCV_INVALID 0x10 CRT_FE_ROUND_MODE __fe_getround(void) { #if defined(__riscv_f) @@ -34,9 +38,23 @@ #endif } +int __fe_raise_divbyzero() { +#if defined(__riscv_f) + __asm__ __volatile__("csrsi fflags, %0" ::"i"(RISCV_DIVBYZERO)); +#endif + return 0; +} + int __fe_raise_inexact(void) { #if defined(__riscv_f) - __asm__ __volatile__("csrsi fflags, %0" :: "i" (RISCV_INEXACT)); + __asm__ __volatile__("csrsi fflags, %0" ::"i"(RISCV_INEXACT)); +#endif + return 0; +} + +int __fe_raise_invalid() { +#if defined(__riscv_f) + __asm__ __volatile__("csrsi fflags, %0" ::"i"(RISCV_INVALID)); #endif return 0; } diff --git a/compiler-rt/test/builtins/Unit/addtf3_test.c b/compiler-rt/test/builtins/Unit/addtf3_test.c --- a/compiler-rt/test/builtins/Unit/addtf3_test.c +++ b/compiler-rt/test/builtins/Unit/addtf3_test.c @@ -1,105 +1,115 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t // REQUIRES: librt_has_addtf3 -#include +#define QUAD_PRECISION +#include "fp_lib.h" +#include "fp_test_fenv.h" #include -#if __LDBL_MANT_DIG__ == 113 - -#include "int_lib.h" -#include "fp_test.h" +#if __LDBL_MANT_DIG__ != 113 +int main() { + fprintf(stderr, "Missing f128 support - skipping.\n"); + return 1; +} +#else +_Static_assert(sizeof(long double) == 16, ""); // Returns: a + b COMPILER_RT_ABI long double __addtf3(long double a, long double b); -int test__addtf3(long double a, long double b, - uint64_t expectedHi, uint64_t expectedLo) -{ - long double x = __addtf3(a, b); - int ret = compareResultLD(x, expectedHi, expectedLo); - - if (ret){ - printf("error in test__addtf3(%.20Lf, %.20Lf) = %.20Lf, " - "expected %.20Lf\n", a, b, x, - fromRep128(expectedHi, expectedLo)); - } - - return ret; +int _test__addtf3(int line, long double a, long double b, int expectedExc, + uint64_t expectedHi, uint64_t expectedLo) { + feclearexcept(FE_ALL_EXCEPT); + long double x = __addtf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); + int ret = compareResultLD(x, expectedHi, expectedLo); + if (ret) { + fprintf(stderr, "%s:%d: error in %s(" F128_FMT ", " F128_FMT ") ", __FILE__, + line, __func__, F128_ARG(a), F128_ARG(b)); + printMismatchLD(x, expectedHi, expectedLo); + } + if (!checkFPException(__FILE__, line, actualExc, expectedExc)) + ret = 1; + return ret; +} +# define test__addtf3(...) _test__addtf3(__LINE__, __VA_ARGS__) + +int main() { + // qNaN + any = qNaN + if (test__addtf3(makeQNaN128(), 0x1.23456789abcdefp+5L, 0, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // NaN + any = NaN + if (test__addtf3(makeNaN128(UINT64_C(0x800030000000)), 0x1.23456789abcdefp+5L, + 0, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // sNaN + any = qNaN, FE_INVALID + if (test__addtf3(makeNaN128(UINT64_C(0x12345)), TF_C(0x1.23456789abcdefp+5), + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // any + sNaN = qNaN, FE_INVALID + if (test__addtf3(TF_C(0x1.23456789abcdefp+5), makeNaN128(UINT64_C(0x12345)), + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // inf + inf = inf + if (test__addtf3(makeInf128(), makeInf128(), 0, UINT64_C(0x7fff000000000000), + UINT64_C(0x0))) + return 1; + // inf + any = inf + if (test__addtf3(makeInf128(), 0x1.2335653452436234723489432abcdefp+5L, 0, + UINT64_C(0x7fff000000000000), UINT64_C(0x0))) + return 1; + + // inf + -inf = NaN, FE_INVALID + if (test__addtf3(makeInf128(), makeNegativeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // -inf + inf = NaN, FE_INVALID + if (test__addtf3(makeNegativeInf128(), makeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // any + any + if (test__addtf3(0x1.23456734245345543849abcdefp+5L, + 0x1.edcba52449872455634654321fp-1L, 0, + UINT64_C(0x40042afc95c8b579), UINT64_C(0x61e58dd6c51eb77c))) + return 1; + +# if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) || \ + defined(i386) || defined(__x86_64__) || \ + (defined(__loongarch__) && __loongarch_frlen != 0) + // Rounding mode tests on supported architectures + const long double m = assertLDRepresentation( + 1234.0Q, UINT64_C(0x4009348000000000), UINT64_C(0x0000000000000000)); + // Closest approximation of 0.1 for f128: + const long double n = assertLDRepresentation( + 0.01Q, UINT64_C(0x3ff847ae147ae147), UINT64_C(0xae147ae147ae147b)); + + fesetround(FE_UPWARD); + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d8))) + return 1; + + fesetround(FE_DOWNWARD); + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; + + fesetround(FE_TOWARDZERO); + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; + + fesetround(FE_TONEAREST); + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; +# endif + + return 0; } - -char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; - -#endif - -int main() -{ -#if __LDBL_MANT_DIG__ == 113 - // qNaN + any = qNaN - if (test__addtf3(makeQNaN128(), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // NaN + any = NaN - if (test__addtf3(makeNaN128(UINT64_C(0x800030000000)), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // inf + inf = inf - if (test__addtf3(makeInf128(), - makeInf128(), - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - // inf + any = inf - if (test__addtf3(makeInf128(), - 0x1.2335653452436234723489432abcdefp+5L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - // any + any - if (test__addtf3(0x1.23456734245345543849abcdefp+5L, - 0x1.edcba52449872455634654321fp-1L, - UINT64_C(0x40042afc95c8b579), - UINT64_C(0x61e58dd6c51eb77c))) - return 1; - -#if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) || \ - defined(i386) || defined(__x86_64__) || (defined(__loongarch__) && \ - __loongarch_frlen != 0) - // Rounding mode tests on supported architectures - const long double m = 1234.0L, n = 0.01L; - - fesetround(FE_UPWARD); - if (test__addtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d8))) - return 1; - - fesetround(FE_DOWNWARD); - if (test__addtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d7))) - return 1; - - - fesetround(FE_TOWARDZERO); - if (test__addtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d7))) - return 1; - - fesetround(FE_TONEAREST); - if (test__addtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d7))) - return 1; -#endif - -#else - printf("skipped\n"); #endif - return 0; -} diff --git a/compiler-rt/test/builtins/Unit/divtf3_test.c b/compiler-rt/test/builtins/Unit/divtf3_test.c --- a/compiler-rt/test/builtins/Unit/divtf3_test.c +++ b/compiler-rt/test/builtins/Unit/divtf3_test.c @@ -1,193 +1,181 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t // REQUIRES: librt_has_divtf3 - -#include "int_lib.h" +#define QUAD_PRECISION +#include "fp_lib.h" +#include "fp_test_fenv.h" #include -#if __LDBL_MANT_DIG__ == 113 - -#include "fp_test.h" +#if __LDBL_MANT_DIG__ != 113 +int main() { + fprintf(stderr, "Missing f128 support - skipping.\n"); + return 1; +} +#else +_Static_assert(sizeof(long double) == 16, ""); // Returns: a / b COMPILER_RT_ABI long double __divtf3(long double a, long double b); -int test__divtf3(long double a, long double b, - uint64_t expectedHi, uint64_t expectedLo) -{ - long double x = __divtf3(a, b); - int ret = compareResultLD(x, expectedHi, expectedLo); - - if (ret){ - printf("error in test__divtf3(%.20Le, %.20Le) = %.20Le, " - "expected %.20Le\n", a, b, x, - fromRep128(expectedHi, expectedLo)); - } - return ret; +int _test__divtf3(int line, long double a, long double b, int expectedExc, + uint64_t expectedHi, uint64_t expectedLo) { + feclearexcept(FE_ALL_EXCEPT); + long double x = __divtf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); + int ret = compareResultLD(x, expectedHi, expectedLo); + + if (ret) { + fprintf(stderr, "%s:%d: error in %s(" F128_FMT ", " F128_FMT ") ", __FILE__, + line, __func__, F128_ARG(a), F128_ARG(b)); + printMismatchLD(x, expectedHi, expectedLo); + } + if (!checkFPException(__FILE__, line, actualExc, expectedExc)) + ret = 1; + return ret; +} +# define test__divtf3(...) _test__divtf3(__LINE__, __VA_ARGS__) + +int main() { + // Returned NaNs are assumed to be qNaN by default + + // qNaN / any = qNaN + if (test__divtf3(makeQNaN128(), 0x1.23456789abcdefp+5L, 0, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // sNaN / any = qNaN, FE_INVALID + if (test__divtf3(makeNaN128(UINT64_C(0x30000000)), 0x1.23456789abcdefp+5L, + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // any / qNaN = qNaN + if (test__divtf3(0x1.23456789abcdefp+5L, makeQNaN128(), 0, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // any / sNaN = NaN, FE_INVALID + if (test__divtf3(0x1.23456789abcdefp+5L, makeNaN128(UINT64_C(0x30000000)), + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // +Inf / positive = +Inf + if (test__divtf3(makeInf128(), 3.L, 0, UINT64_C(0x7fff000000000000), + UINT64_C(0x0))) + return 1; + // +Inf / negative = -Inf + if (test__divtf3(makeInf128(), -3.L, 0, UINT64_C(0xffff000000000000), + UINT64_C(0x0))) + return 1; + // -Inf / positive = -Inf + if (test__divtf3(makeNegativeInf128(), 3.L, 0, UINT64_C(0xffff000000000000), + UINT64_C(0x0))) + return 1; + // -Inf / negative = +Inf + if (test__divtf3(makeNegativeInf128(), -3.L, 0, UINT64_C(0x7fff000000000000), + UINT64_C(0x0))) + return 1; + + // Inf / Inf = qNaN, FE_INVALID + if (test__divtf3(makeInf128(), makeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__divtf3(makeInf128(), makeNegativeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__divtf3(makeNegativeInf128(), makeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__divtf3(makeNegativeInf128(), makeNegativeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // +-0.0 / +-0.0 = qNaN, FE_INVALID + if (test__divtf3(+TF_C(0x0.0p+0), +TF_C(0x0.0p+0), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__divtf3(+TF_C(0x0.0p+0), -TF_C(0x0.0p+0), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__divtf3(-TF_C(0x0.0p+0), +TF_C(0x0.0p+0), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__divtf3(-TF_C(0x0.0p+0), -TF_C(0x0.0p+0), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // +0.0 / +Inf = +0.0 + if (test__divtf3(+0x0.0p+0L, makeInf128(), 0, UINT64_C(0x0), UINT64_C(0x0))) + return 1; + // +Inf / +0.0 = +Inf + if (test__divtf3(makeInf128(), +0x0.0p+0L, 0, UINT64_C(0x7fff000000000000), + UINT64_C(0x0))) + return 1; + + // positive / +0.0 = +Inf, FE_DIVBYZERO + if (test__divtf3(+1.0L, +0x0.0p+0L, FE_DIVBYZERO, + UINT64_C(0x7fff000000000000), UINT64_C(0x0))) + return 1; + // positive / -0.0 = -Inf, FE_DIVBYZERO + if (test__divtf3(+1.0L, -0x0.0p+0L, FE_DIVBYZERO, + UINT64_C(0xffff000000000000), UINT64_C(0x0))) + return 1; + // negative / +0.0 = -Inf + if (test__divtf3(-1.0L, +0x0.0p+0L, FE_DIVBYZERO, + UINT64_C(0xffff000000000000), UINT64_C(0x0))) + return 1; + // negative / -0.0 = +Inf + if (test__divtf3(-1.0L, -0x0.0p+0L, FE_DIVBYZERO, + UINT64_C(0x7fff000000000000), UINT64_C(0x0))) + return 1; + + // 1/3 + if (test__divtf3(1.L, 3.L, 0, UINT64_C(0x3ffd555555555555), + UINT64_C(0x5555555555555555))) + return 1; + // smallest normal result + if (test__divtf3(0x1.0p-16381L, 2.L, 0, UINT64_C(0x0001000000000000), + UINT64_C(0x0))) + return 1; + + // divisor is exactly 1.0 + if (test__divtf3(0x1.0p+0L, 0x1.0p+0L, 0, UINT64_C(0x3fff000000000000), + UINT64_C(0x0))) + return 1; + // divisor is truncated to exactly 1.0 in UQ1.63 + if (test__divtf3(0x1.0p+0L, 0x1.0000000000000001p+0L, 0, + UINT64_C(0x3ffeffffffffffff), UINT64_C(0xfffe000000000000))) + return 1; + + // smallest normal value divided by 2.0 + if (test__divtf3(0x1.0p-16382L, 2.L, 0, UINT64_C(0x0000800000000000), + UINT64_C(0x0))) + return 1; + // smallest subnormal result + if (test__divtf3(0x1.0p-16382L, 0x1p+112L, 0, UINT64_C(0x0), UINT64_C(0x1))) + return 1; + + // any / any + if (test__divtf3(0x1.a23b45362464523375893ab4cdefp+5L, + TF_C(0x1.eedcbaba3a94546558237654321fp-1), 0, + UINT64_C(0x4004b0b72924d407), UINT64_C(0x0717e84356c6eba2))) + return 1; + if (test__divtf3(TF_C(0x1.a2b34c56d745382f9abf2c3dfeffp-50), + TF_C(0x1.ed2c3ba15935332532287654321fp-9), 0, + UINT64_C(0x3fd5b2af3f828c9b), UINT64_C(0x40e51f64cde8b1f2))) + return 1; + if (test__divtf3(TF_C(0x1.2345f6aaaa786555f42432abcdefp+456), + TF_C(0x1.edacbba9874f765463544dd3621fp+6400), 0, + UINT64_C(0x28c62e15dc464466), UINT64_C(0xb5a07586348557ac))) + return 1; + if (test__divtf3(TF_C(0x1.2d3456f789ba6322bc665544edefp-234), + TF_C(0x1.eddcdba39f3c8b7a36564354321fp-4455), 0, + UINT64_C(0x507b38442b539266), UINT64_C(0x22ce0f1d024e1252))) + return 1; + if (test__divtf3(TF_C(0x1.2345f6b77b7a8953365433abcdefp+234), + TF_C(0x1.edcba987d6bb3aa467754354321fp-4055), 0, + UINT64_C(0x50bf2e02f0798d36), UINT64_C(0x5e6fcb6b60044078))) + return 1; + if (test__divtf3(TF_C(6.72420628622418701252535563464350521E-4932), TF_C(2.), + 0, UINT64_C(0x0001000000000000), UINT64_C(0))) + return 1; + + return 0; } - -char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; - -#endif - -int main() -{ -#if __LDBL_MANT_DIG__ == 113 - // Returned NaNs are assumed to be qNaN by default - - // qNaN / any = qNaN - if (test__divtf3(makeQNaN128(), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // NaN / any = NaN - if (test__divtf3(makeNaN128(UINT64_C(0x30000000)), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // any / qNaN = qNaN - if (test__divtf3(0x1.23456789abcdefp+5L, - makeQNaN128(), - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // any / NaN = NaN - if (test__divtf3(0x1.23456789abcdefp+5L, - makeNaN128(UINT64_C(0x30000000)), - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - - // +Inf / positive = +Inf - if (test__divtf3(makeInf128(), 3.L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - // +Inf / negative = -Inf - if (test__divtf3(makeInf128(), -3.L, - UINT64_C(0xffff000000000000), - UINT64_C(0x0))) - return 1; - // -Inf / positive = -Inf - if (test__divtf3(makeNegativeInf128(), 3.L, - UINT64_C(0xffff000000000000), - UINT64_C(0x0))) - return 1; - // -Inf / negative = +Inf - if (test__divtf3(makeNegativeInf128(), -3.L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - - // Inf / Inf = NaN - if (test__divtf3(makeInf128(), makeInf128(), - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // 0.0 / 0.0 = NaN - if (test__divtf3(+0x0.0p+0L, +0x0.0p+0L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // +0.0 / +Inf = +0.0 - if (test__divtf3(+0x0.0p+0L, makeInf128(), - UINT64_C(0x0), - UINT64_C(0x0))) - return 1; - // +Inf / +0.0 = +Inf - if (test__divtf3(makeInf128(), +0x0.0p+0L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - - // positive / +0.0 = +Inf - if (test__divtf3(+1.0L, +0x0.0p+0L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - // positive / -0.0 = -Inf - if (test__divtf3(+1.0L, -0x0.0p+0L, - UINT64_C(0xffff000000000000), - UINT64_C(0x0))) - return 1; - // negative / +0.0 = -Inf - if (test__divtf3(-1.0L, +0x0.0p+0L, - UINT64_C(0xffff000000000000), - UINT64_C(0x0))) - return 1; - // negative / -0.0 = +Inf - if (test__divtf3(-1.0L, -0x0.0p+0L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - - // 1/3 - if (test__divtf3(1.L, 3.L, - UINT64_C(0x3ffd555555555555), - UINT64_C(0x5555555555555555))) - return 1; - // smallest normal result - if (test__divtf3(0x1.0p-16381L, 2.L, - UINT64_C(0x0001000000000000), - UINT64_C(0x0))) - return 1; - - // divisor is exactly 1.0 - if (test__divtf3(0x1.0p+0L, - 0x1.0p+0L, - UINT64_C(0x3fff000000000000), - UINT64_C(0x0))) - return 1; - // divisor is truncated to exactly 1.0 in UQ1.63 - if (test__divtf3(0x1.0p+0L, - 0x1.0000000000000001p+0L, - UINT64_C(0x3ffeffffffffffff), - UINT64_C(0xfffe000000000000))) - return 1; - - // smallest normal value divided by 2.0 - if (test__divtf3(0x1.0p-16382L, 2.L, UINT64_C(0x0000800000000000), UINT64_C(0x0))) - return 1; - // smallest subnormal result - if (test__divtf3(0x1.0p-16382L, 0x1p+112L, UINT64_C(0x0), UINT64_C(0x1))) - return 1; - - // any / any - if (test__divtf3(0x1.a23b45362464523375893ab4cdefp+5L, - 0x1.eedcbaba3a94546558237654321fp-1L, - UINT64_C(0x4004b0b72924d407), - UINT64_C(0x0717e84356c6eba2))) - return 1; - if (test__divtf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50L, - 0x1.ed2c3ba15935332532287654321fp-9L, - UINT64_C(0x3fd5b2af3f828c9b), - UINT64_C(0x40e51f64cde8b1f2))) - return 15; - if (test__divtf3(0x1.2345f6aaaa786555f42432abcdefp+456L, - 0x1.edacbba9874f765463544dd3621fp+6400L, - UINT64_C(0x28c62e15dc464466), - UINT64_C(0xb5a07586348557ac))) - return 1; - if (test__divtf3(0x1.2d3456f789ba6322bc665544edefp-234L, - 0x1.eddcdba39f3c8b7a36564354321fp-4455L, - UINT64_C(0x507b38442b539266), - UINT64_C(0x22ce0f1d024e1252))) - return 1; - if (test__divtf3(0x1.2345f6b77b7a8953365433abcdefp+234L, - 0x1.edcba987d6bb3aa467754354321fp-4055L, - UINT64_C(0x50bf2e02f0798d36), - UINT64_C(0x5e6fcb6b60044078))) - return 1; - if (test__divtf3(6.72420628622418701252535563464350521E-4932L, - 2.L, - UINT64_C(0x0001000000000000), - UINT64_C(0))) - return 1; - -#else - printf("skipped\n"); #endif - return 0; -} diff --git a/compiler-rt/test/builtins/Unit/fp_test.h b/compiler-rt/test/builtins/Unit/fp_test.h --- a/compiler-rt/test/builtins/Unit/fp_test.h +++ b/compiler-rt/test/builtins/Unit/fp_test.h @@ -1,7 +1,9 @@ -#include +#include #include -#include #include +#include +#include +#include #ifdef COMPILER_RT_HAS_FLOAT16 #define TYPE_FP16 _Float16 @@ -160,6 +162,32 @@ } return 1; } + +# define F128_FMT "%.20Lg (0x%016" PRIx64 "%016" PRIx64 ")" +# define F128_ARG(x) \ + ((long double)(x)), (uint64_t)(toRep128(x) >> 64), (uint64_t)(toRep128(x)) + +static inline void printMismatchLD(long double result, uint64_t expectedHi, + uint64_t expectedLo) { + long double expected = fromRep128(expectedHi, expectedLo); + fprintf(stderr, "expected " F128_FMT " but got " F128_FMT "\n", + F128_ARG(expected), F128_ARG(result)); +} + +static inline long double _assertLDRepresentation(const char *str, + long double value, + uint64_t expectedHi, + uint64_t expectedLo) { + if (compareResultLD(value, expectedHi, expectedLo)) { + fprintf(stderr, "Unexpected representation of %s: ", str); + printMismatchLD(value, expectedHi, expectedLo); + exit(1); + } + return value; +} +# define assertLDRepresentation(value, ...) \ + _assertLDRepresentation(#value, value, __VA_ARGS__) + #endif static inline int compareResultCMP(int result, diff --git a/compiler-rt/test/builtins/Unit/fp_test_fenv.h b/compiler-rt/test/builtins/Unit/fp_test_fenv.h new file mode 100644 --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fp_test_fenv.h @@ -0,0 +1,30 @@ +#include "fp_mode.h" +#include "fp_test.h" +#include +#include +#include + +static inline bool crt_sets_fp_exc_flags(void) { + static int result = -1; + if (result == -1) { + int old_except = fetestexcept(FE_ALL_EXCEPT); + feclearexcept(FE_ALL_EXCEPT); + __fe_raise_invalid(); + result = fetestexcept(FE_INVALID) == FE_INVALID; + if (old_except != 0) + feraiseexcept(old_except); + } + return result; +} + +static inline bool checkFPException(const char *file, int line, int actualExc, + int expectedExc) { + if (crt_sets_fp_exc_flags() && actualExc != expectedExc) { + fprintf(stderr, + "%s:%d: Got unexpected floating-point exception %#x, " + "expected %#x\n", + file, line, actualExc, expectedExc); + return false; + } + return true; +} diff --git a/compiler-rt/test/builtins/Unit/multf3_test.c b/compiler-rt/test/builtins/Unit/multf3_test.c --- a/compiler-rt/test/builtins/Unit/multf3_test.c +++ b/compiler-rt/test/builtins/Unit/multf3_test.c @@ -1,86 +1,113 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t // REQUIRES: librt_has_multf3 +#define QUAD_PRECISION +#include "fp_lib.h" +#include "fp_test_fenv.h" #include -#if __LDBL_MANT_DIG__ == 113 - -#include "int_lib.h" -#include "fp_test.h" +#if __LDBL_MANT_DIG__ != 113 +int main() { + fprintf(stderr, "Missing f128 support - skipping.\n"); + return 1; +} +#else +_Static_assert(sizeof(long double) == 16, ""); // Returns: a * b COMPILER_RT_ABI long double __multf3(long double a, long double b); -int test__multf3(long double a, long double b, - uint64_t expectedHi, uint64_t expectedLo) -{ - long double x = __multf3(a, b); - int ret = compareResultLD(x, expectedHi, expectedLo); - - if (ret){ - printf("error in test__multf3(%.20Lf, %.20Lf) = %.20Lf, " - "expected %.20Lf\n", a, b, x, - fromRep128(expectedHi, expectedLo)); - } - return ret; +int _test__multf3(int line, long double a, long double b, int expectedExc, + uint64_t expectedHi, uint64_t expectedLo) { + feclearexcept(FE_ALL_EXCEPT); + long double x = __multf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); + int ret = compareResultLD(x, expectedHi, expectedLo); + if (ret) { + fprintf(stderr, "%s:%d: error in %s(" F128_FMT ", " F128_FMT ") ", __FILE__, + line, __func__, F128_ARG(a), F128_ARG(b)); + printMismatchLD(x, expectedHi, expectedLo); + } + if (!checkFPException(__FILE__, line, actualExc, expectedExc)) + ret = 1; + return ret; } +# define test__multf3(...) _test__multf3(__LINE__, __VA_ARGS__) -char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; +int main() { + // qNaN * any = qNaN + if (test__multf3(makeQNaN128(), TF_C(0x1.23456789abcdefp+5), 0, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // any * qNaN = qNaN + if (test__multf3(TF_C(0x1.23456789abcdefp+5), makeQNaN128(), 0, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // sNaN * any = qNaN, FE_INVALID + if (test__multf3(makeNaN128(UINT64_C(0x100030000000)), + TF_C(0x1.23456789abcdefp+5), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // any * sNaN = qNaN, FE_INVALID + if (test__multf3(TF_C(0x1.23456789abcdefp+5), + makeNaN128(UINT64_C(0x100030000000)), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // inf * any = inf + if (test__multf3(makeInf128(), TF_C(0x1.23456789abcdefp+5), 0, + UINT64_C(0x7fff000000000000), UINT64_C(0x0))) + return 1; -#endif + // +-inf * +-0 = qNaN, FE_INVALID + if (test__multf3(makeInf128(), 0.0, FE_INVALID, UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + if (test__multf3(makeInf128(), -0.0, FE_INVALID, UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + if (test__multf3(makeNegativeInf128(), 0.0, FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__multf3(makeNegativeInf128(), -0.0, FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // +-0 * +-inf = qNaN, FE_INVALID + if (test__multf3(0.0, makeInf128(), FE_INVALID, UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + if (test__multf3(-0.0, makeInf128(), FE_INVALID, UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + if (test__multf3(0.0, makeNegativeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + if (test__multf3(-0.0, makeNegativeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // any * any + if (test__multf3(TF_C(0x1.2eab345678439abcdefea56782346p+5), + TF_C(0x1.edcb34a235253948765432134674fp-1), 0, + UINT64_C(0x400423e7f9e3c9fc), UINT64_C(0xd906c2c2a85777c4))) + return 1; + if (test__multf3(TF_C(0x1.353e45674d89abacc3a2ebf3ff4ffp-50), + TF_C(0x1.ed8764648369535adf4be3214567fp-9), 0, + UINT64_C(0x3fc52a163c6223fc), UINT64_C(0xc94c4bf0430768b4))) + return 1; + if (test__multf3(TF_C(0x1.234425696abcad34a35eeffefdcbap+456), + TF_C(0x451.ed98d76e5d46e5f24323dff21ffp+600), 0, + UINT64_C(0x44293a91de5e0e94), UINT64_C(0xe8ed17cc2cdf64ac))) + return 1; + if (test__multf3(TF_C(0x1.4356473c82a9fabf2d22ace345defp-234), + TF_C(0x1.eda98765476743ab21da23d45678fp-455), 0, + UINT64_C(0x3d4f37c1a3137cae), UINT64_C(0xfc6807048bc2836a))) + return 1; + // underflow + if (test__multf3(TF_C(0x1.23456734245345p-10000), + TF_C(0x1.edcba524498724p-6497), 0, UINT64_C(0x0), + UINT64_C(0x0))) + return 1; -int main() -{ -#if __LDBL_MANT_DIG__ == 113 - // qNaN * any = qNaN - if (test__multf3(makeQNaN128(), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // NaN * any = NaN - if (test__multf3(makeNaN128(UINT64_C(0x800030000000)), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // inf * any = inf - if (test__multf3(makeInf128(), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - // any * any - if (test__multf3(0x1.2eab345678439abcdefea56782346p+5L, - 0x1.edcb34a235253948765432134674fp-1L, - UINT64_C(0x400423e7f9e3c9fc), - UINT64_C(0xd906c2c2a85777c4))) - return 1; - if (test__multf3(0x1.353e45674d89abacc3a2ebf3ff4ffp-50L, - 0x1.ed8764648369535adf4be3214567fp-9L, - UINT64_C(0x3fc52a163c6223fc), - UINT64_C(0xc94c4bf0430768b4))) - return 1; - if (test__multf3(0x1.234425696abcad34a35eeffefdcbap+456L, - 0x451.ed98d76e5d46e5f24323dff21ffp+600L, - UINT64_C(0x44293a91de5e0e94), - UINT64_C(0xe8ed17cc2cdf64ac))) - return 1; - if (test__multf3(0x1.4356473c82a9fabf2d22ace345defp-234L, - 0x1.eda98765476743ab21da23d45678fp-455L, - UINT64_C(0x3d4f37c1a3137cae), - UINT64_C(0xfc6807048bc2836a))) - return 1; - // underflow - if (test__multf3(0x1.23456734245345p-10000L, - 0x1.edcba524498724p-6497L, - UINT64_C(0x0), - UINT64_C(0x0))) - return 1; - -#else - printf("skipped\n"); + return 0; +} #endif - return 0; -} diff --git a/compiler-rt/test/builtins/Unit/subtf3_test.c b/compiler-rt/test/builtins/Unit/subtf3_test.c --- a/compiler-rt/test/builtins/Unit/subtf3_test.c +++ b/compiler-rt/test/builtins/Unit/subtf3_test.c @@ -1,97 +1,109 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t // REQUIRES: librt_has_subtf3 -#include +#define QUAD_PRECISION +#include "fp_lib.h" +#include "fp_test_fenv.h" #include -#if __LDBL_MANT_DIG__ == 113 - -#include "int_lib.h" -#include "fp_test.h" +#if __LDBL_MANT_DIG__ != 113 +int main() { + fprintf(stderr, "Missing f128 support - skipping.\n"); + return 1; +} +#else +_Static_assert(sizeof(long double) == 16, ""); // Returns: a - b COMPILER_RT_ABI long double __subtf3(long double a, long double b); -int test__subtf3(long double a, long double b, - uint64_t expectedHi, uint64_t expectedLo) -{ - long double x = __subtf3(a, b); - int ret = compareResultLD(x, expectedHi, expectedLo); - - if (ret){ - printf("error in test__subtf3(%.20Lf, %.20Lf) = %.20Lf, " - "expected %.20Lf\n", a, b, x, - fromRep128(expectedHi, expectedLo)); - } - return ret; -} +int _test__subtf3(int line, long double a, long double b, int expectedExc, + uint64_t expectedHi, uint64_t expectedLo) { -char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0}; + feclearexcept(FE_ALL_EXCEPT); + long double x = __subtf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); + int ret = compareResultLD(x, expectedHi, expectedLo); -#endif + if (ret) { + fprintf(stderr, "%s:%d: error in %s(" F128_FMT ", " F128_FMT ") ", __FILE__, + line, __func__, F128_ARG(a), F128_ARG(b)); + printMismatchLD(x, expectedHi, expectedLo); + } -int main() -{ -#if __LDBL_MANT_DIG__ == 113 - // qNaN - any = qNaN - if (test__subtf3(makeQNaN128(), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // NaN - any = NaN - if (test__subtf3(makeNaN128(UINT64_C(0x800030000000)), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // inf - any = inf - if (test__subtf3(makeInf128(), - 0x1.23456789abcdefp+5L, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - // any - any - if (test__subtf3(0x1.234567829a3bcdef5678ade36734p+5L, - 0x1.ee9d7c52354a6936ab8d7654321fp-1L, - UINT64_C(0x40041b8af1915166), - UINT64_C(0xa44a7bca780a166c))) - return 1; - -#if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) || \ - defined(i386) || defined(__x86_64__) || (defined(__loongarch__) && \ - __loongarch_frlen != 0) - // Rounding mode tests on supported architectures - const long double m = 1234.02L, n = 0.01L; - - fesetround(FE_UPWARD); - if (test__subtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d7))) - return 1; - - fesetround(FE_DOWNWARD); - if (test__subtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d6))) - return 1; - - fesetround(FE_TOWARDZERO); - if (test__subtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d6))) - return 1; - - fesetround(FE_TONEAREST); - if (test__subtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d7))) - return 1; -#endif - -#else - printf("skipped\n"); + if (!checkFPException(__FILE__, line, actualExc, expectedExc)) + ret = 1; + return ret; +} -#endif - return 0; +# define test__subtf3(...) _test__subtf3(__LINE__, __VA_ARGS__) + +int main() { + // qNaN - any = qNaN + if (test__subtf3(makeQNaN128(), TF_C(0x1.23456789abcdefp+5), 0, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // NaN - any = NaN + if (test__subtf3(makeNaN128(UINT64_C(0x800030000000)), + TF_C(0x1.23456789abcdefp+5), 0, UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + + // sNaN - any = qNaN, FE_INVALID + if (test__subtf3(makeNaN128(UINT64_C(0x12345)), TF_C(0x1.23456789abcdefp+5), + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // any - sNaN = qNaN, FE_INVALID + if (test__subtf3(TF_C(0x1.23456789abcdefp+5), makeNaN128(UINT64_C(0x12345)), + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // inf - any = inf + if (test__subtf3(makeInf128(), TF_C(0x1.23456789abcdefp+5), 0, + UINT64_C(0x7fff000000000000), UINT64_C(0x0))) + return 1; + // inf - inf = NaN, FE_INVALID + if (test__subtf3(makeInf128(), makeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + // -inf - -inf = NaN, FE_INVALID + if (test__subtf3(makeNegativeInf128(), makeNegativeInf128(), FE_INVALID, + UINT64_C(0x7fff800000000000), UINT64_C(0x0))) + return 1; + + // any - any + if (test__subtf3(TF_C(0x1.234567829a3bcdef5678ade36734p+5), + TF_C(0x1.ee9d7c52354a6936ab8d7654321fp-1), FE_INEXACT, + UINT64_C(0x40041b8af1915166), UINT64_C(0xa44a7bca780a166c))) + return 1; + +# if ((defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP)) || \ + defined(i386) || defined(__x86_64__) + // Rounding mode tests on supported architectures + const long double m = assertLDRepresentation( + 1234.02Q, UINT64_C(0x4009348147ae147a), UINT64_C(0xe147ae147ae147ae)); + const long double n = assertLDRepresentation( + 0.01Q, UINT64_C(0x3ff847ae147ae147), UINT64_C(0xae147ae147ae147b)); + + fesetround(FE_UPWARD); + if (test__subtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; + + fesetround(FE_DOWNWARD); + if (test__subtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d6))) + return 1; + + fesetround(FE_TOWARDZERO); + if (test__subtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d6))) + return 1; + + fesetround(FE_TONEAREST); + if (test__subtf3(m, n, FE_INEXACT, UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; +# endif + return 0; } +#endif