[llvm] [APFloat] Add exp function for APFloat::IEEESsingle using expf implementation from LLVM libc. (PR #143959)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 12 21:15:36 PDT 2025
https://github.com/lntue updated https://github.com/llvm/llvm-project/pull/143959
>From ce5e4f90957ed6143d1d46e4dea80e49138a130c Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 12 Jun 2025 19:53:28 +0000
Subject: [PATCH 1/2] [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 cfb67472aa71e..ff2f4ff4ea298 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 dbc882937b4f4..8ec9a30dc85d1 100644
--- a/llvm/include/llvm/Config/llvm-config.h.cmake
+++ b/llvm/include/llvm/Config/llvm-config.h.cmake
@@ -133,4 +133,7 @@
and to 0 otherwise. */
#cmakedefine01 LLVM_ENABLE_DEBUGLOC_COVERAGE_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 <cstring>
#include <limits.h>
+#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<IEEEFloat>(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 4adec802975004fbe0bed0f94ff9307059834f53 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Fri, 13 Jun 2025 04:09:15 +0000
Subject: [PATCH 2/2] 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 ff2f4ff4ea298..fedede482e22f 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 <cmath>
+#include <limits>
#include <ostream>
#include <string>
#include <tuple>
@@ -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<llvm::RoundingMode, 4> 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<float>::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<float>::infinity(),
+ llvm::exp(APFloat::getLargest(APFloat::IEEEsingle(), false),
+ APFloat::rmNearestTiesToEven)
+ .convertToFloat());
+ EXPECT_EQ(std::numeric_limits<float>::infinity(),
+ llvm::exp(APFloat::getLargest(APFloat::IEEEsingle(), false),
+ APFloat::rmTowardPositive)
+ .convertToFloat());
+ EXPECT_EQ(std::numeric_limits<float>::max(),
+ llvm::exp(APFloat::getLargest(APFloat::IEEEsingle(), false),
+ APFloat::rmTowardNegative)
+ .convertToFloat());
+ EXPECT_EQ(std::numeric_limits<float>::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
More information about the llvm-commits
mailing list