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 @@ -57,3 +59,25 @@ 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; +#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 +} 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 @@ -57,3 +59,25 @@ 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; +#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 +} 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 || (bAbs > infRep && (bRep & quietBit) == 0)) + __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 || (aAbs > infRep && (aRep & quietBit) == 0)) + __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 || (bAbs > infRep && (toRep(b) & quietBit) == 0)) + __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 || (aAbs > infRep && (toRep(a) & quietBit) == 0)) + __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 @@ -284,7 +285,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 @@ -25,5 +25,7 @@ CRT_FE_ROUND_MODE __fe_getround(void); int __fe_raise_inexact(void); +int __fe_raise_invalid(void); +int __fe_raise_divbyzero(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 @@ -20,3 +20,11 @@ int __fe_raise_inexact() { return 0; } + +int __fe_raise_invalid() { + return 0; +} + +int __fe_raise_divbyzero() { + 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 || (bAbs > infRep && (toRep(b) & quietBit) == 0)) + __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 || (aAbs > infRep && (toRep(a) & quietBit) == 0)) + __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 @@ -37,3 +37,15 @@ __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; +} + +int __fe_raise_divbyzero() { + float f = 1.0f, g = 0.0f; + __asm__ __volatile__ ("fdivs %1" : "+t" (f) : "m" (g)); + 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,11 +1,10 @@ // RUN: %clang_builtins %s %librt -Wall -Wextra -Werror=format -o %t && %run %t // REQUIRES: librt_has_addtf3 -#include #include #include "int_lib.h" -#include "fp_test.h" +#include "fp_test_fenv.h" #if !defined(CRT_HAS_F128) int main() { @@ -17,14 +16,21 @@ // Returns: a + b COMPILER_RT_ABI f128 __addtf3(f128 a, f128 b); -int _test__addtf3(int line, f128 a, f128 b, +int _test__addtf3(int line, f128 a, f128 b, int expectedExc, uint64_t expectedHi, uint64_t expectedLo) { + feclearexcept(FE_ALL_EXCEPT); f128 x = __addtf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); int ret = compareResultF128(x, expectedHi, expectedLo); if (ret) { printMismatchF128TwoArg(__FILE__, line, "__addtf3", a, b, x, expectedHi, expectedLo); } + 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 1; + } return ret; } #define test__addtf3(...) _test__addtf3(__LINE__, __VA_ARGS__) @@ -33,33 +39,69 @@ // qNaN + any = qNaN if (test__addtf3(makeQNaN128(), 0x1.23456789abcdefp+5Q, + 0, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; // NaN + any = NaN if (test__addtf3(makeNaN128(UINT64_C(0x800030000000)), 0x1.23456789abcdefp+5Q, + 0, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + + // sNaN + any = qNaN, FE_INVALID + if (test__addtf3(makeNaN128(UINT64_C(0x12345)), + 0x1.23456789abcdefp+5Q, + FE_INVALID, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + + // any + sNaN = qNaN, FE_INVALID + if (test__addtf3(0x1.23456789abcdefp+5Q, + 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+5Q, + 0, UINT64_C(0x7fff000000000000), UINT64_C(0x0))) return 1; - // any + any + // 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+5Q */ fromRep128(UINT64_C(0x4004234567342453), UINT64_C(0x45543849abcdef00)), /* 0x1.edcba52449872455634654321fp-1Q */ fromRep128(UINT64_C(0x3ffeedcba5244987), UINT64_C(0x2455634654321f00)), + 0, UINT64_C(0x40042afc95c8b579), UINT64_C(0x61e58dd6c51eb77c))) return 1; @@ -71,25 +113,25 @@ // Closest approximation of 0.1 for f128: const f128 n = assertF128Representation(0.1Q, UINT64_C(0x3ffb999999999999), UINT64_C(0x999999999999999a)); fesetround(FE_UPWARD); - if (test__addtf3(m, n, + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x4009348666666666), UINT64_C(0x6666666666666667))) return 1; fesetround(FE_DOWNWARD); - if (test__addtf3(m, n, + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x4009348666666666), UINT64_C(0x6666666666666666))) return 1; fesetround(FE_TOWARDZERO); - if (test__addtf3(m, n, + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x4009348666666666), UINT64_C(0x6666666666666666))) return 1; fesetround(FE_TONEAREST); - if (test__addtf3(m, n, + if (test__addtf3(m, n, FE_INEXACT, UINT64_C(0x4009348666666666), UINT64_C(0x6666666666666666))) return 1; 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 @@ -4,7 +4,7 @@ #include "int_lib.h" #include -#include "fp_test.h" +#include "fp_test_fenv.h" #if !defined(CRT_HAS_F128) int main() { fprintf(stderr, "Missing f128 support - skipping.\n"); @@ -15,14 +15,21 @@ // Returns: a / b COMPILER_RT_ABI f128 __divtf3(f128 a, f128 b); -int _test__divtf3(int line, f128 a, f128 b, +int _test__divtf3(int line, f128 a, f128 b, int expectedExc, uint64_t expectedHi, uint64_t expectedLo) { + feclearexcept(FE_ALL_EXCEPT); f128 x = __divtf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); int ret = compareResultF128(x, expectedHi, expectedLo); if (ret) { printMismatchF128TwoArg(__FILE__, line, "__divtf3", a, b, x, expectedHi, expectedLo); } + 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 1; + } return ret; } #define test__divtf3(...) _test__divtf3(__LINE__, __VA_ARGS__) @@ -33,98 +40,126 @@ // qNaN / any = qNaN if (test__divtf3(makeQNaN128(), 0x1.23456789abcdefp+5Q, + 0, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; - // NaN / any = NaN + // sNaN / any = qNaN, FE_INVALID if (test__divtf3(makeNaN128(UINT64_C(0x30000000)), 0x1.23456789abcdefp+5Q, + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; // any / qNaN = qNaN if (test__divtf3(0x1.23456789abcdefp+5Q, makeQNaN128(), + 0, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; - // any / NaN = NaN + // any / sNaN = NaN, FE_INVALID if (test__divtf3(0x1.23456789abcdefp+5Q, makeNaN128(UINT64_C(0x30000000)), + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; // +Inf / positive = +Inf - if (test__divtf3(makeInf128(), 3.Q, + if (test__divtf3(makeInf128(), 3.Q, 0, UINT64_C(0x7fff000000000000), UINT64_C(0x0))) return 1; // +Inf / negative = -Inf - if (test__divtf3(makeInf128(), -3.Q, + if (test__divtf3(makeInf128(), -3.Q, 0, UINT64_C(0xffff000000000000), UINT64_C(0x0))) return 1; // -Inf / positive = -Inf - if (test__divtf3(makeNegativeInf128(), 3.Q, + if (test__divtf3(makeNegativeInf128(), 3.Q, 0, UINT64_C(0xffff000000000000), UINT64_C(0x0))) return 1; // -Inf / negative = +Inf - if (test__divtf3(makeNegativeInf128(), -3.Q, + if (test__divtf3(makeNegativeInf128(), -3.Q, 0, UINT64_C(0x7fff000000000000), UINT64_C(0x0))) return 1; - // Inf / Inf = NaN - if (test__divtf3(makeInf128(), makeInf128(), + // 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 = NaN - if (test__divtf3(+0x0.0p+0Q, +0x0.0p+0Q, + // +-0.0 / +-0.0 = qNaN, FE_INVALID + if (test__divtf3(+0x0.0p+0Q, +0x0.0p+0Q, FE_INVALID, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + if (test__divtf3(+0x0.0p+0Q, -0x0.0p+0Q, FE_INVALID, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + if (test__divtf3(-0x0.0p+0Q, +0x0.0p+0Q, FE_INVALID, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + if (test__divtf3(-0x0.0p+0Q, -0x0.0p+0Q, FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; // +0.0 / +Inf = +0.0 - if (test__divtf3(+0x0.0p+0Q, makeInf128(), + if (test__divtf3(+0x0.0p+0Q, makeInf128(), 0, UINT64_C(0x0), UINT64_C(0x0))) return 1; // +Inf / +0.0 = +Inf - if (test__divtf3(makeInf128(), +0x0.0p+0Q, + if (test__divtf3(makeInf128(), +0x0.0p+0Q, 0, UINT64_C(0x7fff000000000000), UINT64_C(0x0))) return 1; // positive / +0.0 = +Inf - if (test__divtf3(+1.0Q, +0x0.0p+0Q, + if (test__divtf3(+1.0Q, +0x0.0p+0Q, FE_DIVBYZERO, UINT64_C(0x7fff000000000000), UINT64_C(0x0))) return 1; // positive / -0.0 = -Inf - if (test__divtf3(+1.0Q, -0x0.0p+0Q, + if (test__divtf3(+1.0Q, -0x0.0p+0Q, FE_DIVBYZERO, UINT64_C(0xffff000000000000), UINT64_C(0x0))) return 1; // negative / +0.0 = -Inf - if (test__divtf3(-1.0Q, +0x0.0p+0Q, + if (test__divtf3(-1.0Q, +0x0.0p+0Q, FE_DIVBYZERO, UINT64_C(0xffff000000000000), UINT64_C(0x0))) return 1; // negative / -0.0 = +Inf - if (test__divtf3(-1.0Q, -0x0.0p+0Q, + if (test__divtf3(-1.0Q, -0x0.0p+0Q, FE_DIVBYZERO, UINT64_C(0x7fff000000000000), UINT64_C(0x0))) return 1; // 1/3 - if (test__divtf3(1.Q, 3.Q, + if (test__divtf3(1.Q, 3.Q, 0, UINT64_C(0x3ffd555555555555), UINT64_C(0x5555555555555555))) return 1; // smallest normal result - if (test__divtf3(0x1.0p-16381Q, 2.Q, + if (test__divtf3(0x1.0p-16381Q, 2.Q, 0, UINT64_C(0x0001000000000000), UINT64_C(0x0))) return 1; @@ -132,51 +167,59 @@ // divisor is exactly 1.0 if (test__divtf3(0x1.0p+0Q, 0x1.0p+0Q, + 0, UINT64_C(0x3fff000000000000), UINT64_C(0x0))) return 1; // divisor is truncated to exactly 1.0 in UQ1.63 if (test__divtf3(0x1.0p+0Q, 0x1.0000000000000001p+0Q, + 0, UINT64_C(0x3ffeffffffffffff), UINT64_C(0xfffe000000000000))) return 1; // smallest normal value divided by 2.0 - if (test__divtf3(0x1.0p-16382Q, 2.Q, UINT64_C(0x0000800000000000), UINT64_C(0x0))) + if (test__divtf3(0x1.0p-16382Q, 2.Q, 0, UINT64_C(0x0000800000000000), UINT64_C(0x0))) return 1; // smallest subnormal result - if (test__divtf3(0x1.0p-16382Q, 0x1p+112Q, UINT64_C(0x0), UINT64_C(0x1))) + if (test__divtf3(0x1.0p-16382Q, 0x1p+112Q, 0, UINT64_C(0x0), UINT64_C(0x1))) return 1; // any / any if (test__divtf3(0x1.a23b45362464523375893ab4cdefp+5Q, 0x1.eedcbaba3a94546558237654321fp-1Q, + 0, UINT64_C(0x4004b0b72924d407), UINT64_C(0x0717e84356c6eba2))) return 1; if (test__divtf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50Q, 0x1.ed2c3ba15935332532287654321fp-9Q, + 0, UINT64_C(0x3fd5b2af3f828c9b), UINT64_C(0x40e51f64cde8b1f2))) - return 15; + return 1; if (test__divtf3(0x1.2345f6aaaa786555f42432abcdefp+456Q, 0x1.edacbba9874f765463544dd3621fp+6400Q, + 0, UINT64_C(0x28c62e15dc464466), UINT64_C(0xb5a07586348557ac))) return 1; if (test__divtf3(0x1.2d3456f789ba6322bc665544edefp-234Q, 0x1.eddcdba39f3c8b7a36564354321fp-4455Q, + 0, UINT64_C(0x507b38442b539266), UINT64_C(0x22ce0f1d024e1252))) return 1; if (test__divtf3(0x1.2345f6b77b7a8953365433abcdefp+234Q, 0x1.edcba987d6bb3aa467754354321fp-4055Q, + 0, UINT64_C(0x50bf2e02f0798d36), UINT64_C(0x5e6fcb6b60044078))) return 1; if (test__divtf3(6.72420628622418701252535563464350521E-4932Q, 2.Q, + 0, UINT64_C(0x0001000000000000), UINT64_C(0))) return 1; 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,16 @@ +#include "fp_mode.h" +#include "fp_test.h" +#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; +} 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 @@ -4,7 +4,7 @@ #include #include "int_lib.h" -#include "fp_test.h" +#include "fp_test_fenv.h" #if !defined(CRT_HAS_F128) int main() { @@ -16,68 +16,115 @@ // Returns: a * b COMPILER_RT_ABI f128 __multf3(f128 a, f128 b); -int _test__multf3(int line, f128 a, f128 b, - uint64_t expectedHi, uint64_t expectedLo) { +int _test__multf3(int line, f128 a, f128 b, int expectedExc, + uint64_t expectedHi, uint64_t expectedLo) { + feclearexcept(FE_ALL_EXCEPT); f128 x = __multf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); int ret = compareResultF128(x, expectedHi, expectedLo); if (ret) { printMismatchF128TwoArg(__FILE__, line, "__multf3", a, b, x, expectedHi, expectedLo); } + 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 1; + } return ret; } #define test__multf3(...) _test__multf3(__LINE__, __VA_ARGS__) -int main() -{ - // qNaN * any = qNaN - if (test__multf3(makeQNaN128(), - 0x1.23456789abcdefp+5Q, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // NaN * any = NaN - if (test__multf3(makeNaN128(UINT64_C(0x800030000000)), - 0x1.23456789abcdefp+5Q, - UINT64_C(0x7fff800000000000), - UINT64_C(0x0))) - return 1; - // inf * any = inf - if (test__multf3(makeInf128(), - 0x1.23456789abcdefp+5Q, - UINT64_C(0x7fff000000000000), - UINT64_C(0x0))) - return 1; - // any * any - if (test__multf3(0x1.2eab345678439abcdefea56782346p+5Q, - 0x1.edcb34a235253948765432134674fp-1Q, - UINT64_C(0x400423e7f9e3c9fc), - UINT64_C(0xd906c2c2a85777c4))) - return 1; - if (test__multf3(0x1.353e45674d89abacc3a2ebf3ff4ffp-50Q, - 0x1.ed8764648369535adf4be3214567fp-9Q, - UINT64_C(0x3fc52a163c6223fc), - UINT64_C(0xc94c4bf0430768b4))) - return 1; - if (test__multf3(0x1.234425696abcad34a35eeffefdcbap+456Q, - 0x451.ed98d76e5d46e5f24323dff21ffp+600Q, - UINT64_C(0x44293a91de5e0e94), - UINT64_C(0xe8ed17cc2cdf64ac))) - return 1; - if (test__multf3(0x1.4356473c82a9fabf2d22ace345defp-234Q, - 0x1.eda98765476743ab21da23d45678fp-455Q, - UINT64_C(0x3d4f37c1a3137cae), - UINT64_C(0xfc6807048bc2836a))) - return 1; - // underflow - if (test__multf3(0x1.23456734245345p-10000Q, - 0x1.edcba524498724p-6497Q, - UINT64_C(0x0), - UINT64_C(0x0))) - return 1; +int main() { + // qNaN * any = qNaN + if (test__multf3(makeQNaN128(), + 0x1.23456789abcdefp+5Q, + 0, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + // any * qNaN = qNaN + if (test__multf3(0x1.23456789abcdefp+5Q, + makeQNaN128(), + 0, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + // sNaN * any = qNaN, FE_INVALID + if (test__multf3(makeNaN128(UINT64_C(0x100030000000)), + 0x1.23456789abcdefp+5Q, + FE_INVALID, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + // any * sNaN = qNaN, FE_INVALID + if (test__multf3(0x1.23456789abcdefp+5Q, + makeNaN128(UINT64_C(0x100030000000)), + FE_INVALID, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + // inf * any = inf + if (test__multf3(makeInf128(), + 0x1.23456789abcdefp+5Q, + 0, + UINT64_C(0x7fff000000000000), + UINT64_C(0x0))) + return 1; + + // +-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(0x1.2eab345678439abcdefea56782346p+5Q, + 0x1.edcb34a235253948765432134674fp-1Q, + 0, + UINT64_C(0x400423e7f9e3c9fc), + UINT64_C(0xd906c2c2a85777c4))) + return 1; + if (test__multf3(0x1.353e45674d89abacc3a2ebf3ff4ffp-50Q, + 0x1.ed8764648369535adf4be3214567fp-9Q, + 0, + UINT64_C(0x3fc52a163c6223fc), + UINT64_C(0xc94c4bf0430768b4))) + return 1; + if (test__multf3(0x1.234425696abcad34a35eeffefdcbap+456Q, + 0x451.ed98d76e5d46e5f24323dff21ffp+600Q, + 0, + UINT64_C(0x44293a91de5e0e94), + UINT64_C(0xe8ed17cc2cdf64ac))) + return 1; + if (test__multf3(0x1.4356473c82a9fabf2d22ace345defp-234Q, + 0x1.eda98765476743ab21da23d45678fp-455Q, + 0, + UINT64_C(0x3d4f37c1a3137cae), + UINT64_C(0xfc6807048bc2836a))) + return 1; + // underflow + if (test__multf3(0x1.23456734245345p-10000Q, + 0x1.edcba524498724p-6497Q, + 0, + UINT64_C(0x0), + UINT64_C(0x0))) + return 1; - return 0; + return 0; } #endif 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,11 +1,10 @@ // RUN: %clang_builtins %s %librt -o %t && %run %t // REQUIRES: librt_has_subtf3 -#include #include #include "int_lib.h" -#include "fp_test.h" +#include "fp_test_fenv.h" #if !defined(CRT_HAS_F128) int main() { @@ -17,14 +16,21 @@ // Returns: a - b COMPILER_RT_ABI f128 __subtf3(f128 a, f128 b); -int _test__subtf3(int line, f128 a, f128 b, +int _test__subtf3(int line, f128 a, f128 b, int expectedExc, uint64_t expectedHi, uint64_t expectedLo) { + feclearexcept(FE_ALL_EXCEPT); f128 x = __subtf3(a, b); + int actualExc = fetestexcept(FE_ALL_EXCEPT); int ret = compareResultF128(x, expectedHi, expectedLo); if (ret) { printMismatchF128TwoArg(__FILE__, line, "__subtf3", a, b, x, expectedHi, expectedLo); } + 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 1; + } return ret; } @@ -34,24 +40,58 @@ // qNaN - any = qNaN if (test__subtf3(makeQNaN128(), 0x1.23456789abcdefp+5Q, + 0, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; // NaN - any = NaN if (test__subtf3(makeNaN128(UINT64_C(0x800030000000)), 0x1.23456789abcdefp+5Q, + 0, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + + // sNaN - any = qNaN, FE_INVALID + if (test__subtf3(makeNaN128(UINT64_C(0x12345)), + 0x1.23456789abcdefp+5Q, + FE_INVALID, + UINT64_C(0x7fff800000000000), + UINT64_C(0x0))) + return 1; + // any - sNaN = qNaN, FE_INVALID + if (test__subtf3(0x1.23456789abcdefp+5Q, + makeNaN128(UINT64_C(0x12345)), + FE_INVALID, UINT64_C(0x7fff800000000000), UINT64_C(0x0))) return 1; // inf - any = inf if (test__subtf3(makeInf128(), 0x1.23456789abcdefp+5Q, + 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(0x1.234567829a3bcdef5678ade36734p+5Q, 0x1.ee9d7c52354a6936ab8d7654321fp-1Q, + FE_INEXACT, UINT64_C(0x40041b8af1915166), UINT64_C(0xa44a7bca780a166c))) return 1; @@ -59,33 +99,33 @@ #if (defined(__arm__) || defined(__aarch64__)) && defined(__ARM_FP) || \ defined(i386) || defined(__x86_64__) // Rounding mode tests on supported architectures - const f128 m = assertF128Representation(1234.02Q, UINT64_C(0x4009348147ae147a), UINT64_C(0xe147ae147ae147ae)); - const f128 n = assertF128Representation(0.01Q, UINT64_C(0x3ff847ae147ae147), UINT64_C(0xae147ae147ae147b)); + const f128 m = assertF128Representation(1234.02Q, UINT64_C(0x4009348147ae147a), UINT64_C(0xe147ae147ae147ae)); + const f128 n = assertF128Representation(0.01Q, UINT64_C(0x3ff847ae147ae147), UINT64_C(0xae147ae147ae147b)); - fesetround(FE_UPWARD); - if (test__subtf3(m, n, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d7))) - return 1; + 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, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d6))) - 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, - 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, - UINT64_C(0x40093480a3d70a3d), - UINT64_C(0x70a3d70a3d70a3d7))) - return 1; + fesetround(FE_TONEAREST); + if (test__subtf3(m, n, FE_INEXACT, + UINT64_C(0x40093480a3d70a3d), + UINT64_C(0x70a3d70a3d70a3d7))) + return 1; #endif - return 0; + return 0; } #endif