-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[libc++] std::cmp_less and other integer comparison functions could be improved #151332
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
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-libcxx Author: None (kisuhorikka) ChangesFix #65136 Full diff: https://github.com/llvm/llvm-project/pull/151332.diff 1 Files Affected:
diff --git a/libcxx/include/__utility/cmp.h b/libcxx/include/__utility/cmp.h
index 14dc0c154c040..4c29f09628095 100644
--- a/libcxx/include/__utility/cmp.h
+++ b/libcxx/include/__utility/cmp.h
@@ -28,7 +28,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept {
- if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
+ if constexpr (sizeof(_Tp) < sizeof(int) && sizeof(_Up) < sizeof(int)) {
+ __builtin_assume(__t < numeric_limits<int>::max() && __u < numeric_limits<int>::max());
+ return static_cast<int>(__t) == static_cast<int>(__u);
+ } else if constexpr (sizeof(_Tp) < sizeof(long long) && sizeof(_Up) < sizeof(long long)) {
+ __builtin_assume(__t < numeric_limits<long long>::max() && __u < numeric_limits<long long>::max());
+ return static_cast<long long>(__t) == static_cast<long long>(__u);
+ } else if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
return __t == __u;
else if constexpr (is_signed_v<_Tp>)
return __t < 0 ? false : make_unsigned_t<_Tp>(__t) == __u;
@@ -43,7 +49,13 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_not_equal(_Tp __t, _Up __u) noexcept {
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept {
- if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
+ if constexpr (sizeof(_Tp) < sizeof(int) && sizeof(_Up) < sizeof(int)) {
+ __builtin_assume(__t < numeric_limits<int>::max() && __u < numeric_limits<int>::max());
+ return static_cast<int>(__t) < static_cast<int>(__u);
+ } else if constexpr (sizeof(_Tp) < sizeof(long long) && sizeof(_Up) < sizeof(long long)) {
+ __builtin_assume(__t < numeric_limits<long long>::max() && __u < numeric_limits<long long>::max());
+ return static_cast<long long>(__t) < static_cast<long long>(__u);
+ } else if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
return __t < __u;
else if constexpr (is_signed_v<_Tp>)
return __t < 0 ? true : make_unsigned_t<_Tp>(__t) < __u;
|
libcxx seems unhappy with |
Have you read this discussion: #91612 llvm-project/libcxx/include/__assert Line 26 in 098426c
|
cedea5b
to
b2409ee
Compare
Checks for last commit failed due to 'interrupted by user', and I found no obvious errors. The discussion points out that the CI is not done running yet and that job needs to be restarted (which will happen automatically). So I will try to commit again if the CI doesn't restarts automatically after hours. |
libcxx/include/__utility/cmp.h
Outdated
@@ -28,7 +29,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD | |||
|
|||
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> | |||
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept { | |||
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) | |||
if constexpr (sizeof(_Tp) < sizeof(int) && sizeof(_Up) < sizeof(int)) { | |||
_LIBCPP_ASSUME(__t < numeric_limits<int>::max() && __u < numeric_limits<int>::max()); |
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.
Why did you add these in the first place?
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.
Previous bench shows slower results when converting parameters from short
to long long
. The performance is better if parameters are converted to int
. https://quick-bench.com/q/q87HT8ePhR1AqI_Gy3Zj6rbElp8
However, the above results are based on clang 15 (I neglected this before unfortunately), and the difference seems vanished on clang 17. https://quick-bench.com/q/q0Q-bgFsVQyqe8QiDTiPHkawIu4
Though the little difference between speed, the assembly for int
is shorter than long long
, and _LIBCPP_ASSUME
seems no work now. https://godbolt.org/z/a5s3zx64W
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.
On Clang 21 (or 22?), _LIBCPP_ASSUME
doesn't affect the generated same assembly. I'd like to remove _LIBCPP_ASSUME
here.
Issues like that can happen. Just restart the failed job if you have access or rebase to restart the CI. Sometimes somebody can restart the job for you. Specifically I have the same issue with buildkite/libcxx-ci/aarch64 |
680faaa
to
00b0d72
Compare
Hi @philnik777 There are 3 CI tests waiting for status to be reported for 3 days. The CI might be required to start manually for first PR in similar case . Could you please help to start it? Thank you for your help! |
libcxx/include/__utility/cmp.h
Outdated
@@ -28,7 +29,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD | |||
|
|||
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> | |||
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept { | |||
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) | |||
if constexpr (sizeof(_Tp) < sizeof(int) && sizeof(_Up) < sizeof(int)) |
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 doesn't cover comparison between int
and unsigned short
yet.
I wonder whether we can/should do the following (ditto cmp_less
).
template <__signed_or_unsigned_integer _Tp, __signed_integer _Ip>
inline constexpr bool __comparison_can_promote_to =
__signed_integer<_Tp> ? sizeof(_Tp) <= sizeof(_Ip) : sizeof(_Tp) < sizeof(_Ip);
template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up>
_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept {
if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>)
return __t == __u;
else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>)
return static_cast<int>(__t) == static_cast<int>(__u);
else if constexpr (__comparison_can_promote_to<_Tp, long long> && __comparison_can_promote_to<_Up, long long>)
return static_cast<long long>(__t) == static_cast<long long>(__u);
else if constexpr (is_signed_v<_Tp>)
return __t < 0 ? false : make_unsigned_t<_Tp>(__t) == __u;
else
return __u < 0 ? false : __t == make_unsigned_t<_Up>(__u);
}
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 starts to feel like it should be a compiler builtin.
00b0d72
to
03f8228
Compare
c8e0a17
to
534afd4
Compare
…e improved with _LIBCPP_ASSUME
534afd4
to
f39c2b6
Compare
@@ -26,10 +26,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD | |||
|
|||
#if _LIBCPP_STD_VER >= 20 | |||
|
|||
template <typename _Tp, typename _Ip> | |||
inline constexpr bool __comparison_can_promote_to = |
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.
Couldn't we use a concept 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.
The concept
version was submitted several times, but it always failed the check due to timeout. The typename
version, otherwise, passed without a hitch. I guess that when cmp.h
is directly or indirectly referenced by other files, instantiation of the concept may take too much time.
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.
concepts take pretty much exactly the same time as variables. You should investigate further whether there is a problem in the compiler or something. I doubt it though.
Fix #65136