Skip to content

[APFloat] Add exp function for APFloat::IEEESsingle using expf implementation from LLVM libc. #143959

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions libc/src/__support/math/expf.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,22 @@ static constexpr float expf(float x) {
return static_cast<float>(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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the pragma to enable fenv_access?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (rounding_mode == current_rounding_mode)
return expf(x);

fputil::set_round(rounding_mode);
float result = expf(x);
fputil::set_round(current_rounding_mode);
return result;
}

#pragma STDC FENV_ACCESS DEFAULT

} // namespace math

} // namespace LIBC_NAMESPACE_DECL
Expand Down
11 changes: 11 additions & 0 deletions llvm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,17 @@ endif()

set(LLVM_ENABLE_Z3_SOLVER_DEFAULT "${Z3_FOUND}")

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}")
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} )
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/ADT/APFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,10 @@ class APFloat : public APFloatBase {
friend APFloat frexp(const APFloat &X, int &Exp, 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),
Expand Down Expand Up @@ -1657,6 +1661,12 @@ 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::rmNearestTiesToEven);
#endif // LLVM_INTEGRATE_LIBC

inline raw_ostream &operator<<(raw_ostream &OS, const APFloat &V) {
V.print(OS);
return OS;
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Config/llvm-config.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
32 changes: 32 additions & 0 deletions llvm/lib/Support/APFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())) \
Expand Down Expand Up @@ -5601,6 +5606,33 @@ float APFloat::convertToFloat() const {
return Temp.getIEEE().convertToFloat();
}

#ifdef LLVM_INTEGRATE_LIBC
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) {
assert((&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) &&
"Float semantics is not IEEEsingle");
if (&X.getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) {
float result = LIBC_NAMESPACE::shared::expf(
X.convertToFloat(), getFEnvRoundingMode(rounding_mode));
return APFloat(result);
}
llvm_unreachable("Unexpected semantics");
}
#endif // LLVM_INTEGRATE_LIBC

} // namespace llvm

#undef APFLOAT_DISPATCH_ON_SEMANTICS
6 changes: 6 additions & 0 deletions llvm/lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this build locally, and somehow the way this was declared caused a fatal include error trying to build APFloat.cpp, complaining that it couldn't find shared/math.h

target_compile_options(LLVMSupport PRIVATE "-Wno-c99-extensions") # _Complex warnings.
endif()
2 changes: 1 addition & 1 deletion llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
77 changes: 77 additions & 0 deletions llvm/unittests/ADT/APFloatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/Support/FormatVariadic.h"
#include "gtest/gtest.h"
#include <cmath>
#include <limits>
#include <ostream>
#include <string>
#include <tuple>
Expand Down Expand Up @@ -8356,4 +8357,80 @@ TEST(APFloatTest, hasSignBitInMSB) {
EXPECT_FALSE(APFloat::hasSignBitInMSB(APFloat::Float8E8M0FNU()));
}

#ifdef LLVM_INTEGRATE_LIBC
TEST(APFloatTest, expf) {
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());
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());
// 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.000002p0f,
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());
// 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

} // namespace
Loading