-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[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
}
|
philnik777
left a comment
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
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?
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 wanted to avoid having a function that is sometimes defined inline and sometimes defined in the dylib, since I think it's more difficult to reason about ODR and ABI-wise.
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 that worth carrying around the (IMO) somewhat weird naming forever? I personally don't find it particularly confusing, since _LIBCPP_HIDE_FROM_ABI causes different mangling and thus makes it very clearly distinct in terms of ABI.
| 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?
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 would be great if we could get an answer here @lntue (I don't know is fine as well)
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.
e13ba84 to
fac6c31
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.
Is that worth carrying around the (IMO) somewhat weird naming forever? I personally don't find it particularly confusing, since _LIBCPP_HIDE_FROM_ABI causes different mangling and thus makes it very clearly distinct in terms of ABI.
| #else | ||
| // When deploying to older targets, call `lgamma_r` directly but avoid declaring the actual | ||
| // function since different platforms declare the function slightly differently. | ||
| double __lgamma_r_shim(double, int*) _NOEXCEPT __asm__("lgamma_r"); |
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.
| double __lgamma_r_shim(double, int*) _NOEXCEPT __asm__("lgamma_r"); | |
| double __lgamma_r_shim(double, int*) _NOEXCEPT __asm__("_lgamma_r"); |
I think __asm__ ignores that on Apple platforms an underscore is prepended to all functions, so this has to be added manually.
| 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.
It would be great if we could get an answer here @lntue (I don't know is fine as well)
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_rwithout redeclaring it when we have a back-deployment constraint.