[libcxx-commits] [libcxx] [libc++] Implement C++29 Bit Permutations P3104R6 (PR #217820)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Sep 25 06:46:48 PDT 2026
https://github.com/siradam7th updated https://github.com/llvm/llvm-project/pull/217820
>From c281774ac93e4b2e208c8abbc9d740edb5c101b5 Mon Sep 17 00:00:00 2001
From: siradam7th <oss at afterback.gq>
Date: Fri, 21 Aug 2026 06:15:40 +0100
Subject: [PATCH 1/6] [libc++] implement std::bit_reverse
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__bit/bit_reverse.h | 32 ++++++++++++++++++++++++++++++
libcxx/include/bit | 1 +
libcxx/include/module.modulemap.in | 1 +
libcxx/modules/std/bit.inc | 6 ++++++
5 files changed, 41 insertions(+)
create mode 100644 libcxx/include/__bit/bit_reverse.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 99c3bd8b72aa81..83b527eee2fb83 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -235,6 +235,7 @@ set(files
__bit/bit_floor.h
__bit/bit_log2.h
__bit/bit_width.h
+ __bit/bit_reverse.h
__bit/blsr.h
__bit/byteswap.h
__bit/countl.h
diff --git a/libcxx/include/__bit/bit_reverse.h b/libcxx/include/__bit/bit_reverse.h
new file mode 100644
index 00000000000000..eae2903771fa6d
--- /dev/null
+++ b/libcxx/include/__bit/bit_reverse.h
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BIT_REVERSE_H
+#define _LIBCPP___BIT_BIT_REVERSE_H
+
+#include <__config>
+#include <__type_traits/integer_traits.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 29
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <__unsigned_integer _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_reverse(_Tp __t) noexcept {
+ return __builtin_elementwise_bitreverse(__t);
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 29
+
+#endif // _LIBCPP___BIT_BIT_REVERSE_H
diff --git a/libcxx/include/bit b/libcxx/include/bit
index be3dfdc451b3d4..d89a8122a1454d 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -91,6 +91,7 @@ namespace std {
# endif
# if _LIBCPP_STD_VER >= 29
+# include <__bit/bit_reverse.h>
# include <__bit/shift.h>
# endif
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 3e2b446780a437..fba4d3777915e3 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -922,6 +922,7 @@ module std {
module bit_floor { header "__bit/bit_floor.h" }
module bit_log2 { header "__bit/bit_log2.h" }
module bit_width { header "__bit/bit_width.h" }
+ module bit_reverse { header "__bit/bit_reverse.h" }
module blsr { header "__bit/blsr.h" }
module byteswap { header "__bit/byteswap.h" }
module countl { header "__bit/countl.h" }
diff --git a/libcxx/modules/std/bit.inc b/libcxx/modules/std/bit.inc
index dd05b3963db333..055a3b77c08b5b 100644
--- a/libcxx/modules/std/bit.inc
+++ b/libcxx/modules/std/bit.inc
@@ -41,4 +41,10 @@ export namespace std {
// [bit.endian], endian
using std::endian;
+
+#if _LIBCPP_STD_VER >= 29
+ // [bit.permute], permutation
+ using std::bit_reverse;
+#endif
+
} // namespace std
>From 9383327d28a92c131c41c80c8553876641412319 Mon Sep 17 00:00:00 2001
From: siradam7th <oss at afterback.gq>
Date: Fri, 21 Aug 2026 06:17:11 +0100
Subject: [PATCH 2/6] [libc++] implement std::bit_repeat
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__bit/bit_repeat.h | 37 ++++++++++++++++++++++++++++++
libcxx/include/bit | 1 +
libcxx/include/module.modulemap.in | 1 +
libcxx/modules/std/bit.inc | 1 +
5 files changed, 41 insertions(+)
create mode 100644 libcxx/include/__bit/bit_repeat.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 83b527eee2fb83..b6a3b486086a28 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -236,6 +236,7 @@ set(files
__bit/bit_log2.h
__bit/bit_width.h
__bit/bit_reverse.h
+ __bit/bit_repeat.h
__bit/blsr.h
__bit/byteswap.h
__bit/countl.h
diff --git a/libcxx/include/__bit/bit_repeat.h b/libcxx/include/__bit/bit_repeat.h
new file mode 100644
index 00000000000000..3b617329e8f61c
--- /dev/null
+++ b/libcxx/include/__bit/bit_repeat.h
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BIT_REPEAT_H
+#define _LIBCPP___BIT_BIT_REPEAT_H
+
+#include <__config>
+#include <__type_traits/integer_traits.h>
+#include <limits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 29
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <__unsigned_integer _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_repeat(_Tp __t, int __l) {
+ _Tp __res = 0;
+ for (int __i = 0; __i < numeric_limits<_Tp>::digits; ++__i) {
+ __res |= ((__t >> (__i % __l)) & 1) << __i;
+ }
+ return __res;
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 29
+
+#endif // _LIBCPP___BIT_BIT_REPEAT_H
diff --git a/libcxx/include/bit b/libcxx/include/bit
index d89a8122a1454d..966de711a3bfc7 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -91,6 +91,7 @@ namespace std {
# endif
# if _LIBCPP_STD_VER >= 29
+# include <__bit/bit_repeat.h>
# include <__bit/bit_reverse.h>
# include <__bit/shift.h>
# endif
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index fba4d3777915e3..81abbed3c8cf89 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -923,6 +923,7 @@ module std {
module bit_log2 { header "__bit/bit_log2.h" }
module bit_width { header "__bit/bit_width.h" }
module bit_reverse { header "__bit/bit_reverse.h" }
+ module bit_repeat { header "__bit/bit_repeat.h" }
module blsr { header "__bit/blsr.h" }
module byteswap { header "__bit/byteswap.h" }
module countl { header "__bit/countl.h" }
diff --git a/libcxx/modules/std/bit.inc b/libcxx/modules/std/bit.inc
index 055a3b77c08b5b..f296afcf608c2d 100644
--- a/libcxx/modules/std/bit.inc
+++ b/libcxx/modules/std/bit.inc
@@ -44,6 +44,7 @@ export namespace std {
#if _LIBCPP_STD_VER >= 29
// [bit.permute], permutation
+ using std::bit_repeat;
using std::bit_reverse;
#endif
>From 584a5012e2e8254fc60bdf76f4ed96e56c3bb60f Mon Sep 17 00:00:00 2001
From: siradam7th <oss at afterback.gq>
Date: Fri, 21 Aug 2026 06:19:37 +0100
Subject: [PATCH 3/6] [libc++] implement std::bit_compress
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__bit/bit_compress.h | 32 +++++++++++++++++++++++++++++
libcxx/include/bit | 1 +
libcxx/include/module.modulemap.in | 1 +
libcxx/modules/std/bit.inc | 1 +
5 files changed, 36 insertions(+)
create mode 100644 libcxx/include/__bit/bit_compress.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index b6a3b486086a28..0fa815e9cbb190 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -237,6 +237,7 @@ set(files
__bit/bit_width.h
__bit/bit_reverse.h
__bit/bit_repeat.h
+ __bit/bit_compress.h
__bit/blsr.h
__bit/byteswap.h
__bit/countl.h
diff --git a/libcxx/include/__bit/bit_compress.h b/libcxx/include/__bit/bit_compress.h
new file mode 100644
index 00000000000000..4fe2b009563b90
--- /dev/null
+++ b/libcxx/include/__bit/bit_compress.h
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BIT_COMPRESS_H
+#define _LIBCPP___BIT_BIT_COMPRESS_H
+
+#include <__config>
+#include <__type_traits/integer_traits.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 29
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <__unsigned_integer _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_compress(_Tp __t, _Tp __m) noexcept {
+ return __builtin_elementwise_pext(__t, __m);
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 29
+
+#endif // _LIBCPP___BIT_BIT_COMPRESS_H
diff --git a/libcxx/include/bit b/libcxx/include/bit
index 966de711a3bfc7..67d7ae6c2194a2 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -91,6 +91,7 @@ namespace std {
# endif
# if _LIBCPP_STD_VER >= 29
+# include <__bit/bit_compress.h>
# include <__bit/bit_repeat.h>
# include <__bit/bit_reverse.h>
# include <__bit/shift.h>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 81abbed3c8cf89..9b5419c58292b2 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -924,6 +924,7 @@ module std {
module bit_width { header "__bit/bit_width.h" }
module bit_reverse { header "__bit/bit_reverse.h" }
module bit_repeat { header "__bit/bit_repeat.h" }
+ module bit_compress { header "__bit/bit_compress.h" }
module blsr { header "__bit/blsr.h" }
module byteswap { header "__bit/byteswap.h" }
module countl { header "__bit/countl.h" }
diff --git a/libcxx/modules/std/bit.inc b/libcxx/modules/std/bit.inc
index f296afcf608c2d..33799bbd9d4da5 100644
--- a/libcxx/modules/std/bit.inc
+++ b/libcxx/modules/std/bit.inc
@@ -44,6 +44,7 @@ export namespace std {
#if _LIBCPP_STD_VER >= 29
// [bit.permute], permutation
+ using std::bit_compress;
using std::bit_repeat;
using std::bit_reverse;
#endif
>From 43b3834de4c671f50a9b793d652b9f62dadda489 Mon Sep 17 00:00:00 2001
From: siradam7th <oss at afterback.gq>
Date: Fri, 21 Aug 2026 06:20:55 +0100
Subject: [PATCH 4/6] [libc++] implement std::bit_expand
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__bit/bit_expand.h | 32 ++++++++++++++++++++++++++++++
libcxx/include/bit | 1 +
libcxx/include/module.modulemap.in | 1 +
libcxx/modules/std/bit.inc | 1 +
5 files changed, 36 insertions(+)
create mode 100644 libcxx/include/__bit/bit_expand.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 0fa815e9cbb190..a99bf01e717586 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -238,6 +238,7 @@ set(files
__bit/bit_reverse.h
__bit/bit_repeat.h
__bit/bit_compress.h
+ __bit/bit_expand.h
__bit/blsr.h
__bit/byteswap.h
__bit/countl.h
diff --git a/libcxx/include/__bit/bit_expand.h b/libcxx/include/__bit/bit_expand.h
new file mode 100644
index 00000000000000..fc86578439f7b8
--- /dev/null
+++ b/libcxx/include/__bit/bit_expand.h
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BIT_EXPAND_H
+#define _LIBCPP___BIT_BIT_EXPAND_H
+
+#include <__config>
+#include <__type_traits/integer_traits.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 29
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <__unsigned_integer _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_expand(_Tp __t, _Tp __m) noexcept {
+ return __builtin_elementwise_pdep(__t, __m);
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 29
+
+#endif // _LIBCPP___BIT_BIT_EXPAND_H
diff --git a/libcxx/include/bit b/libcxx/include/bit
index 67d7ae6c2194a2..62fb145a665b23 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -92,6 +92,7 @@ namespace std {
# if _LIBCPP_STD_VER >= 29
# include <__bit/bit_compress.h>
+# include <__bit/bit_expand.h>
# include <__bit/bit_repeat.h>
# include <__bit/bit_reverse.h>
# include <__bit/shift.h>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 9b5419c58292b2..1d7a8bf537040f 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -925,6 +925,7 @@ module std {
module bit_reverse { header "__bit/bit_reverse.h" }
module bit_repeat { header "__bit/bit_repeat.h" }
module bit_compress { header "__bit/bit_compress.h" }
+ module bit_expand { header "__bit/bit_expand.h" }
module blsr { header "__bit/blsr.h" }
module byteswap { header "__bit/byteswap.h" }
module countl { header "__bit/countl.h" }
diff --git a/libcxx/modules/std/bit.inc b/libcxx/modules/std/bit.inc
index 33799bbd9d4da5..7ac49f3b8acb8d 100644
--- a/libcxx/modules/std/bit.inc
+++ b/libcxx/modules/std/bit.inc
@@ -45,6 +45,7 @@ export namespace std {
#if _LIBCPP_STD_VER >= 29
// [bit.permute], permutation
using std::bit_compress;
+ using std::bit_expand;
using std::bit_repeat;
using std::bit_reverse;
#endif
>From 5a4852a9448b2bca4e9c35d1f4da413d78ad63e6 Mon Sep 17 00:00:00 2001
From: siradam7th <oss at afterback.gq>
Date: Fri, 21 Aug 2026 06:52:14 +0100
Subject: [PATCH 5/6] [libc++] lint CMakeLists.txt
---
libcxx/include/CMakeLists.txt | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index a99bf01e717586..2db119c32510bf 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -232,13 +232,13 @@ set(files
__atomic/to_gcc_order.h
__bit/bit_cast.h
__bit/bit_ceil.h
+ __bit/bit_compress.h
+ __bit/bit_expand.h
__bit/bit_floor.h
__bit/bit_log2.h
- __bit/bit_width.h
- __bit/bit_reverse.h
__bit/bit_repeat.h
- __bit/bit_compress.h
- __bit/bit_expand.h
+ __bit/bit_reverse.h
+ __bit/bit_width.h
__bit/blsr.h
__bit/byteswap.h
__bit/countl.h
>From 82bf0001d0d999ffc5987681bb306f8087c1eaeb Mon Sep 17 00:00:00 2001
From: siradam7th <oss at afterback.gq>
Date: Fri, 25 Sep 2026 14:45:41 +0100
Subject: [PATCH 6/6] [libc++] add test for std::bit_reverse
---
.../std/numerics/bit/bit_reverse.pass.cpp | 78 +++++++++++++++++++
1 file changed, 78 insertions(+)
create mode 100644 libcxx/test/std/numerics/bit/bit_reverse.pass.cpp
diff --git a/libcxx/test/std/numerics/bit/bit_reverse.pass.cpp b/libcxx/test/std/numerics/bit/bit_reverse.pass.cpp
new file mode 100644
index 00000000000000..697c27efde918b
--- /dev/null
+++ b/libcxx/test/std/numerics/bit/bit_reverse.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++29
+
+#include <bit>
+
+template <typename T>
+concept can_reverse = requires(T x) { std::bit_reverse(x); };
+
+static_assert(!can_reverse<bool>, "type is not allowed to be reversed");
+static_assert(!can_reverse<float>);
+
+static_assert(!can_reverse<signed char>, "signed integers are not allowed to be reversed");
+static_assert(!can_reverse<short>);
+static_assert(!can_reverse<int>);
+static_assert(!can_reverse<long long>);
+static_assert(!can_reverse<int8_t>);
+static_assert(!can_reverse<int16_t>);
+static_assert(!can_reverse<int32_t>);
+static_assert(!can_reverse<int64_t>);
+
+static_assert(!can_reverse<char*>, "pointers are not allowed to be reversed");
+static_assert(!can_reverse<short*>);
+static_assert(!can_reverse<int*>);
+static_assert(!can_reverse<long long*>);
+static_assert(!can_reverse<int8_t*>);
+static_assert(!can_reverse<int16_t*>);
+static_assert(!can_reverse<int32_t*>);
+static_assert(!can_reverse<int64_t*>);
+
+int main(int, char**) {
+ // Test the bit patterns:
+ // - 1111 == 1111
+ // - 1010 == 0101
+ // - 0101 == 1010
+ // - 1000 == 0001
+ // - 0001 == 1000
+
+ // uint8_t
+ static_assert(std::bit_reverse(uint8_t{0x0}) == uint8_t{0x0});
+ static_assert(std::bit_reverse(uint8_t{0xFF}) == uint8_t{0xFF});
+ static_assert(std::bit_reverse(uint8_t{0xAA}) == uint8_t{0x55});
+ static_assert(std::bit_reverse(uint8_t{0x55}) == uint8_t{0xAA});
+ static_assert(std::bit_reverse(uint8_t{0x88}) == uint8_t{0x11});
+ static_assert(std::bit_reverse(uint8_t{0x11}) == uint8_t{0x88});
+
+ // uint16_t
+ static_assert(std::bit_reverse(uint16_t{0x0}) == uint16_t{0x0});
+ static_assert(std::bit_reverse(uint16_t{0xFFFF}) == uint16_t{0xFFFF});
+ static_assert(std::bit_reverse(uint16_t{0xAAAA}) == uint16_t{0x5555});
+ static_assert(std::bit_reverse(uint16_t{0x5555}) == uint16_t{0xAAAA});
+ static_assert(std::bit_reverse(uint16_t{0x8888}) == uint16_t{0x1111});
+ static_assert(std::bit_reverse(uint16_t{0x1111}) == uint16_t{0x8888});
+
+ // uint32_t
+ static_assert(std::bit_reverse(uint32_t{0x0}) == uint32_t{0x0});
+ static_assert(std::bit_reverse(uint32_t{0xFFFFFFFF}) == uint32_t{0xFFFFFFFF});
+ static_assert(std::bit_reverse(uint32_t{0xAAAAAAAA}) == uint32_t{0x55555555});
+ static_assert(std::bit_reverse(uint32_t{0x55555555}) == uint32_t{0xAAAAAAAA});
+ static_assert(std::bit_reverse(uint32_t{0x88888888}) == uint32_t{0x11111111});
+ static_assert(std::bit_reverse(uint32_t{0x11111111}) == uint32_t{0x88888888});
+
+ // uint64_t
+ static_assert(std::bit_reverse(uint64_t{0x0}) == uint64_t{0x0});
+ static_assert(std::bit_reverse(uint64_t{0xFFFFFFFFFFFFFFFF}) == uint64_t{0xFFFFFFFFFFFFFFFF});
+ static_assert(std::bit_reverse(uint64_t{0xAAAAAAAAAAAAAAAA}) == uint64_t{0x5555555555555555});
+ static_assert(std::bit_reverse(uint64_t{0x5555555555555555}) == uint64_t{0xAAAAAAAAAAAAAAAA});
+ static_assert(std::bit_reverse(uint64_t{0x8888888888888888}) == uint64_t{0x1111111111111111});
+ static_assert(std::bit_reverse(uint64_t{0x1111111111111111}) == uint64_t{0x8888888888888888});
+
+ return 0;
+}
More information about the libcxx-commits
mailing list