-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[libc++] Add a thread-safe version of std::lgamma in the dylib #153631
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libcxx Author: Louis Dionne (ldionne) ChangesThis causes issues when building with modules, and redeclaring functions provided by another library (here the C library) is bad hygiene. Instead, use <math.h> to access the declaration provided by the system. As a drive-by, this also starts using ::lgamma_r instead of ::lgamma when building on top of LLVM-libc. We didn't do that previously due to a declration conflict, but using the _r version when we can should only make things thread safe. Full diff: https://github.com/llvm/llvm-project/pull/153631.diff 1 Files Affected:
diff --git a/libcxx/include/__random/binomial_distribution.h b/libcxx/include/__random/binomial_distribution.h
index b4b4340827761..ab0da2de38b89 100644
--- a/libcxx/include/__random/binomial_distribution.h
+++ b/libcxx/include/__random/binomial_distribution.h
@@ -14,6 +14,7 @@
#include <__random/uniform_real_distribution.h>
#include <cmath>
#include <iosfwd>
+#include <math.h> // for ::lgamma_r
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -97,17 +98,12 @@ class binomial_distribution {
}
};
-// The LLVM C library provides this with conflicting `noexcept` attributes.
-#if !defined(_LIBCPP_MSVCRT_LIKE) && !defined(__LLVM_LIBC__)
-extern "C" double lgamma_r(double, int*);
-#endif
-
inline _LIBCPP_HIDE_FROM_ABI double __libcpp_lgamma(double __d) {
-#if defined(_LIBCPP_MSVCRT_LIKE) || defined(__LLVM_LIBC__)
- return lgamma(__d);
+#if defined(_LIBCPP_MSVCRT_LIKE)
+ return ::lgamma(__d);
#else
int __sign;
- return lgamma_r(__d, &__sign);
+ return ::lgamma_r(__d, &__sign);
#endif
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is lgamma_r
unconditionally provided? I think it would be really nice if we could get a private implementation from LLVM libc so that we can be thread-safe on every platform.
I do think it is unconditionally provided by llvm-libc. What you're thinking about is some kind of hand-in-hand like thing but just for that function? |
Yeah. We could just define our own |
From the #libcxx channel, someone mentioned that LLVM libc doesn't implement I would prefer some solution to be landed. This redecl is problematic because it may conflict with the exception spec of the decl in math.h. GCC and Clang ignore this discrepancy in system headers but not all compilers do so. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undef _LIBCPP_MUST_UNDEFINE_REENTRANT as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a feature test macro for lgamma_r
? You have CI failures here on apple platforms.
@philnik777 I was going to go down the route of adding We already provide definitions for Do you agree that requesting a Clang builtin seems like the better approach? Then we would simply use the builtin from here unconditionally. |
In the meantime, I'd be OK with taking a temporary patch such as #156547. |
I don't think that's the right approach. Adding a builtin is basically just having |
I don't think we have a single generic implementation in llvm-libc yet, maybe @lntue has something. |
0a9e0e0
to
ddd93ec
Compare
_LIBCPP_BEGIN_NAMESPACE_STD | ||
namespace __math { | ||
|
||
_LIBCPP_EXPORTED_FROM_ABI __lgamma_result __lgamma_thread_safe_impl(double __d) noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The _LIBCPP_EXPORTED_FROM_ABI
shouldn't be required here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't hurt to have it though and we do have a bunch of functions in .cpp
files that specify _LIBCPP_EXPORTED_FROM_ABI
too, which IMO helps spot which functions are exported and which ones are not. In this case it's not super helpful since there's currently only one function in that .cpp
file, but still.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to say I completely disagree. IMO this significantly hurts readability. We should instead just have non-_Uglified names for library-internal functions (which itself helps with readability in general). Spotting exported ones is trivial in that case. Removing the attribute here also ensures that the correct declarations are visible at the definition, which helps avoid declaration mismatches.
This causes issues when building with modules, and redeclaring functions provided by another library (here the C library) is bad hygiene. Instead, use <math.h> to access the declaration provided by the system. As a drive-by, this also starts using ::lgamma_r instead of ::lgamma when building on top of LLVM-libc. We didn't do that previously due to a declration conflict, but using the _r version when we can should only make things thread safe.
a1aa577
to
e13ba84
Compare
inline _LIBCPP_HIDE_FROM_ABI __lgamma_result __lgamma_thread_safe(double __d) _NOEXCEPT { | ||
return __math::__lgamma_thread_safe_impl(__d); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for having another wrapper here?
struct __lgamma_result { | ||
double __result; | ||
int __sign; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're never using the __sign
. Should we remove that part? @lntue do you think this makes any difference in the implementation?
_LIBCPP_BEGIN_NAMESPACE_STD | ||
namespace __math { | ||
|
||
_LIBCPP_EXPORTED_FROM_ABI __lgamma_result __lgamma_thread_safe_impl(double __d) noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to say I completely disagree. IMO this significantly hurts readability. We should instead just have non-_Uglified names for library-internal functions (which itself helps with readability in general). Spotting exported ones is trivial in that case. Removing the attribute here also ensures that the correct declarations are visible at the definition, which helps avoid declaration mismatches.
#include <math.h> // for lgamma_r | ||
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
namespace __math { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want to enshrine the __math
namespace forever in our ABI?
Libc++ currently redeclares ::lgamma_r on platforms that provide it. This causes issues when building with modules, and redeclaring functions provided by another library (here the C library) is bad hygiene.
Instead, introduce our own version of a thread-safe gamma function inside the dylib and fall back on
::lgamma_r
without redeclaring it when we have a back-deployment constraint.