[libc][math] Set floating point exceptions for exp*f, sinhf, and coshf.
authorTue Ly <lntue@google.com>
Sun, 19 Feb 2023 02:33:46 +0000 (21:33 -0500)
committerTue Ly <lntue@google.com>
Fri, 24 Feb 2023 17:56:39 +0000 (12:56 -0500)
Set FE_OVERFLOW and FE_UNDERFLOW for expf, exp2f, exp10f, expm1f, sinhf
and coshf.

Reviewed By: sivachandra, renyichen

Differential Revision: https://reviews.llvm.org/D144340

20 files changed:
libc/src/__support/FPUtil/CMakeLists.txt
libc/src/__support/FPUtil/FEnvImpl.h
libc/src/math/generic/acosf.cpp
libc/src/math/generic/asinf.cpp
libc/src/math/generic/cosf.cpp
libc/src/math/generic/coshf.cpp
libc/src/math/generic/exp10f.cpp
libc/src/math/generic/exp2f.cpp
libc/src/math/generic/expf.cpp
libc/src/math/generic/expm1f.cpp
libc/src/math/generic/sincosf.cpp
libc/src/math/generic/sinf.cpp
libc/src/math/generic/sinhf.cpp
libc/src/math/generic/tanf.cpp
libc/test/src/math/coshf_test.cpp
libc/test/src/math/exp10f_test.cpp
libc/test/src/math/exp2f_test.cpp
libc/test/src/math/expf_test.cpp
libc/test/src/math/expm1f_test.cpp
libc/test/src/math/sinhf_test.cpp

index c635276830807d4a00b6ae7f04ccff6cf4350556..6ccb3ba511c37a743caee45182ce7e1be9737327 100644 (file)
@@ -3,10 +3,13 @@ add_header_library(
   HDRS
     FEnvImpl.h
   DEPENDS
+    libc.include.errno
     libc.include.fenv
+    libc.include.math
     libc.src.__support.macros.attributes
     libc.src.__support.macros.properties.architectures
     libc.src.__support.macros.sanitizer
+    libc.src.errno.errno
 )
 
 add_header_library(
index f24e273066c47c17075e751509a63c61140c81f7..a31488d8fc8ce86a400584b15bb3038bab8b1838 100644 (file)
 #include "src/__support/macros/attributes.h" // LIBC_INLINE
 #include "src/__support/macros/properties/architectures.h"
 
+#include <errno.h>
+#include <fenv.h>
+#include <math.h>
+
 #if defined(LIBC_TARGET_ARCH_IS_AARCH64)
 #if defined(__APPLE__)
 #include "aarch64/fenv_darwin_impl.h"
 #elif defined(LIBC_TARGET_ARCH_IS_X86)
 #include "x86_64/FEnvImpl.h"
 #else
-#include <fenv.h>
 
-namespace __llvm_libc {
-namespace fputil {
+namespace __llvm_libc::fputil {
 
 // All dummy functions silently succeed.
 
@@ -44,8 +46,28 @@ LIBC_INLINE int get_env(fenv_t *) { return 0; }
 
 LIBC_INLINE int set_env(const fenv_t *) { return 0; }
 
-} // namespace fputil
-} // namespace __llvm_libc
+} // namespace __llvm_libc::fputil
 #endif
 
+namespace __llvm_libc::fputil {
+
+LIBC_INLINE int set_except_if_required(int excepts) {
+  if (math_errhandling & MATH_ERREXCEPT)
+    return set_except(excepts);
+  return 0;
+}
+
+LIBC_INLINE int raise_except_if_required(int excepts) {
+  if (math_errhandling & MATH_ERREXCEPT)
+    return raise_except(excepts);
+  return 0;
+}
+
+LIBC_INLINE void set_errno_if_required(int err) {
+  if (math_errhandling & MATH_ERRNO)
+    errno = err;
+}
+
+} // namespace __llvm_libc::fputil
+
 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FENVIMPL_H
index 5723dc56a2603f6ed9c62620e58d2bc4d6e752f5..d75e36209a4a757aadfb544dc2d8a4af23361c45 100644 (file)
@@ -76,8 +76,8 @@ LLVM_LIBC_FUNCTION(float, acosf, (float x)) {
   // |x| > 1, return NaNs.
   if (LIBC_UNLIKELY(x_abs > 0x3f80'0000U)) {
     if (x_abs <= 0x7f80'0000U) {
-      errno = EDOM;
-      fputil::set_except(FE_INVALID);
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
     }
     return x +
            FPBits::build_nan(1 << (fputil::MantissaWidth<float>::VALUE - 1));
index 2bfa20842a1908398266c9195801bdf8d9d91251..c24697cb14727ca2ea86de34bc014427321c8f1c 100644 (file)
@@ -105,8 +105,8 @@ LLVM_LIBC_FUNCTION(float, asinf, (float x)) {
   // |x| > 1, return NaNs.
   if (LIBC_UNLIKELY(x_abs > 0x3f80'0000U)) {
     if (x_abs <= 0x7f80'0000U) {
-      errno = EDOM;
-      fputil::set_except(FE_INVALID);
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
     }
     return x +
            FPBits::build_nan(1 << (fputil::MantissaWidth<float>::VALUE - 1));
index b9a67861e6de3b5a83d79cf834039f739e593d70..89b7d63b9e8c17c18aa6fcd0a9fd8e9a4f5ad92b 100644 (file)
@@ -114,8 +114,8 @@ LLVM_LIBC_FUNCTION(float, cosf, (float x)) {
   // x is inf or nan.
   if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
     if (x_abs == 0x7f80'0000U) {
-      errno = EDOM;
-      fputil::set_except(FE_INVALID);
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
     }
     return x +
            FPBits::build_nan(1 << (fputil::MantissaWidth<float>::VALUE - 1));
index c1387bc1f0c2ad9bef8d1777b17eb4708aaddc09..1ce1bc300d46bbbb33ae7678d93a7f397fa9f541 100644 (file)
@@ -36,7 +36,8 @@ LLVM_LIBC_FUNCTION(float, coshf, (float x)) {
     if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO))
       return FPBits(FPBits::MAX_NORMAL).get_val();
 
-    errno = ERANGE;
+    fputil::set_errno_if_required(ERANGE);
+    fputil::raise_except_if_required(FE_OVERFLOW);
 
     return x + FPBits::inf().get_val();
   }
index 4059da5907546a706eff962bba4ecfbc251081ae..06509a97fe032530e211c53c00d04b5baf87e0da 100644 (file)
@@ -40,7 +40,8 @@ LLVM_LIBC_FUNCTION(float, exp10f, (float x)) {
         return x;
       if (fputil::get_round() == FE_UPWARD)
         return static_cast<float>(FPBits(FPBits::MIN_SUBNORMAL));
-      errno = ERANGE;
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_UNDERFLOW);
       return 0.0f;
     }
     // x >= log10(2^128) or nan
@@ -51,7 +52,8 @@ LLVM_LIBC_FUNCTION(float, exp10f, (float x)) {
         if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
           return static_cast<float>(FPBits(FPBits::MAX_NORMAL));
 
-        errno = ERANGE;
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
       }
       // x is +inf or nan
       return x + static_cast<float>(FPBits::inf());
index b5d720faac3d3ec1ae450f0ee43b236eecfcf232..116f40fc0a1784334ea7b5413fdd86e4e34cee2b 100644 (file)
@@ -48,7 +48,8 @@ LLVM_LIBC_FUNCTION(float, exp2f, (float x)) {
         if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
           return static_cast<float>(FPBits(FPBits::MAX_NORMAL));
 
-        errno = ERANGE;
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
       }
       // x is +inf or nan
       return x + FPBits::inf().get_val();
@@ -63,8 +64,10 @@ LLVM_LIBC_FUNCTION(float, exp2f, (float x)) {
         return x;
       if (fputil::get_round() == FE_UPWARD)
         return FPBits(FPBits::MIN_SUBNORMAL).get_val();
-      if (x != 0.0f)
-        errno = ERANGE;
+      if (x != 0.0f) {
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_UNDERFLOW);
+      }
       return 0.0f;
     }
   }
index a22449017bfc7efaac22316ed4aedd7416ffab25..cbee8a1ec4640afc4670e8a72e09420c8ace1680 100644 (file)
@@ -50,7 +50,8 @@ LLVM_LIBC_FUNCTION(float, expf, (float x)) {
         return x;
       if (fputil::get_round() == FE_UPWARD)
         return static_cast<float>(FPBits(FPBits::MIN_SUBNORMAL));
-      errno = ERANGE;
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_UNDERFLOW);
       return 0.0f;
     }
     // x >= 89 or nan
@@ -61,7 +62,8 @@ LLVM_LIBC_FUNCTION(float, expf, (float x)) {
         if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
           return static_cast<float>(FPBits(FPBits::MAX_NORMAL));
 
-        errno = ERANGE;
+        fputil::set_errno_if_required(ERANGE);
+        fputil::raise_except_if_required(FE_OVERFLOW);
       }
       // x is +inf or nan
       return x + static_cast<float>(FPBits::inf());
index 67bbb8ef0ae8f649c1b47315848ab2799d9c03bd..33e408cd7861a05193473103a1a804c77efc82ab 100644 (file)
@@ -69,7 +69,8 @@ LLVM_LIBC_FUNCTION(float, expm1f, (float x)) {
           if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
             return static_cast<float>(FPBits(FPBits::MAX_NORMAL));
 
-          errno = ERANGE;
+          fputil::set_errno_if_required(ERANGE);
+          fputil::raise_except_if_required(FE_OVERFLOW);
         }
         return x + static_cast<float>(FPBits::inf());
       }
index 291d4628f60539afa44696074c56891c7bcbbd01..8448945a71d5d6df534db8cc7c090c2ff7dbe5f0 100644 (file)
@@ -144,8 +144,8 @@ LLVM_LIBC_FUNCTION(void, sincosf, (float x, float *sinp, float *cosp)) {
   // x is inf or nan.
   if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
     if (x_abs == 0x7f80'0000U) {
-      errno = EDOM;
-      fputil::set_except(FE_INVALID);
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
     }
     *sinp =
         x + FPBits::build_nan(1 << (fputil::MantissaWidth<float>::VALUE - 1));
index 1cbe4f69e0a7a2a5c9c9af7dc2555b37b38e3ee3..86f47ace2cc8efba2a9bfba4242489748c815698 100644 (file)
@@ -135,8 +135,8 @@ LLVM_LIBC_FUNCTION(float, sinf, (float x)) {
 
   if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
     if (x_abs == 0x7f80'0000U) {
-      errno = EDOM;
-      fputil::set_except(FE_INVALID);
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
     }
     return x +
            FPBits::build_nan(1 << (fputil::MantissaWidth<float>::VALUE - 1));
index 9ba5ac279c0e04dd6a8775bbc6a66146d912e049..cc3811deeb9deba59d73773ceb00ed7cba05085f 100644 (file)
@@ -42,7 +42,8 @@ LLVM_LIBC_FUNCTION(float, sinhf, (float x)) {
         return FPBits(FPBits::MAX_NORMAL).get_val();
     }
 
-    errno = ERANGE;
+    fputil::set_errno_if_required(ERANGE);
+    fputil::raise_except_if_required(FE_OVERFLOW);
 
     return x + FPBits::inf(sign).get_val();
   }
index 0c055d22f24259fd398936b58bade05722c32d1f..e2208203a2e8ab00bfff036f293332316d759f1b 100644 (file)
@@ -111,8 +111,8 @@ LLVM_LIBC_FUNCTION(float, tanf, (float x)) {
     // Inf or NaN
     if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
       if (x_abs == 0x7f80'0000U) {
-        errno = EDOM;
-        fputil::set_except(FE_INVALID);
+        fputil::set_errno_if_required(EDOM);
+        fputil::raise_except_if_required(FE_INVALID);
       }
       return x +
              FPBits::build_nan(1 << (fputil::MantissaWidth<float>::VALUE - 1));
index f91d09fd5d86f7a36e54690cfcd8f774fb8c2d86..c151fbaff4b2864a6f3e01dc5b34be9262bcca12 100644 (file)
@@ -44,13 +44,16 @@ TEST(LlvmLibcCoshfTest, SpecialNumbers) {
 
 TEST(LlvmLibcCoshfTest, Overflow) {
   errno = 0;
-  EXPECT_FP_EQ(inf, __llvm_libc::coshf(float(FPBits(0x7f7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::coshf(float(FPBits(0x7f7fffffU))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::coshf(float(FPBits(0x42cffff8U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::coshf(float(FPBits(0x42cffff8U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::coshf(float(FPBits(0x42d00008U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::coshf(float(FPBits(0x42d00008U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 }
 
index d7100fae294704a8ae0411685df3928717f2f48c..1ea7b80087b3586c925e0fbe965bb2431698c5cb 100644 (file)
@@ -41,13 +41,33 @@ TEST(LlvmLibcExp10fTest, SpecialNumbers) {
 
 TEST(LlvmLibcExp10fTest, Overflow) {
   errno = 0;
-  EXPECT_FP_EQ(inf, __llvm_libc::exp10f(float(FPBits(0x7f7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::exp10f(float(FPBits(0x7f7fffffU))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::exp10f(float(FPBits(0x43000000U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::exp10f(float(FPBits(0x43000000U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::exp10f(float(FPBits(0x43000001U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::exp10f(float(FPBits(0x43000001U))), FE_OVERFLOW);
+  EXPECT_MATH_ERRNO(ERANGE);
+}
+
+TEST(LlvmLibcExp10fTest, Underflow) {
+  errno = 0;
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      0.0f, __llvm_libc::exp10f(float(FPBits(0xff7fffffU))), FE_UNDERFLOW);
+  EXPECT_MATH_ERRNO(ERANGE);
+
+  float x = float(FPBits(0xc2cffff8U));
+  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
+                                 __llvm_libc::exp10f(x), 0.5);
+  EXPECT_MATH_ERRNO(ERANGE);
+
+  x = float(FPBits(0xc2d00008U));
+  EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp10, x,
+                                 __llvm_libc::exp10f(x), 0.5);
   EXPECT_MATH_ERRNO(ERANGE);
 }
 
index c66a39a6b7836ae3f297623c6c5a6eaec7f9aafc..b38c4d43ed53548e734e28d752764cf846884a89 100644 (file)
@@ -42,13 +42,16 @@ TEST(LlvmLibcExp2fTest, SpecialNumbers) {
 
 TEST(LlvmLibcExp2fTest, Overflow) {
   errno = 0;
-  EXPECT_FP_EQ(inf, __llvm_libc::exp2f(float(FPBits(0x7f7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::exp2f(float(FPBits(0x7f7fffffU))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::exp2f(float(FPBits(0x43000000U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::exp2f(float(FPBits(0x43000000U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::exp2f(float(FPBits(0x43000001U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::exp2f(float(FPBits(0x43000001U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 }
 
@@ -79,7 +82,8 @@ TEST(LlvmLibcExp2fTest, TrickyInputs) {
 
 TEST(LlvmLibcExp2fTest, Underflow) {
   errno = 0;
-  EXPECT_FP_EQ(0.0f, __llvm_libc::exp2f(float(FPBits(0xff7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      0.0f, __llvm_libc::exp2f(float(FPBits(0xff7fffffU))), FE_UNDERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
   float x = float(FPBits(0xc3158000U));
index 64ca974b902d0a0510c575e1f4e56cc264a0982c..bcd1dcdb8b6e1172a908affd3fe31b4ee539ecc9 100644 (file)
@@ -41,19 +41,23 @@ TEST(LlvmLibcExpfTest, SpecialNumbers) {
 
 TEST(LlvmLibcExpfTest, Overflow) {
   errno = 0;
-  EXPECT_FP_EQ(inf, __llvm_libc::expf(float(FPBits(0x7f7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::expf(float(FPBits(0x7f7fffffU))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::expf(float(FPBits(0x42cffff8U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::expf(float(FPBits(0x42cffff8U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::expf(float(FPBits(0x42d00008U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::expf(float(FPBits(0x42d00008U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 }
 
 TEST(LlvmLibcExpfTest, Underflow) {
   errno = 0;
-  EXPECT_FP_EQ(0.0f, __llvm_libc::expf(float(FPBits(0xff7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      0.0f, __llvm_libc::expf(float(FPBits(0xff7fffffU))), FE_UNDERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
   float x = float(FPBits(0xc2cffff8U));
index 7dc7456089a5bd66aac462e3c06da4e92f79bb6a..74df79fe7a390a6199a6d5ff35cf258c49cc03eb 100644 (file)
@@ -41,13 +41,16 @@ TEST(LlvmLibcExpm1fTest, SpecialNumbers) {
 
 TEST(LlvmLibcExpm1fTest, Overflow) {
   errno = 0;
-  EXPECT_FP_EQ(inf, __llvm_libc::expm1f(float(FPBits(0x7f7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::expm1f(float(FPBits(0x7f7fffffU))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::expm1f(float(FPBits(0x42cffff8U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::expm1f(float(FPBits(0x42cffff8U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::expm1f(float(FPBits(0x42d00008U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::expm1f(float(FPBits(0x42d00008U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 }
 
index b94c5041d10da0855370df0e97c0a8a6ba6e842c..6bec6426d1d51ac30507643178381e139b6e2686 100644 (file)
@@ -68,13 +68,16 @@ TEST(LlvmLibcSinhfTest, SmallValues) {
 
 TEST(LlvmLibcSinhfTest, Overflow) {
   errno = 0;
-  EXPECT_FP_EQ(inf, __llvm_libc::sinhf(float(FPBits(0x7f7fffffU))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::sinhf(float(FPBits(0x7f7fffffU))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::sinhf(float(FPBits(0x42cffff8U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::sinhf(float(FPBits(0x42cffff8U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 
-  EXPECT_FP_EQ(inf, __llvm_libc::sinhf(float(FPBits(0x42d00008U))));
+  EXPECT_FP_EQ_WITH_EXCEPTION(
+      inf, __llvm_libc::sinhf(float(FPBits(0x42d00008U))), FE_OVERFLOW);
   EXPECT_MATH_ERRNO(ERANGE);
 }