Repository navigation
[libc++] Implement <bit> parts of P3793R2 Better shifting - #219389
Conversation
|
@llvm/pr-subscribers-libcxx Author: Jan Schultke (eisenwave) ChangesCloses #204401 The implementations of No idea how to run any of these tests locally though because the build seems to be messed up for me: Patch is 33.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/219389.diff 11 Files Affected:
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index cabd30847b2af..ea9157141cef6 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -558,6 +558,8 @@ Status
---------------------------------------------------------- -----------------
**C++29**
----------------------------------------------------------------------------
+ ``__cpp_lib_bitops`` ``202606L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_map_lookup`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_mdspan_copy`` *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index f7a8e5b04f1ea..3210b6a1a6af7 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -55,6 +55,7 @@ Implemented Papers
- P3369R0: constexpr for ``uninitialized_default_construct`` (`Github <https://llvm.org/PR118380>`__)
- P3508R0: Wording for "constexpr for specialized memory algorithms" (`Github <https://llvm.org/PR118379>`__)
- P4206R0: Revert string support in ``std::constant_wrapper`` (`Github <https://llvm.org/PR203338>`__)
+- P3793R2: Better shifting (`Github <https://llvm.org/PR????>`__)
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx29Papers.csv b/libcxx/docs/Status/Cxx29Papers.csv
index 3c48fe89be33d..30f0588b49e60 100644
--- a/libcxx/docs/Status/Cxx29Papers.csv
+++ b/libcxx/docs/Status/Cxx29Papers.csv
@@ -11,7 +11,7 @@
"`P3154R3 <https://wg21.link/P3154R3>`__","Deprecating signed character types in iostreams","2026-06 (Brno)","","","`#204398 <https://github.com/llvm/llvm-project/issues/204398>`__",""
"`P3428R4 <https://wg21.link/P3428R4>`__","Hazard Pointer Batches","2026-06 (Brno)","","","`#204399 <https://github.com/llvm/llvm-project/issues/204399>`__",""
"`P3248R5 <https://wg21.link/P3248R5>`__","Require ``[u]intptr_t``","2026-06 (Brno)","","","`#204400 <https://github.com/llvm/llvm-project/issues/204400>`__",""
-"`P3793R2 <https://wg21.link/P3793R2>`__","Better shifting","2026-06 (Brno)","","","`#204401 <https://github.com/llvm/llvm-project/issues/204401>`__",""
+"`P3793R2 <https://wg21.link/P3793R2>`__","Better shifting","2026-06 (Brno)","|Partial|","24","`#204401 <https://github.com/llvm/llvm-project/issues/204401>`__","No `std::simd` overloads provided yet."
"`P3242R4 <https://wg21.link/P3242R4>`__","Copy and fill for ``mdspan``","2026-06 (Brno)","","","`#204402 <https://github.com/llvm/llvm-project/issues/204402>`__",""
"`P3692R4 <https://wg21.link/P3692R4>`__","How to Avoid OOTA Without Really Trying","2026-06 (Brno)","","","`#204403 <https://github.com/llvm/llvm-project/issues/204403>`__",""
"`P3104R6 <https://wg21.link/P3104R6>`__","Bit permutations","2026-06 (Brno)","","","`#204404 <https://github.com/llvm/llvm-project/issues/204404>`__",""
diff --git a/libcxx/include/__bit/shift.h b/libcxx/include/__bit/shift.h
new file mode 100644
index 0000000000000..75bafe9731125
--- /dev/null
+++ b/libcxx/include/__bit/shift.h
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___BIT_SHIFT_H
+#define _LIBCPP___BIT_SHIFT_H
+
+#include <__config>
+#include <__type_traits/integer_traits.h>
+#include <__type_traits/make_unsigned.h>
+#include <limits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// Writing two full functions for shl and shr makes it easier for the compiler
+// to optimize the code.
+
+#if _LIBCPP_STD_VER >= 29
+
+template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Shift>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp shl(_Tp __t, _Shift __cnt) noexcept {
+ constexpr auto __n = static_cast<_Shift>(numeric_limits<make_unsigned_t<_Tp>>::digits);
+ if constexpr (is_signed_v<_Shift>) {
+ if (__cnt < 0) {
+ if (__cnt <= -__n)
+ return static_cast<_Tp>(__t < 0 ? -1 : 0);
+ return __t >> -__cnt;
+ }
+ }
+ if (__cnt >= __n)
+ return static_cast<_Tp>(0);
+ return __t << __cnt;
+}
+
+template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Shift>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp shr(_Tp __t, _Shift __cnt) noexcept {
+ constexpr auto __n = static_cast<_Shift>(numeric_limits<make_unsigned_t<_Tp>>::digits);
+ if constexpr (is_signed_v<_Shift>) {
+ if (__cnt < 0) {
+ if (__cnt <= -__n)
+ return static_cast<_Tp>(0);
+ return __t << -__cnt;
+ }
+ }
+ if (__cnt >= __n)
+ return static_cast<_Tp>(__t < 0 ? -1 : 0);
+ return __t >> __cnt;
+}
+
+#endif // _LIBCPP_STD_VER >= 29
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___BIT_SHIFT_H
diff --git a/libcxx/include/bit b/libcxx/include/bit
index 40fcda27856bb..be3dfdc451b3d 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -32,6 +32,12 @@ namespace std {
template <class T>
constexpr int bit_width(T x) noexcept; // C++20
+ // [bit.shift], shifting
+ template<class T, class S>
+ constexpr T shl(T x, S s) noexcept; // C++29
+ template<class T, class S>
+ constexpr T shr(T x, S s) noexcept; // C++29
+
// [bit.rotate], rotating
template<class T>
constexpr T rotl(T x, int s) noexcept; // C++20
@@ -84,6 +90,10 @@ namespace std {
# include <__bit/byteswap.h>
# endif
+# if _LIBCPP_STD_VER >= 29
+# include <__bit/shift.h>
+# endif
+
# include <version>
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/version b/libcxx/include/version
index 589ce789ffa7c..421ceb20b270e 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -47,7 +47,8 @@ __cpp_lib_bind_back 202202L <functional>
__cpp_lib_bind_front 202306L <functional>
201907L // C++20
__cpp_lib_bit_cast 201806L <bit>
-__cpp_lib_bitops 201907L <bit>
+__cpp_lib_bitops 202606L <bit>
+ 201907L // C++20
__cpp_lib_bitset 202306L <bitset>
__cpp_lib_bool_constant 201505L <type_traits>
__cpp_lib_bounded_array_traits 201902L <type_traits>
@@ -661,6 +662,8 @@ __cpp_lib_void_t 201411L <type_traits>
#endif
#if _LIBCPP_STD_VER >= 29
+# undef __cpp_lib_bitops
+# define __cpp_lib_bitops 202606L
// # define __cpp_lib_map_lookup 202606L
// # define __cpp_lib_mdspan_copy 202606L
// # define __cpp_lib_pointer_tag_pair 202606L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp
index 39df8f7ed649e..28a7debf546fe 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp
@@ -204,8 +204,8 @@
# ifndef __cpp_lib_bitops
# error "__cpp_lib_bitops should be defined in c++29"
# endif
-# if __cpp_lib_bitops != 201907L
-# error "__cpp_lib_bitops should have the value 201907L in c++29"
+# if __cpp_lib_bitops != 202606L
+# error "__cpp_lib_bitops should have the value 202606L in c++29"
# endif
# ifndef __cpp_lib_byteswap
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 769b79c7924d2..480b8692cfe5e 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -8829,8 +8829,8 @@
# ifndef __cpp_lib_bitops
# error "__cpp_lib_bitops should be defined in c++29"
# endif
-# if __cpp_lib_bitops != 201907L
-# error "__cpp_lib_bitops should have the value 201907L in c++29"
+# if __cpp_lib_bitops != 202606L
+# error "__cpp_lib_bitops should have the value 202606L in c++29"
# endif
# ifndef __cpp_lib_bitset
diff --git a/libcxx/test/std/numerics/bit/bitops.shift/shl.pass.cpp b/libcxx/test/std/numerics/bit/bitops.shift/shl.pass.cpp
new file mode 100644
index 0000000000000..d63a547226ba7
--- /dev/null
+++ b/libcxx/test/std/numerics/bit/bitops.shift/shl.pass.cpp
@@ -0,0 +1,307 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23, c++26
+
+// template <class T, class S>
+// constexpr T shl(T x, S s) noexcept;
+
+// Constraints: Each of T and S is a signed or unsigned integer type.
+
+#include <bit>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#include "test_macros.h"
+
+struct A {};
+enum E1 : unsigned char { rEd };
+enum class E2 : unsigned char { red };
+
+template <class T>
+constexpr bool test()
+{
+ ASSERT_SAME_TYPE(decltype(std::shl(T(), 0)), T);
+ ASSERT_NOEXCEPT(std::shl(T(), 0));
+
+ using U = std::make_unsigned_t<T>;
+ constexpr int width = std::numeric_limits<U>::digits;
+
+ // shl(1, n) for n = 0..7 — basic left shifts
+ assert(std::shl(T(1), 0) == T(1));
+ assert(std::shl(T(1), 1) == T(2));
+ assert(std::shl(T(1), 2) == T(4));
+ assert(std::shl(T(1), 3) == T(8));
+ assert(std::shl(T(1), 4) == T(16));
+ assert(std::shl(T(1), 5) == T(32));
+ assert(std::shl(T(1), 6) == T(64));
+ assert(std::shl(T(1), 7) == T(128));
+
+ // Overlong shifts return 0
+ assert(std::shl(T(1), width) == T(0));
+ assert(std::shl(T(1), width + 1) == T(0));
+ assert(std::shl(T(1), width + 100) == T(0));
+ assert(std::shl(T(1), std::numeric_limits<int>::max()) == T(0));
+
+ // Test all-ones pattern shifted out
+ if constexpr (std::is_signed_v<T>) {
+ assert(std::shl(T(-1), width) == T(0));
+ assert(std::shl(T(-1), width + 5) == T(0));
+ } else {
+ assert(std::shl(T(~T(0)), width) == T(0));
+ assert(std::shl(T(~T(0)), width + 5) == T(0));
+ }
+
+ // Negative shift amounts shift right (bidirectional)
+ U highbit_u = U(1) << (width - 1);
+ T highbit = static_cast<T>(highbit_u);
+ assert(std::shl(highbit, -1) == static_cast<T>(highbit_u >> 1));
+ assert(std::shl(highbit, -2) == static_cast<T>(highbit_u >> 2));
+ assert(std::shl(highbit, -3) == static_cast<T>(highbit_u >> 3));
+ assert(std::shl(highbit, -4) == static_cast<T>(highbit_u >> 4));
+ assert(std::shl(highbit, -5) == static_cast<T>(highbit_u >> 5));
+ assert(std::shl(highbit, -6) == static_cast<T>(highbit_u >> 6));
+ assert(std::shl(highbit, -7) == static_cast<T>(highbit_u >> 7));
+ assert(std::shl(highbit, -(width - 1)) == T(1));
+
+ // Negative overlong shifts: 0 for unsigned, sign-extended for signed
+ if constexpr (std::is_signed_v<T>) {
+ assert(std::shl(T(-1), -width) == T(-1));
+ assert(std::shl(T(-1), -(width + 1)) == T(-1));
+ assert(std::shl(T(-1), std::numeric_limits<int>::min()) == T(-1));
+ assert(std::shl(T(42), -width) == T(0));
+ assert(std::shl(T(42), -(width + 1)) == T(0));
+ } else {
+ assert(std::shl(T(~T(0)), -width) == T(0));
+ assert(std::shl(T(~T(0)), -(width + 1)) == T(0));
+ assert(std::shl(T(1), std::numeric_limits<int>::min()) == T(0));
+ }
+
+#ifndef TEST_HAS_NO_INT128
+ if constexpr (std::is_same_v<T, __uint128_t>) {
+ assert(std::shl(T(1), 0) == T(1));
+ assert(std::shl(T(1), 64) == T(1) << 64);
+ assert(std::shl(T(1), 127) == T(1) << 127);
+ assert(std::shl(T(1), 128) == T(0));
+ assert(std::shl(T(1), 200) == T(0));
+ assert(std::shl(T(1) << 127, -1) == T(1) << 126);
+ assert(std::shl(T(1) << 127, -127) == T(1));
+ assert(std::shl(T(1) << 127, -128) == T(0));
+ assert(std::shl(T(1) << 127, -200) == T(0));
+ }
+#endif
+
+ return true;
+}
+
+int main(int, char**)
+{
+ {
+ // Constraint: T must be a signed or unsigned integer type
+ auto lambda = [](auto x) -> decltype(std::shl(x, 1U)) {};
+ using L = decltype(lambda);
+
+ // Signed integer types are accepted
+ static_assert(std::is_invocable_v<L, signed char>);
+ static_assert(std::is_invocable_v<L, short>);
+ static_assert(std::is_invocable_v<L, int>);
+ static_assert(std::is_invocable_v<L, long>);
+ static_assert(std::is_invocable_v<L, long long>);
+#ifndef TEST_HAS_NO_INT128
+ static_assert(std::is_invocable_v<L, __int128_t>);
+#endif
+
+ static_assert(std::is_invocable_v<L, std::int8_t>);
+ static_assert(std::is_invocable_v<L, std::int16_t>);
+ static_assert(std::is_invocable_v<L, std::int32_t>);
+ static_assert(std::is_invocable_v<L, std::int64_t>);
+ static_assert(std::is_invocable_v<L, std::intmax_t>);
+ static_assert(std::is_invocable_v<L, std::intptr_t>);
+ static_assert(std::is_invocable_v<L, std::ptrdiff_t>);
+
+ // Unsigned integer types are accepted
+ static_assert(std::is_invocable_v<L, unsigned char>);
+ static_assert(std::is_invocable_v<L, unsigned short>);
+ static_assert(std::is_invocable_v<L, unsigned int>);
+ static_assert(std::is_invocable_v<L, unsigned long>);
+ static_assert(std::is_invocable_v<L, unsigned long long>);
+
+ // bool, character types, enums, classes, and pointers are rejected
+ static_assert(!std::is_invocable_v<L, bool>);
+ static_assert(!std::is_invocable_v<L, char>);
+ static_assert(!std::is_invocable_v<L, wchar_t>);
+#ifndef TEST_HAS_NO_CHAR8_T
+ static_assert(!std::is_invocable_v<L, char8_t>);
+#endif
+ static_assert(!std::is_invocable_v<L, char16_t>);
+ static_assert(!std::is_invocable_v<L, char32_t>);
+
+ static_assert(!std::is_invocable_v<L, A>);
+ static_assert(!std::is_invocable_v<L, A*>);
+ static_assert(!std::is_invocable_v<L, E1>);
+ static_assert(!std::is_invocable_v<L, E2>);
+ }
+ {
+ // Constraint: S must be a signed or unsigned integer type
+ auto lambda_s = [](auto s) -> decltype(std::shl(1, s)) {};
+ using LS = decltype(lambda_s);
+
+ static_assert(std::is_invocable_v<LS, signed char>);
+ static_assert(std::is_invocable_v<LS, short>);
+ static_assert(std::is_invocable_v<LS, int>);
+ static_assert(std::is_invocable_v<LS, long>);
+ static_assert(std::is_invocable_v<LS, long long>);
+
+ static_assert(std::is_invocable_v<LS, unsigned char>);
+ static_assert(std::is_invocable_v<LS, unsigned short>);
+ static_assert(std::is_invocable_v<LS, unsigned int>);
+ static_assert(std::is_invocable_v<LS, unsigned long>);
+ static_assert(std::is_invocable_v<LS, unsigned long long>);
+
+ static_assert(!std::is_invocable_v<LS, bool>);
+ static_assert(!std::is_invocable_v<LS, char>);
+ static_assert(!std::is_invocable_v<LS, wchar_t>);
+#ifndef TEST_HAS_NO_CHAR8_T
+ static_assert(!std::is_invocable_v<LS, char8_t>);
+#endif
+ static_assert(!std::is_invocable_v<LS, char16_t>);
+ static_assert(!std::is_invocable_v<LS, char32_t>);
+
+ static_assert(!std::is_invocable_v<LS, A>);
+ static_assert(!std::is_invocable_v<LS, A*>);
+ static_assert(!std::is_invocable_v<LS, E1>);
+ static_assert(!std::is_invocable_v<LS, E2>);
+ }
+
+ static_assert(test<unsigned char>());
+ static_assert(test<unsigned short>());
+ static_assert(test<unsigned int>());
+ static_assert(test<unsigned long>());
+ static_assert(test<unsigned long long>());
+#ifndef TEST_HAS_NO_INT128
+ static_assert(test<__uint128_t>());
+#endif
+
+ static_assert(test<signed char>());
+ static_assert(test<short>());
+ static_assert(test<int>());
+ static_assert(test<long>());
+ static_assert(test<long long>());
+
+ static_assert(test<std::uint8_t>());
+ static_assert(test<std::uint16_t>());
+ static_assert(test<std::uint32_t>());
+ static_assert(test<std::uint64_t>());
+ static_assert(test<std::uintmax_t>());
+ static_assert(test<std::uintptr_t>());
+ static_assert(test<std::size_t>());
+
+ static_assert(test<std::int8_t>());
+ static_assert(test<std::int16_t>());
+ static_assert(test<std::int32_t>());
+ static_assert(test<std::int64_t>());
+ static_assert(test<std::intmax_t>());
+ static_assert(test<std::intptr_t>());
+ static_assert(test<std::ptrdiff_t>());
+
+ test<unsigned char>();
+ test<unsigned short>();
+ test<unsigned int>();
+ test<unsigned long>();
+ test<unsigned long long>();
+#ifndef TEST_HAS_NO_INT128
+ test<__uint128_t>();
+#endif
+
+ test<signed char>();
+ test<short>();
+ test<int>();
+ test<long>();
+ test<long long>();
+
+ test<std::uint8_t>();
+ test<std::uint16_t>();
+ test<std::uint32_t>();
+ test<std::uint64_t>();
+ test<std::uintmax_t>();
+ test<std::uintptr_t>();
+ test<std::size_t>();
+
+ test<std::int8_t>();
+ test<std::int16_t>();
+ test<std::int32_t>();
+ test<std::int64_t>();
+ test<std::intmax_t>();
+ test<std::intptr_t>();
+ test<std::ptrdiff_t>();
+
+#if TEST_HAS_EXTENSION(bit_int)
+ {
+ using T32 = unsigned _BitInt(32);
+ using T64 = unsigned _BitInt(64);
+
+ assert(std::shl(T32(1), 0) == T32(1));
+ assert(std::shl(T32(1), 1) == T32(2));
+ assert(std::shl(T32(1), 4) == T32(16));
+ assert(std::shl(T32(1), 7) == T32(128));
+ assert(std::shl(T32(1), 31) == T32(1) << 31);
+ // Overlong shift returns 0
+ assert(std::shl(T32(1), 32) == T32(0));
+ assert(std::shl(T32(~T32(0)), 32) == T32(0));
+ // Negative shift (bidirectional)
+ assert(std::shl(T32(1) << 31, -1) == T32(1) << 30);
+ assert(std::shl(T32(1) << 31, -31) == T32(1));
+ assert(std::shl(T32(1) << 31, -32) == T32(0));
+
+ assert(std::shl(T64(1), 0) == T64(1));
+ assert(std::shl(T64(1), 4) == T64(16));
+ assert(std::shl(T64(1), 63) == T64(1) << 63);
+ assert(std::shl(T64(1), 64) == T64(0));
+ assert(std::shl(T64(1) << 63, -1) == T64(1) << 62);
+ assert(std::shl(T64(1) << 63, -63) == T64(1));
+ assert(std::shl(T64(1) << 63, -64) == T64(0));
+ }
+# if __BITINT_MAXWIDTH__ >= 128
+ {
+ using T128 = unsigned _BitInt(128);
+ assert(std::shl(T128(1), 0) == T128(1));
+ assert(std::shl(T128(1), 4) == T128(16));
+ assert(std::shl(T128(1), 63) == T128(1) << 63);
+ assert(std::shl(T128(1), 64) == T128(1) << 64);
+ assert(std::shl(T128(1), 127) == T128(1) << 127);
+ // Overlong shifts return 0
+ assert(std::shl(T128(1), 128) == T128(0));
+ assert(std::shl(T128(1), 200) == T128(0));
+ // Negative shift (bidirectional)
+ assert(std::shl(T128(1) << 127, -1) == T128(1) << 126);
+ assert(std::shl(T128(1) << 127, -127) == T128(1));
+ assert(std::shl(T128(1) << 127, -128) == T128(0));
+ }
+# endif
+# if __BITINT_MAXWIDTH__ >= 256
+ {
+ using T256 = unsigned _BitInt(256);
+ assert(std::shl(T256(1), 0) == T256(1));
+ assert(std::shl(T256(1), 4) == T256(16));
+ assert(std::shl(T256(1), 200) == T256(1) << 200);
+ // Overlong shift returns 0
+ assert(std::sh...
[truncated]
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
<bit> parts of P3793R2 Better shifting
philnik777
left a comment
There was a problem hiding this comment.
The commit message shouldn't be closing the issue, since the paper isn't fully implemented.
philnik777
left a comment
There was a problem hiding this comment.
Basically looks good, just a few nits.
|
Ok yeah, it's definitely incorrect now. It was correct before the "fixes". I'm also realizing that the tests only cover signed shift amounts because they always use int, so that needs some more coverage. |
@eisenwave AFAIK These lines would considered inappropriate to include in the commit message. Please delete this from the top comment or move this to a separate message. The commit message should contain info about the implementation only. |
|
@frederick-vs-ja @philnik777 can you merge? |
) Partially implements llvm#204401 That is, the scalar `<bit>` parts are implemented, but the `<simd>` overloads are missing. Notice that only `__cpp_lib_bitops` is set to `202606L`. `__cpp_lib_simd_bitops` is missing. The implementations of `shl` and `shr` are based on the reference implementation in the paper. The test code is partially AI-generated and inspired by the test code for `rotl` or `rotr`, but comes with significant modernizations.
Partially implements #204401
That is, the scalar
<bit>parts are implemented, but the<simd>overloads are missing. Notice that only__cpp_lib_bitopsis set to202606L.__cpp_lib_simd_bitopsis missing.The implementations of
shlandshrare based on the reference implementation in the paper. The test code is partially AI-generated and inspired by the test code forrotlorrotr, but comes with significant modernizations.