Skip to content

[libc++][bit] Improves rotate functions. #98032

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

Merged
merged 1 commit into from
Aug 3, 2024
Merged
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
37 changes: 25 additions & 12 deletions libcxx/include/__bit/rotate.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,37 @@

_LIBCPP_BEGIN_NAMESPACE_STD

// Writing two full functions for rotl and rotr makes it easier for the compiler
// to optimize the code. On x86 this function becomes the ROL instruction and
// the rotr function becomes the ROR instruction.
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __t, int __cnt) _NOEXCEPT {
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotr requires an unsigned integer type");
const unsigned int __dig = numeric_limits<_Tp>::digits;
if ((__cnt % __dig) == 0)
return __t;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __x, int __s) _NOEXCEPT {
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotl requires an unsigned integer type");
const int __N = numeric_limits<_Tp>::digits;
int __r = __s % __N;

if (__r == 0)
return __x;

if (__cnt < 0) {
__cnt *= -1;
return (__t << (__cnt % __dig)) | (__t >> (__dig - (__cnt % __dig))); // rotr with negative __cnt is similar to rotl
}
if (__r > 0)
return (__x << __r) | (__x >> (__N - __r));

return (__t >> (__cnt % __dig)) | (__t << (__dig - (__cnt % __dig)));
return (__x >> -__r) | (__x << (__N + __r));
}

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __t, int __cnt) _NOEXCEPT {
return std::__rotr(__t, -__cnt);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __x, int __s) _NOEXCEPT {
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotr requires an unsigned integer type");
const int __N = numeric_limits<_Tp>::digits;
int __r = __s % __N;

if (__r == 0)
return __x;

if (__r > 0)
return (__x >> __r) | (__x << (__N - __r));

return (__x << -__r) | (__x >> (__N + __r));
}

#if _LIBCPP_STD_VER >= 20
Expand Down
4 changes: 4 additions & 0 deletions libcxx/test/std/numerics/bit/bitops.rot/rotl.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ constexpr bool test()
assert(std::rotl(T(max - 1), 5) == T(max - 32));
assert(std::rotl(T(max - 1), 6) == T(max - 64));
assert(std::rotl(T(max - 1), 7) == T(max - 128));
assert(std::rotl(T(max - 1), std::numeric_limits<int>::max()) ==
std::rotl(T(max - 1), std::numeric_limits<int>::max() % std::numeric_limits<T>::digits));

assert(std::rotl(T(max - 1), -1) == T(max - highbit));
assert(std::rotl(T(max - 1), -2) == T(max - (highbit >> 1)));
Expand All @@ -49,6 +51,8 @@ constexpr bool test()
assert(std::rotl(T(max - 1), -5) == T(max - (highbit >> 4)));
assert(std::rotl(T(max - 1), -6) == T(max - (highbit >> 5)));
assert(std::rotl(T(max - 1), -7) == T(max - (highbit >> 6)));
assert(std::rotl(T(max - 1), std::numeric_limits<int>::min()) ==
std::rotl(T(max - 1), std::numeric_limits<int>::min() % std::numeric_limits<T>::digits));

assert(std::rotl(T(1), 0) == T(1));
assert(std::rotl(T(1), 1) == T(2));
Expand Down
4 changes: 4 additions & 0 deletions libcxx/test/std/numerics/bit/bitops.rot/rotr.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ constexpr bool test()
assert(std::rotr(T(max - 1), 5) == T(max - (highbit >> 4)));
assert(std::rotr(T(max - 1), 6) == T(max - (highbit >> 5)));
assert(std::rotr(T(max - 1), 7) == T(max - (highbit >> 6)));
assert(std::rotr(T(max - 1), std::numeric_limits<int>::max()) ==
std::rotr(T(max - 1), std::numeric_limits<int>::max() % std::numeric_limits<T>::digits));

assert(std::rotr(T(max - 1), -1) == T(max - 2));
assert(std::rotr(T(max - 1), -2) == T(max - 4));
Expand All @@ -49,6 +51,8 @@ constexpr bool test()
assert(std::rotr(T(max - 1), -5) == T(max - 32));
assert(std::rotr(T(max - 1), -6) == T(max - 64));
assert(std::rotr(T(max - 1), -7) == T(max - 128));
assert(std::rotr(T(max - 1), std::numeric_limits<int>::min()) ==
std::rotr(T(max - 1), std::numeric_limits<int>::min() % std::numeric_limits<T>::digits));

assert(std::rotr(T(128), 0) == T(128));
assert(std::rotr(T(128), 1) == T(64));
Expand Down
Loading