From aeaac932cde03103ba4831dfd54d943098fad716 Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Thu, 12 Jun 2025 19:53:28 +0000 Subject: [PATCH 1/7] [APFloat] Add exp function for APFloat::IEEESsingle using expf implementation from LLVM libc. --- llvm/CMakeLists.txt | 11 +++++++ llvm/include/llvm/ADT/APFloat.h | 5 +++ llvm/include/llvm/Config/llvm-config.h.cmake | 3 ++ llvm/lib/Support/APFloat.cpp | 34 ++++++++++++++++++++ llvm/lib/Support/CMakeLists.txt | 6 ++++ llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp | 2 +- llvm/unittests/ADT/APFloatTest.cpp | 19 +++++++++++ 7 files changed, 79 insertions(+), 1 deletion(-) diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 0849bec26d56a..4128cceaf33fa 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -644,6 +644,17 @@ endif() set(LLVM_ENABLE_Z3_SOLVER_DEFAULT "${Z3_FOUND}") +set(LLVM_INTEGRATE_LIBC "OFF" CACHE STRING "Use LLVM libc codes directly if available.") + +if(LLVM_INTEGRATE_LIBC) + message(STATUS "LLVM_INTEGRATE_LIBC is ${LLVM_INTEGRATE_LIBC}") + include(FindLibcCommonUtils) + if(NOT TARGET llvm-libc-common-utilities) + message(STATUS "LLVM_INTEGRATE_LIBC is set but cannot find LLVM libc at ${libc_path}.") + set(LLVM_INTEGRATE_LIBC OFF) + endif() +endif() + if( LLVM_TARGETS_TO_BUILD STREQUAL "all" ) set( LLVM_TARGETS_TO_BUILD ${LLVM_ALL_TARGETS} ) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 13df838da3dad..6f6dd3c014584 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1522,6 +1522,7 @@ class APFloat : public APFloatBase { friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); } friend APFloat scalbn(APFloat X, int Exp, roundingMode RM); friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM); + friend APFloat exp(const APFloat &X, roundingMode RM); friend IEEEFloat; friend DoubleAPFloat; }; @@ -1657,6 +1658,10 @@ inline APFloat maximumnum(const APFloat &A, const APFloat &B) { return A < B ? B : A; } +/// Implement IEEE 754-2019 exp functions. +LLVM_READONLY +APFloat exp(const APFloat &X, RoundingMode RM); + inline raw_ostream &operator<<(raw_ostream &OS, const APFloat &V) { V.print(OS); return OS; diff --git a/llvm/include/llvm/Config/llvm-config.h.cmake b/llvm/include/llvm/Config/llvm-config.h.cmake index 6d3c37cc8b194..30c4ed6fffc74 100644 --- a/llvm/include/llvm/Config/llvm-config.h.cmake +++ b/llvm/include/llvm/Config/llvm-config.h.cmake @@ -137,4 +137,7 @@ coverage bugs, and to 0 otherwise. */ #cmakedefine01 LLVM_ENABLE_DEBUGLOC_ORIGIN_TRACKING +/* Define if LLVM and clang uses LLVM libc for math computations. */ +#cmakedefine LLVM_INTEGRATE_LIBC + #endif diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 5e0b29ffb2590..150853743540d 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -28,6 +28,11 @@ #include #include +#ifdef LLVM_INTEGRATE_LIBC +// Shared headers from LLVM libc +#include "shared/math.h" +#endif // LLVM_INTEGRATE_LIBC + #define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL) \ do { \ if (usesLayout(getSemantics())) \ @@ -5601,6 +5606,35 @@ float APFloat::convertToFloat() const { return Temp.getIEEE().convertToFloat(); } +#ifdef LLVM_INTEGRATE_LIBC +APFloat exp(const APFloat &X, RoundingMode rounding_mode) { + assert((&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) && + "Float semantics is not IEEEsingle"); + if (&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) { + int current_rounding_mode = fegetround(); + switch (rounding_mode) { + case APFloat::rmNearestTiesToEven: + fesetround(FE_TONEAREST); + break; + case APFloat::rmTowardPositive: + fesetround(FE_UPWARD); + break; + case APFloat::rmTowardNegative: + fesetround(FE_DOWNWARD); + break; + case APFloat::rmTowardZero: + fesetround(FE_TOWARDZERO); + break; + default: + } + float result = LIBC_NAMESPACE::shared::expf(X.convertToFloat()); + fesetround(current_rounding_mode); + return APFloat(result); + } + llvm_unreachable("Unexpected semantics"); +} +#endif // LLVM_INTEGRATE_LIBC + } // namespace llvm #undef APFLOAT_DISPATCH_ON_SEMANTICS diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 45d961e994a1a..aeeba93819227 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -379,3 +379,9 @@ if(LLVM_WITH_Z3) ${Z3_INCLUDE_DIR} ) endif() + +if(LLVM_INTEGRATE_LIBC) + set_property(TARGET LLVMSupport PROPERTY CXX_STANDARD 17) + target_include_directories(LLVMSupport PRIVATE "${LLVM_INCLUDE_DIR}/../../libc") + target_compile_options(LLVMSupport PRIVATE "-Wno-c99-extensions") # _Complex warnings. +endif() diff --git a/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp b/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp index 8767208d20ec9..1e2aa2839fc8f 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp @@ -1540,7 +1540,7 @@ bool AMDGPULibCalls::evaluateScalarMathFunc(const FuncInfo &FInfo, double &Res0, return true; case AMDGPULibFunc::EI_EXP: - Res0 = exp(opr0); + Res0 = std::exp(opr0); return true; case AMDGPULibFunc::EI_EXP2: diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 7a5fd83cd9581..c56cd8898d17a 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -8356,4 +8356,23 @@ TEST(APFloatTest, hasSignBitInMSB) { EXPECT_FALSE(APFloat::hasSignBitInMSB(APFloat::Float8E8M0FNU())); } +#ifdef LLVM_INTEGRATE_LIBC +TEST(APFloatTest, expf) { + EXPECT_EQ( + 1.0f, + llvm::exp(APFloat(0.0f), APFloat::rmNearestTiesToEven).convertToFloat()); + EXPECT_EQ( + 0x1.5bf0a8p1f, + llvm::exp(APFloat(1.0f), APFloat::rmNearestTiesToEven).convertToFloat()); + EXPECT_EQ( + 0x1.5bf0aap1f, + llvm::exp(APFloat(1.0f), APFloat::rmTowardPositive).convertToFloat()); + EXPECT_EQ( + 0x1.5bf0a8p1f, + llvm::exp(APFloat(1.0f), APFloat::rmTowardNegative).convertToFloat()); + EXPECT_EQ(0x1.5bf0a8p1f, + llvm::exp(APFloat(1.0f), APFloat::rmTowardZero).convertToFloat()); +} +#endif // LLVM_INTEGRATE_LIBC + } // namespace From 32f6609a86ba8164407cd6099c7ab60cf7fe8438 Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Fri, 13 Jun 2025 04:09:15 +0000 Subject: [PATCH 2/7] Fix typo and add more tests. --- llvm/CMakeLists.txt | 2 +- llvm/unittests/ADT/APFloatTest.cpp | 53 ++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 4128cceaf33fa..f1a1b39a60652 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -644,7 +644,7 @@ endif() set(LLVM_ENABLE_Z3_SOLVER_DEFAULT "${Z3_FOUND}") -set(LLVM_INTEGRATE_LIBC "OFF" CACHE STRING "Use LLVM libc codes directly if available.") +set(LLVM_INTEGRATE_LIBC "OFF" CACHE STRING "Use LLVM libc code directly if available.") if(LLVM_INTEGRATE_LIBC) message(STATUS "LLVM_INTEGRATE_LIBC is ${LLVM_INTEGRATE_LIBC}") diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index c56cd8898d17a..f7e5a64ba9306 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -16,6 +16,7 @@ #include "llvm/Support/FormatVariadic.h" #include "gtest/gtest.h" #include +#include #include #include #include @@ -8358,9 +8359,24 @@ TEST(APFloatTest, hasSignBitInMSB) { #ifdef LLVM_INTEGRATE_LIBC TEST(APFloatTest, expf) { - EXPECT_EQ( - 1.0f, - llvm::exp(APFloat(0.0f), APFloat::rmNearestTiesToEven).convertToFloat()); + std::array allRoundingModes = { + APFloat::rmNearestTiesToEven, APFloat::rmTowardPositive, + APFloat::rmTowardNegative, APFloat::rmTowardZero}; + for (auto rm : allRoundingModes) { + // exp(+-0) = 1 for all rounding modes. + EXPECT_EQ(1.0f, llvm::exp(APFloat(0.0f), rm).convertToFloat()); + EXPECT_EQ(1.0f, llvm::exp(APFloat(-0.0f), rm).convertToFloat()); + // exp(+Inf) = +Inf for all rounding modes. + EXPECT_EQ(std::numeric_limits::infinity(), + llvm::exp(APFloat::getInf(APFloat::IEEEsingle(), false), rm) + .convertToFloat()); + // exp(-Inf) = 0 for all rounding modes. + EXPECT_EQ(0.0f, llvm::exp(APFloat::getInf(APFloat::IEEEsingle(), true), rm) + .convertToFloat()); + // exp(NaN) = NaN for all rounding modes. + EXPECT_TRUE(llvm::exp(APFloat::getNaN(APFloat::IEEEsingle()), rm).isNaN()); + } + // exp(1) EXPECT_EQ( 0x1.5bf0a8p1f, llvm::exp(APFloat(1.0f), APFloat::rmNearestTiesToEven).convertToFloat()); @@ -8372,6 +8388,37 @@ TEST(APFloatTest, expf) { llvm::exp(APFloat(1.0f), APFloat::rmTowardNegative).convertToFloat()); EXPECT_EQ(0x1.5bf0a8p1f, llvm::exp(APFloat(1.0f), APFloat::rmTowardZero).convertToFloat()); + // exp(float max) + EXPECT_EQ(std::numeric_limits::infinity(), + llvm::exp(APFloat::getLargest(APFloat::IEEEsingle(), false), + APFloat::rmNearestTiesToEven) + .convertToFloat()); + EXPECT_EQ(std::numeric_limits::infinity(), + llvm::exp(APFloat::getLargest(APFloat::IEEEsingle(), false), + APFloat::rmTowardPositive) + .convertToFloat()); + EXPECT_EQ(std::numeric_limits::max(), + llvm::exp(APFloat::getLargest(APFloat::IEEEsingle(), false), + APFloat::rmTowardNegative) + .convertToFloat()); + EXPECT_EQ(std::numeric_limits::max(), + llvm::exp(APFloat::getLargest(APFloat::IEEEsingle(), false), + APFloat::rmTowardZero) + .convertToFloat()); + // exp(min_denormal) + EXPECT_EQ(1.0f, llvm::exp(APFloat::getSmallest(APFloat::IEEEsingle(), false), + APFloat::rmNearestTiesToEven) + .convertToFloat()); + EXPECT_EQ(0x1.000002p0, + llvm::exp(APFloat::getSmallest(APFloat::IEEEsingle(), false), + APFloat::rmTowardPositive) + .convertToFloat()); + EXPECT_EQ(1.0f, llvm::exp(APFloat::getSmallest(APFloat::IEEEsingle(), false), + APFloat::rmTowardNegative) + .convertToFloat()); + EXPECT_EQ(1.0f, llvm::exp(APFloat::getSmallest(APFloat::IEEEsingle(), false), + APFloat::rmTowardZero) + .convertToFloat()); } #endif // LLVM_INTEGRATE_LIBC From d43491bf2f30923dd4b03d2fe8355947709c240a Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Fri, 13 Jun 2025 14:16:20 +0000 Subject: [PATCH 3/7] Add directional rounding version to LLVM libc and use that in APFloat. --- libc/src/__support/math/expf.h | 9 +++++++++ llvm/lib/Support/APFloat.cpp | 37 +++++++++++++++++----------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/libc/src/__support/math/expf.h b/libc/src/__support/math/expf.h index 88c151492a041..d401993a75fc9 100644 --- a/libc/src/__support/math/expf.h +++ b/libc/src/__support/math/expf.h @@ -109,6 +109,15 @@ static constexpr float expf(float x) { return static_cast(exp_hi * exp_mid * exp_lo); } +// Directional rounding version of expf. +LIBC_INLINE static float expf(float x, int rounding_mode) { + int current_rounding_mode = fputil::get_round(); + fputil::set_round(rounding_mode); + float result = expf(x); + fputil::set_round(current_rounding_mode); + return result; +} + } // namespace math } // namespace LIBC_NAMESPACE_DECL diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 150853743540d..574d0c233c425 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -5607,28 +5607,27 @@ float APFloat::convertToFloat() const { } #ifdef LLVM_INTEGRATE_LIBC -APFloat exp(const APFloat &X, RoundingMode rounding_mode) { +static constexpr int getFEnvRoundingMode(llvm::RoundingMode rm) { + switch (rm) { + case APFloat::rmTowardPositive: + return FE_UPWARD; + case APFloat::rmTowardNegative: + return FE_DOWNWARD; + case APFloat::rmTowardZero: + return FE_TOWARDZERO; + default: + // TODO: fix rmNearestTiesToAway for platform without FE_TONEARESTFROMZERO. + return FE_TONEAREST; + }; +} + +APFloat exp(const APFloat &X, + RoundingMode rounding_mode = APFloat::rmNearestTiesToEven) { assert((&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) && "Float semantics is not IEEEsingle"); if (&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) { - int current_rounding_mode = fegetround(); - switch (rounding_mode) { - case APFloat::rmNearestTiesToEven: - fesetround(FE_TONEAREST); - break; - case APFloat::rmTowardPositive: - fesetround(FE_UPWARD); - break; - case APFloat::rmTowardNegative: - fesetround(FE_DOWNWARD); - break; - case APFloat::rmTowardZero: - fesetround(FE_TOWARDZERO); - break; - default: - } - float result = LIBC_NAMESPACE::shared::expf(X.convertToFloat()); - fesetround(current_rounding_mode); + float result = LIBC_NAMESPACE::shared::expf( + X.convertToFloat(), getFEnvRoundingMode(rounding_mode)); return APFloat(result); } llvm_unreachable("Unexpected semantics"); From f134cb785f59348d6a668dedfe6e5ed6fa896c73 Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Fri, 13 Jun 2025 14:21:45 +0000 Subject: [PATCH 4/7] Only change rounding modes if they are different. --- libc/src/__support/math/expf.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libc/src/__support/math/expf.h b/libc/src/__support/math/expf.h index d401993a75fc9..6b0498428bd13 100644 --- a/libc/src/__support/math/expf.h +++ b/libc/src/__support/math/expf.h @@ -112,6 +112,9 @@ static constexpr float expf(float x) { // Directional rounding version of expf. LIBC_INLINE static float expf(float x, int rounding_mode) { int current_rounding_mode = fputil::get_round(); + if (rounding_mode == current_rounding_mode) + return expf(x); + fputil::set_round(rounding_mode); float result = expf(x); fputil::set_round(current_rounding_mode); From d18947d256236ddd4d1dd19a08d133c399bad9ee Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Fri, 13 Jun 2025 15:36:32 +0000 Subject: [PATCH 5/7] Omit declarations when LLVM_INTEGRATE_LIBC is off and fix default rounding mode declaration. --- llvm/include/llvm/ADT/APFloat.h | 9 +++++++-- llvm/lib/Support/APFloat.cpp | 3 +-- llvm/unittests/ADT/APFloatTest.cpp | 13 ++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 6f6dd3c014584..731c972443f42 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1522,9 +1522,12 @@ class APFloat : public APFloatBase { friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); } friend APFloat scalbn(APFloat X, int Exp, roundingMode RM); friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM); - friend APFloat exp(const APFloat &X, roundingMode RM); friend IEEEFloat; friend DoubleAPFloat; + +#ifdef LLVM_INTEGRATE_LIBC + friend APFloat exp(const APFloat &X, roundingMode RM); +#endif // LLVM_INTEGRATE_LIBC) }; static_assert(sizeof(APFloat) == sizeof(detail::IEEEFloat), @@ -1658,9 +1661,11 @@ inline APFloat maximumnum(const APFloat &A, const APFloat &B) { return A < B ? B : A; } +#ifdef LLVM_INTEGRATE_LIBC /// Implement IEEE 754-2019 exp functions. LLVM_READONLY -APFloat exp(const APFloat &X, RoundingMode RM); +APFloat exp(const APFloat &X, RoundingMode RM = APFloat::rmNearestTiesToEven); +#endif // LLVM_INTEGRATE_LIBC inline raw_ostream &operator<<(raw_ostream &OS, const APFloat &V) { V.print(OS); diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 574d0c233c425..d2948d37a5cf0 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -5621,8 +5621,7 @@ static constexpr int getFEnvRoundingMode(llvm::RoundingMode rm) { }; } -APFloat exp(const APFloat &X, - RoundingMode rounding_mode = APFloat::rmNearestTiesToEven) { +APFloat exp(const APFloat &X, RoundingMode rounding_mode) { assert((&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) && "Float semantics is not IEEEsingle"); if (&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) { diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index f7e5a64ba9306..3eef9287b8abf 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -8409,7 +8409,7 @@ TEST(APFloatTest, expf) { EXPECT_EQ(1.0f, llvm::exp(APFloat::getSmallest(APFloat::IEEEsingle(), false), APFloat::rmNearestTiesToEven) .convertToFloat()); - EXPECT_EQ(0x1.000002p0, + EXPECT_EQ(0x1.000002p0f, llvm::exp(APFloat::getSmallest(APFloat::IEEEsingle(), false), APFloat::rmTowardPositive) .convertToFloat()); @@ -8419,6 +8419,17 @@ TEST(APFloatTest, expf) { EXPECT_EQ(1.0f, llvm::exp(APFloat::getSmallest(APFloat::IEEEsingle(), false), APFloat::rmTowardZero) .convertToFloat()); + // Default rounding mode. + // exp(-1) + EXPECT_EQ(0x1.78b564p-2f, llvm::exp(APFloat(-1.0f)).convertToFloat()); + EXPECT_EQ( + 0x1.78b564p-2f, + llvm::exp(APFloat(-1.0f), APFloat::rmTowardPositive).convertToFloat()); + EXPECT_EQ( + 0x1.78b562p-2f, + llvm::exp(APFloat(-1.0f), APFloat::rmTowardNegative).convertToFloat()); + EXPECT_EQ(0x1.78b562p-2f, + llvm::exp(APFloat(-1.0f), APFloat::rmTowardZero).convertToFloat()); } #endif // LLVM_INTEGRATE_LIBC From 79ee1b59948c72f1bc0d5e710339fae01ea122cc Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Fri, 13 Jun 2025 18:23:28 +0000 Subject: [PATCH 6/7] Remove trailing ). --- llvm/include/llvm/ADT/APFloat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 731c972443f42..b2bbd096a802c 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1527,7 +1527,7 @@ class APFloat : public APFloatBase { #ifdef LLVM_INTEGRATE_LIBC friend APFloat exp(const APFloat &X, roundingMode RM); -#endif // LLVM_INTEGRATE_LIBC) +#endif // LLVM_INTEGRATE_LIBC }; static_assert(sizeof(APFloat) == sizeof(detail::IEEEFloat), From b1ea3320e01d2e7f024217bd1138fd31eaf5ead4 Mon Sep 17 00:00:00 2001 From: Tue Ly Date: Sun, 15 Jun 2025 01:35:19 +0000 Subject: [PATCH 7/7] Wrap static rounding expf function with #pragma STDC FENV_ACCESS ON --- libc/src/__support/math/expf.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/src/__support/math/expf.h b/libc/src/__support/math/expf.h index 6b0498428bd13..f3accce54885f 100644 --- a/libc/src/__support/math/expf.h +++ b/libc/src/__support/math/expf.h @@ -109,6 +109,8 @@ static constexpr float expf(float x) { return static_cast(exp_hi * exp_mid * exp_lo); } +#pragma STDC FENV_ACCESS ON + // Directional rounding version of expf. LIBC_INLINE static float expf(float x, int rounding_mode) { int current_rounding_mode = fputil::get_round(); @@ -121,6 +123,8 @@ LIBC_INLINE static float expf(float x, int rounding_mode) { return result; } +#pragma STDC FENV_ACCESS DEFAULT + } // namespace math } // namespace LIBC_NAMESPACE_DECL