[libcxx-commits] [libcxx] ad9ecc4 - [libcxx] Configuration option to lower deque block size (#198348)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jun 16 18:17:32 PDT 2026


Author: Prabhu Rajasekaran
Date: 2026-06-16T18:17:27-07:00
New Revision: ad9ecc4739d136ac6818d6d439751556402b5134

URL: https://github.com/llvm/llvm-project/commit/ad9ecc4739d136ac6818d6d439751556402b5134
DIFF: https://github.com/llvm/llvm-project/commit/ad9ecc4739d136ac6818d6d439751556402b5134.diff

LOG: [libcxx] Configuration option to lower deque block size (#198348)

Added: 
    libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.default.compile.pass.cpp
    libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.lower.compile.pass.cpp

Modified: 
    libcxx/docs/ABIGuarantees.rst
    libcxx/include/__configuration/abi.h
    libcxx/include/deque
    libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp
    libcxx/utils/libcxx/test/features/libcxx_macros.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ABIGuarantees.rst b/libcxx/docs/ABIGuarantees.rst
index 4bd9737542a43..5d3d9891dc664 100644
--- a/libcxx/docs/ABIGuarantees.rst
+++ b/libcxx/docs/ABIGuarantees.rst
@@ -145,6 +145,10 @@ This flag adds ``[[clang::trivial_abi]]`` to ``shared_ptr``, which makes it triv
 This flag makes ``__bit_iterator`` (a.k.a. ``vector<bool>::iterator``) trivially copyable as well as trivial for the
 purpose of calls, since the copy constructor is made trivial.
 
+``_LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE``
+------------------------------------------
+This flag sets the default block size of ``deque`` to 512 bytes and the minimum number of elements per block to 4.
+
 Types that public aliases reference
 ===================================
 There are a lot of aliases that reference types with library internal names. For example, containers contain an

diff  --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 8781cb11e22ef..51c82d99eec30 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -76,6 +76,7 @@
 #  define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
 #  define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION
 #  define _LIBCPP_ABI_TRIVIALLY_COPYABLE_BIT_ITERATOR
+#  define _LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE
 
 #elif _LIBCPP_ABI_VERSION == 1
 // Feature macros for disabling pre ABI v1 features. All of these options

diff  --git a/libcxx/include/deque b/libcxx/include/deque
index bf589b05aef72..7aee552c63d37 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -263,10 +263,17 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#  ifndef _LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE
 template <class _ValueType, class _DiffType>
 struct __deque_block_size {
   static const _DiffType value = sizeof(_ValueType) < 256 ? 4096 / sizeof(_ValueType) : 16;
 };
+#  else
+template <class _ValueType, class _DiffType>
+struct __deque_block_size {
+  static const _DiffType value = sizeof(_ValueType) < 128 ? 512 / sizeof(_ValueType) : 4;
+};
+#  endif
 
 template <class _ValueType,
           class _Pointer,

diff  --git a/libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.default.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.default.compile.pass.cpp
new file mode 100644
index 0000000000000..888075bee7a08
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.default.compile.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// Test that std::__deque_block_size has default sizes when _LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE is not defined.
+
+// UNSUPPORTED: libcpp-abi-use-small-deque-block-size
+
+#include <deque>
+#include <cstddef>
+
+template <std::size_t Size>
+struct TypeOfSize {
+  char data[Size];
+};
+
+static_assert(std::__deque_block_size<char, std::ptr
diff _t>::value == 4096, "");
+static_assert(std::__deque_block_size<int, std::ptr
diff _t>::value == 1024, "");
+static_assert(std::__deque_block_size<double, std::ptr
diff _t>::value == 512, "");
+
+static_assert(std::__deque_block_size<TypeOfSize<255>, std::ptr
diff _t>::value == 16, "");
+static_assert(std::__deque_block_size<TypeOfSize<256>, std::ptr
diff _t>::value == 16, "");
+static_assert(std::__deque_block_size<TypeOfSize<512>, std::ptr
diff _t>::value == 16, "");

diff  --git a/libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.lower.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.lower.compile.pass.cpp
new file mode 100644
index 0000000000000..251ae98a9c74d
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/deque/lower_deque_block_size.lower.compile.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// Test that std::__deque_block_size has lowered sizes when _LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE is defined to 1.
+// REQUIRES: libcpp-abi-use-small-deque-block-size
+
+#include <deque>
+#include <cstddef>
+
+template <std::size_t Size>
+struct TypeOfSize {
+  char data[Size];
+};
+
+static_assert(std::__deque_block_size<char, std::ptr
diff _t>::value == 512, "");
+static_assert(std::__deque_block_size<int, std::ptr
diff _t>::value == 128, "");
+static_assert(std::__deque_block_size<double, std::ptr
diff _t>::value == 64, "");
+
+static_assert(std::__deque_block_size<TypeOfSize<255>, std::ptr
diff _t>::value == 4, "");
+static_assert(std::__deque_block_size<TypeOfSize<256>, std::ptr
diff _t>::value == 4, "");
+static_assert(std::__deque_block_size<TypeOfSize<512>, std::ptr
diff _t>::value == 4, "");

diff  --git a/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp
index c5f152a26a766..21c19cc6411af 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/deque/spare_block_handling.pass.cpp
@@ -55,7 +55,11 @@ struct LargeT {
   LargeT()       = default;
   char buff[256] = {};
 };
+#ifdef _LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE
+static_assert(BlockSize<LargeT>::value == 4, "");
+#else
 static_assert(BlockSize<LargeT>::value == 16, "");
+#endif
 
 const auto& AllocBytes = malloc_allocator_base::outstanding_bytes;
 
@@ -87,7 +91,7 @@ static void push_back() {
   {
     TEST_REQUIRE(d.size() == 1, on_fail);
     TEST_REQUIRE(d.__front_spare() == 0, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 14, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS - 2, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__capacity() == BS - 1, on_fail);
     TEST_REQUIRE(d.__block_count() == 1, on_fail);
@@ -97,7 +101,7 @@ static void push_back() {
   {
     TEST_REQUIRE(d.size() == 2, on_fail);
     TEST_REQUIRE(d.__front_spare() == 0, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 13, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS - 3, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
   }
   // Push back until we need a new block.
@@ -107,7 +111,7 @@ static void push_back() {
     TEST_REQUIRE(d.__block_count() == 2, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 15, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS - 1, on_fail);
   }
 
   // Remove the only element in the new block. Test that we keep the empty
@@ -117,7 +121,7 @@ static void push_back() {
     TEST_REQUIRE(d.__block_count() == 2, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 1, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 16, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS, on_fail);
   }
 
   // Pop back again, keep the spare.
@@ -125,7 +129,7 @@ static void push_back() {
   {
     TEST_REQUIRE(d.__block_count() == 2, on_fail);
     TEST_REQUIRE(d.__front_spare() == 0, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 17, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS + 1, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 1, on_fail);
   }
 
@@ -134,6 +138,7 @@ static void push_back() {
 }
 
 static void push_front() {
+  const auto BS = BlockSize<LargeT>::value;
   std::unique_ptr<Deque<LargeT>> dp(new Deque<LargeT>);
   auto& d = *dp;
   PrintOnFailure<Deque<LargeT>> on_fail(d);
@@ -149,8 +154,8 @@ static void push_front() {
   d.push_front({});
   {
     TEST_REQUIRE(d.size() == 1, on_fail);
-    TEST_REQUIRE(d.__front_spare() == 7, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 7, on_fail);
+    TEST_REQUIRE(d.__front_spare() == BS / 2 - 1, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS / 2 - 1, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__block_count() == 1, on_fail);
@@ -159,8 +164,8 @@ static void push_front() {
   d.push_front({});
   {
     TEST_REQUIRE(d.size() == 2, on_fail);
-    TEST_REQUIRE(d.__front_spare() == 6, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 7, on_fail);
+    TEST_REQUIRE(d.__front_spare() == BS / 2 - 2, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS / 2 - 1, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
   }
@@ -169,8 +174,8 @@ static void push_front() {
     d.push_front({});
   {
     TEST_REQUIRE(d.__block_count() == 2, on_fail);
-    TEST_REQUIRE(d.__front_spare() == 15, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 7, on_fail);
+    TEST_REQUIRE(d.__front_spare() == BS - 1, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS / 2 - 1, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
   }
@@ -182,7 +187,7 @@ static void push_front() {
     TEST_REQUIRE(d.__block_count() == 2, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 1, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 7, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS / 2 - 1, on_fail);
   }
 
   // Pop back again, keep the spare.
@@ -190,7 +195,7 @@ static void push_front() {
   {
     TEST_REQUIRE(d.__block_count() == 2, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 1, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 7, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS / 2 - 1, on_fail);
   }
 
   dp.reset();
@@ -205,12 +210,13 @@ static void std_queue() {
   Queue& q   = CA;
   PrintOnFailure<Deque<LargeT>> on_fail(d);
 
+  const auto BS = BlockSize<LargeT>::value;
   while (d.__block_count() < 4)
     q.push({});
   {
     TEST_REQUIRE(d.__block_count() == 4, on_fail);
     TEST_REQUIRE(d.__front_spare() == 0, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 15, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS - 1, on_fail);
     TEST_REQUIRE(d.__back_spare_blocks() == 0, on_fail);
   }
   while (d.__back_spare()) {
@@ -229,13 +235,13 @@ static void std_queue() {
   }
 
   // Pop until we create a spare block at the front.
-  while (d.__front_spare() <= 15)
+  while (d.__front_spare() <= BS - 1)
     q.pop();
 
   {
     TEST_REQUIRE(d.__block_count() == 4, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 1, on_fail);
-    TEST_REQUIRE(d.__front_spare() == 16, on_fail);
+    TEST_REQUIRE(d.__front_spare() == BS, on_fail);
     TEST_REQUIRE(d.__back_spare() == 0, on_fail);
   }
 
@@ -246,7 +252,7 @@ static void std_queue() {
     TEST_REQUIRE(d.__block_count() == 4, on_fail);
     TEST_REQUIRE(d.__front_spare_blocks() == 0, on_fail);
     TEST_REQUIRE(d.__front_spare() == 0, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 15, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS - 1, on_fail);
   }
   while (!q.empty()) {
     q.pop();
@@ -255,9 +261,9 @@ static void std_queue() {
 
   // The empty state has two blocks
   {
-    TEST_REQUIRE(d.__front_spare() == 16, on_fail);
-    TEST_REQUIRE(d.__back_spare() == 15, on_fail);
-    TEST_REQUIRE(d.__capacity() == 31, on_fail);
+    TEST_REQUIRE(d.__front_spare() == BS, on_fail);
+    TEST_REQUIRE(d.__back_spare() == BS - 1, on_fail);
+    TEST_REQUIRE(d.__capacity() == BS * 2 - 1, on_fail);
   }
 }
 

diff  --git a/libcxx/utils/libcxx/test/features/libcxx_macros.py b/libcxx/utils/libcxx/test/features/libcxx_macros.py
index aeb4696501a83..a3b32a9c88051 100644
--- a/libcxx/utils/libcxx/test/features/libcxx_macros.py
+++ b/libcxx/utils/libcxx/test/features/libcxx_macros.py
@@ -34,6 +34,7 @@
     "_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR": "libcpp-deprecated-abi-disable-pair-trivial-copy-ctor",
     "_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING": "libcpp-abi-no-compressed-pair-padding",
     "_LIBCPP_PSTL_BACKEND_LIBDISPATCH": "libcpp-pstl-backend-libdispatch",
+    "_LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE": "libcpp-abi-use-small-deque-block-size",
 }
 for macro, feature in macros.items():
     features.append(


        


More information about the libcxx-commits mailing list