[libc-commits] [libc] [libc][malloc] add a flat TLSF allocator for baremetal environment (PR #200075)

via libc-commits libc-commits at lists.llvm.org
Wed May 27 17:55:24 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

<details>
<summary>Changes</summary>

This is an allocator inspired directly by https://github.com/SFBdragon/talc and https://github.com/mattconte/tlsf.

Featuring a high throughput while a reduced but comparable heap efficiency compared to dlmalloc.

Assisted-by: AI Agents, Checked Manually

---

Patch is 95.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/200075.diff


31 Files Affected:

- (modified) libc/cmake/modules/LLVMLibCCompileOptionRules.cmake (+8) 
- (modified) libc/config/config.json (+6) 
- (modified) libc/src/__support/CMakeLists.txt (+18) 
- (added) libc/src/__support/flat_tlsf/CMakeLists.txt (+117) 
- (added) libc/src/__support/flat_tlsf/binning.h (+161) 
- (added) libc/src/__support/flat_tlsf/bit_utils.h (+88) 
- (added) libc/src/__support/flat_tlsf/bitfield.h (+75) 
- (added) libc/src/__support/flat_tlsf/chunk.h (+91) 
- (added) libc/src/__support/flat_tlsf/common.h (+35) 
- (added) libc/src/__support/flat_tlsf/global.cpp (+24) 
- (added) libc/src/__support/flat_tlsf/global.h (+117) 
- (added) libc/src/__support/flat_tlsf/heap.h (+507) 
- (added) libc/src/__support/flat_tlsf/node.h (+47) 
- (added) libc/src/__support/flat_tlsf/tag.h (+50) 
- (added) libc/src/__support/heap.cpp (+29) 
- (added) libc/src/__support/heap.h (+38) 
- (modified) libc/src/stdlib/baremetal/CMakeLists.txt (+5-5) 
- (modified) libc/src/stdlib/baremetal/aligned_alloc.cpp (+2-2) 
- (modified) libc/src/stdlib/baremetal/calloc.cpp (+2-2) 
- (modified) libc/src/stdlib/baremetal/free.cpp (+2-2) 
- (modified) libc/src/stdlib/baremetal/malloc.cpp (+2-2) 
- (modified) libc/src/stdlib/baremetal/realloc.cpp (+2-2) 
- (modified) libc/test/src/__support/CMakeLists.txt (+1) 
- (added) libc/test/src/__support/flat_tlsf/CMakeLists.txt (+97) 
- (added) libc/test/src/__support/flat_tlsf/binning_test.cpp (+150) 
- (added) libc/test/src/__support/flat_tlsf/bitfield_test.cpp (+195) 
- (added) libc/test/src/__support/flat_tlsf/chunk_test.cpp (+77) 
- (added) libc/test/src/__support/flat_tlsf/global_test.cpp (+286) 
- (added) libc/test/src/__support/flat_tlsf/heap_test.cpp (+219) 
- (added) libc/test/src/__support/flat_tlsf/node_test.cpp (+88) 
- (added) libc/test/src/__support/flat_tlsf/tag_test.cpp (+58) 


``````````diff
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index c65fc4db605c9..9ea0e820636ec 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -177,6 +177,14 @@ function(_get_compile_options_from_config output_var)
     libc_add_definition(config_options "LIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT=${LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT}")
   endif()
 
+  if(LIBC_CONF_HEAP_TYPE)
+    if(LIBC_CONF_HEAP_TYPE STREQUAL "LIBC_HEAP_TYPE_FLAT_TLSF")
+      libc_add_definition(config_options "LIBC_HEAP_TYPE_FLAT_TLSF")
+    else()
+      libc_add_definition(config_options "LIBC_HEAP_TYPE_FREELIST")
+    endif()
+  endif()
+
   if(LIBC_CONF_MATH_USE_SYSTEM_FENV)
     libc_add_definition(config_options "LIBC_MATH_USE_SYSTEM_FENV")
   endif()
diff --git a/libc/config/config.json b/libc/config/config.json
index 27d9f08ed31e0..ebeba5bd00706 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -196,5 +196,11 @@
       "value": false,
       "doc": "Use the system assert macro for LIBC_ASSERT."
     }
+  },
+  "heap": {
+    "LIBC_CONF_HEAP_TYPE": {
+      "value": "LIBC_HEAP_TYPE_FREELIST",
+      "doc": "Selects the implementation for the global heap: 'LIBC_HEAP_TYPE_FREELIST' or 'LIBC_HEAP_TYPE_FLAT_TLSF'."
+    }
   }
 }
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index 1f77fc02380df..2605ac36ed39a 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -82,6 +82,23 @@ add_object_library(
     libc.src.string.memory_utils.inline_memset
 )
 
+if(LIBC_CONF_HEAP_TYPE STREQUAL "LIBC_HEAP_TYPE_FLAT_TLSF")
+  set(heap_impl_dependency libc.src.__support.flat_tlsf.global)
+else()
+  set(heap_impl_dependency .freelist_heap)
+endif()
+
+add_object_library(
+  heap
+  HDRS
+    heap.h
+  SRCS
+    heap.cpp
+  DEPENDS
+    ${heap_impl_dependency}
+    libc.src.__support.macros.config
+)
+
 add_header_library(
   blockstore
   HDRS
@@ -464,6 +481,7 @@ add_subdirectory(File)
 add_subdirectory(HashTable)
 
 add_subdirectory(fixed_point)
+add_subdirectory(flat_tlsf)
 
 add_subdirectory(time)
 
diff --git a/libc/src/__support/flat_tlsf/CMakeLists.txt b/libc/src/__support/flat_tlsf/CMakeLists.txt
new file mode 100644
index 0000000000000..b57e6ce8aec3b
--- /dev/null
+++ b/libc/src/__support/flat_tlsf/CMakeLists.txt
@@ -0,0 +1,117 @@
+add_header_library(
+  common
+  HDRS
+    common.h
+  DEPENDS
+    libc.src.__support.macros.config
+)
+
+add_header_library(
+  bit_utils
+  HDRS
+    bit_utils.h
+  DEPENDS
+    libc.hdr.stdint_proxy
+    libc.src.__support.CPP.bit
+    libc.src.__support.CPP.limits
+    .common
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+    libc.src.__support.math_extras
+)
+
+add_header_library(
+  bitfield
+  HDRS
+    bitfield.h
+  DEPENDS
+    libc.hdr.stdint_proxy
+    libc.src.__support.CPP.array
+    .bit_utils
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+)
+
+add_header_library(
+  binning
+  HDRS
+    binning.h
+  DEPENDS
+    libc.hdr.stdint_proxy
+    .common
+    .bitfield
+    .bit_utils
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+)
+
+add_header_library(
+  tag
+  HDRS
+    tag.h
+  DEPENDS
+    .common
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+)
+
+add_header_library(
+  node
+  HDRS
+    node.h
+  DEPENDS
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+)
+
+add_header_library(
+  chunk
+  HDRS
+    chunk.h
+  DEPENDS
+    .common
+    .node
+    .bit_utils
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+    libc.src.string.memory_utils.inline_memcpy
+)
+
+add_header_library(
+  heap
+  HDRS
+    heap.h
+  DEPENDS
+    .common
+    .node
+    .bit_utils
+    .bitfield
+    .binning
+    .chunk
+    .tag
+    libc.hdr.types.size_t
+    libc.src.__support.CPP.optional
+    libc.src.__support.CPP.limits
+    libc.src.__support.CPP.algorithm
+    libc.src.string.memory_utils.inline_memcpy
+    libc.src.__support.libc_assert
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+)
+
+add_object_library(
+  global
+  HDRS
+    global.h
+  SRCS
+    global.cpp
+  DEPENDS
+    .common
+    .heap
+    libc.src.__support.CPP.cstddef
+    libc.src.__support.CPP.span
+    libc.src.__support.math_extras
+    libc.src.string.memory_utils.inline_memset
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+)
diff --git a/libc/src/__support/flat_tlsf/binning.h b/libc/src/__support/flat_tlsf/binning.h
new file mode 100644
index 0000000000000..6745b19c201ac
--- /dev/null
+++ b/libc/src/__support/flat_tlsf/binning.h
@@ -0,0 +1,161 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provide Binning class for the flat_tlsf allocator.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BINNING_H
+#define LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BINNING_H
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/flat_tlsf/bit_utils.h"
+#include "src/__support/flat_tlsf/bitfield.h"
+#include "src/__support/flat_tlsf/common.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace flat_tlsf {
+
+struct Binning {
+  static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
+                "Only 32-bit and 64-bit architectures are currently supported");
+
+  static constexpr size_t BIN_COUNT = BitField::BITS - 1;
+
+  /// A fast binning algorithm with relatively even coverage and configurable
+  /// behavior.
+  ///
+  /// This is the default binning algorithm used due to having a good spread of
+  /// bin intervals, being able to take advantage of many or few buckets well,
+  /// and being very fast (only a handful of instructions with one branch).
+  ///
+  /// # Behavior by size
+  /// - `0..=(CHUNK_UNIT*LIN_DIVS*LIN_EXT_MULTI)` : Bins sizes into
+  /// one-bin-per-chunk-size
+  /// - `(CHUNK_UNIT*LIN_DIVS*LIN_EXT_MULTI)..`   : Binds sizes by
+  /// linearly-subdivided exponential levels.
+  ///
+  /// # Parameters
+  /// - `LIN_DIVS`: the number of linear regions per power of two in the
+  /// exponential region.
+  ///     - The higher this is, the more buckets are needed but the binning is
+  ///     more fine-grained.
+  ///     - Must be a power of two.
+  ///     - Typically 2 (few bins, subpar granularity), 4, or 8 (lots of bins,
+  ///     good granularity).
+  ///     - This is the parameter you want to figure out first for a given
+  ///     number of bins.
+  ///
+  /// - `LIN_EXT_MULTI`: the linear region extent multiplier.
+  ///     - Scales the extent of the linear region.
+  ///     - Must be a power of two.
+  ///     - Set this to 1 by default.
+  ///     - If there are too many bins being used on excessively-high size
+  ///     regions, this is useful for spending those bins on more buckets for
+  ///     small sizes instead.
+  ///
+  /// # Deciding on the parameters
+  /// `LIN_DIVS` has a much larger effect so tinker with that first while
+  /// keeping `LIN_EXT_MULTI` low, and then increase `LIN_EXT_MULTI` if there is
+  /// useless range at the top, given the number of bins you have.
+  ///
+  /// Having a range up to around 128MiB~2GiB is enough for most applications.
+  /// But keep in mind the largest bucket size you'll ever make use of is the
+  /// largest contiguous span of memory.
+  ///
+  /// The main effects on the allocator will be the heap efficiency and the
+  /// performance.
+  template <size_t LIN_DIVS, size_t LIN_EXT_MULTI>
+  LIBC_INLINE static constexpr size_t
+  linear_extend_then_linearly_divided_expotential_binning(size_t size) {
+    static_assert(bit_utils::is_power_of_2(LIN_DIVS),
+                  "LIN_DIVS must be a power of two");
+    static_assert(bit_utils::is_power_of_2(LIN_EXT_MULTI),
+                  "LIN_EXT_MULTI must be a power of two");
+
+    size_t exponential_region = CHUNK_UNIT * LIN_DIVS * LIN_EXT_MULTI;
+
+    // If the size is small enough, just divide by the chunk size.
+    // This is a fast short-circuit that handles the case where the size is
+    // smaller than `CHUNK_UNIT` and doesn't waste extra bins due to exponential
+    // subdivisions being smaller than `CHUNK_UNIT` here.
+    if (size <= exponential_region)
+      return size >> bit_utils::ilog2(CHUNK_UNIT);
+
+    // Let's say `exponential_region` is 256, the chunk unit is 32, LIN_DIVS is
+    // 4
+    //
+    // Exponential level 0:  256 ;  (512 - 256)/LIN_DIVS = 256/LIN_DIVS = 64
+    //  Subdiv 0: 256       ; bin 0 + LIN_DIVS * LIN_EXT_MULTI
+    //  Subdiv 1: 256 +  64 ; bin 1 + LIN_DIVS * LIN_EXT_MULTI
+    //  Subdiv 2: 256 + 128 ; bin 2 + LIN_DIVS * LIN_EXT_MULTI
+    //  Subdiv 3: 256 + 196 ; bin 3 + LIN_DIVS * LIN_EXT_MULTI
+    // Exponential level 1:  512 ;  512/LIN_DIVS = 128
+    //  Subdiv 0: 512       ; bin 4 + LIN_DIVS * LIN_EXT_MULTI
+    //  Subdiv 1: 512 + 128 ; bin 5 + LIN_DIVS * LIN_EXT_MULTI
+    //  Subdiv 2: 512 + 256 ; bin 6 + LIN_DIVS * LIN_EXT_MULTI
+    //  Subdiv 3: 512 + 384 ; bin 7 + LIN_DIVS * LIN_EXT_MULTI
+    // Exponential level 2: 1024 ; 1024/LIN_DIVS = 256
+    //  etc...
+    //
+    // Any size here is essentially broken up as follows:
+    //
+    // 00000000_1_01_010101010
+    //               ^^^^^^^^^ dead bits; all of this is ignored, effectively
+    //               rounding down these bits away
+    //            ^^ linear division bits; LIN_DIVS.ilog2() bits long after the
+    //            first set bit; tells us which linear subdivision we're in
+    //          ^ first set bit; dictates size.ilog2(); tells us which
+    //          "exponential level" this size is
+
+    size_t size_ilog2 = bit_utils::ilog2(size);
+
+    // Shift out the dead bits. This leaves the linear subdivision plus LIN_DIVS
+    // (due to the always-set bit at the top)
+    size_t linear_subdivision_plus_lin_divs =
+        size >> (size_ilog2 - bit_utils::ilog2(LIN_DIVS));
+
+    // Extract the exponential level above the `exponential_region` limit
+    // add LIN_EXT_MULTI here along with the other constants, it will get
+    // multiplied by LIN_DIVS next which gives us the exponential bins offset
+    // subtract 1 along with the other constants, this is important later
+    size_t unshifted_exponential_minus_one =
+        size_ilog2 - bit_utils::ilog2(exponential_region) + LIN_EXT_MULTI - 1;
+
+    // Multiply the exponential level by LIN_DIVS to shift it above the linear
+    // division bits Multiply the LIN_EXT_MULTI by LIN_DIVS to add the offset
+    // due to the linearly-spaced buckets Multiply (-1) to get (-LIN_DIVS)
+    size_t exponential_plus_offset_minus_lin_divs =
+        unshifted_exponential_minus_one << bit_utils::ilog2(LIN_DIVS);
+
+    // This LIN_DIVS cancel out, yielding the expected exponential-region bin
+    return exponential_plus_offset_minus_lin_divs +
+           linear_subdivision_plus_lin_divs;
+  }
+
+  LIBC_INLINE constexpr static uint32_t size_to_bin(size_t size) {
+    if constexpr (sizeof(void *) == 8)
+      return static_cast<uint32_t>(
+          linear_extend_then_linearly_divided_expotential_binning<8, 4>(size));
+    else
+      return static_cast<uint32_t>(
+          linear_extend_then_linearly_divided_expotential_binning<4, 4>(size));
+  }
+
+  LIBC_INLINE constexpr static uint32_t size_to_bin_ceil(size_t size) {
+    return size_to_bin(size - 1) + 1;
+  }
+};
+
+} // namespace flat_tlsf
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BINNING_H
diff --git a/libc/src/__support/flat_tlsf/bit_utils.h b/libc/src/__support/flat_tlsf/bit_utils.h
new file mode 100644
index 0000000000000..cf52c8b34b2e5
--- /dev/null
+++ b/libc/src/__support/flat_tlsf/bit_utils.h
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provide bit utilities for the flat_tlsf allocator.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BIT_UTILS_H
+#define LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BIT_UTILS_H
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/flat_tlsf/common.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/math_extras.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace flat_tlsf {
+
+// We could use cpp::byte, but that definition currently have strict aliasing
+// violation, hence we fallback to unsigned char directly.
+namespace bit_utils {
+
+LIBC_INLINE constexpr size_t ilog2(size_t n) {
+  return cpp::numeric_limits<size_t>::digits - 1 -
+         static_cast<size_t>(cpp::countl_zero(n));
+}
+
+LIBC_INLINE constexpr bool is_power_of_2(size_t n) {
+  return cpp::has_single_bit(n);
+}
+
+LIBC_INLINE constexpr uint32_t bit_scan_after(size_t w, uint32_t start_index) {
+  size_t lower_bits_cleared = (w >> start_index) << start_index;
+  return static_cast<uint32_t>(cpp::countr_zero(lower_bits_cleared));
+}
+
+LIBC_INLINE constexpr void set_bit(size_t &w, uint32_t index) {
+  w |= size_t{1} << index;
+}
+
+LIBC_INLINE constexpr void clear_bit(size_t &w, uint32_t index) {
+  w &= ~(size_t{1} << index);
+}
+
+LIBC_INLINE constexpr bool read_bit(size_t w, uint32_t index) {
+  return w & (size_t{1} << index);
+}
+
+LIBC_INLINE bool is_aligned_to(Byte *ptr, size_t align) {
+  return (cpp::bit_cast<uintptr_t>(ptr) & (align - 1)) == 0;
+}
+
+LIBC_INLINE Byte *align_down_by(Byte *ptr, size_t align) {
+  uintptr_t addr = cpp::bit_cast<uintptr_t>(ptr);
+  return cpp::bit_cast<Byte *>(addr & ~(align - 1));
+}
+
+LIBC_INLINE Byte *align_up_by_mask(Byte *ptr, size_t align_mask) {
+  uintptr_t addr = cpp::bit_cast<uintptr_t>(ptr);
+  return cpp::bit_cast<Byte *>((addr + align_mask) & ~align_mask);
+}
+
+LIBC_INLINE Byte *align_up_by(Byte *ptr, size_t align) {
+  return align_up_by_mask(ptr, align - 1);
+}
+
+LIBC_INLINE Byte *saturating_ptr_add(Byte *ptr, size_t bytes) {
+  uintptr_t addr = cpp::bit_cast<uintptr_t>(ptr);
+  uintptr_t result;
+  if (add_overflow(addr, bytes, result))
+    return cpp::bit_cast<Byte *>(cpp::numeric_limits<uintptr_t>::max());
+  return cpp::bit_cast<Byte *>(result);
+}
+
+} // namespace bit_utils
+} // namespace flat_tlsf
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BIT_UTILS_H
diff --git a/libc/src/__support/flat_tlsf/bitfield.h b/libc/src/__support/flat_tlsf/bitfield.h
new file mode 100644
index 0000000000000..7a8cdf0494784
--- /dev/null
+++ b/libc/src/__support/flat_tlsf/bitfield.h
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provide BitField class for the flat_tlsf allocator.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BITFIELD_H
+#define LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BITFIELD_H
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/array.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/flat_tlsf/bit_utils.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace flat_tlsf {
+
+struct alignas(16) BitField {
+  static constexpr size_t BITS_PER_ELEMENT =
+      cpp::numeric_limits<size_t>::digits;
+  static constexpr size_t NUMBER_OF_ELEMENTS = 3;
+  static constexpr size_t BITS = BITS_PER_ELEMENT * NUMBER_OF_ELEMENTS;
+
+  cpp::array<size_t, NUMBER_OF_ELEMENTS> storage;
+
+  LIBC_INLINE static constexpr BitField zeros() { return {}; }
+
+  LIBC_INLINE constexpr uint32_t bit_scan_after(uint32_t bit) const {
+    uint32_t array_index = bit / BITS_PER_ELEMENT;
+    uint32_t element_index = bit % BITS_PER_ELEMENT;
+    uint32_t bit_index =
+        bit_utils::bit_scan_after(storage[array_index], element_index);
+    if (bit_index < BITS_PER_ELEMENT)
+      return array_index * BITS_PER_ELEMENT + bit_index;
+    for (array_index = array_index + 1; array_index < NUMBER_OF_ELEMENTS;
+         ++array_index) {
+      bit_index = bit_utils::bit_scan_after(storage[array_index], 0);
+      if (bit_index < BITS_PER_ELEMENT)
+        return array_index * BITS_PER_ELEMENT + bit_index;
+    }
+    return BITS;
+  }
+
+  LIBC_INLINE constexpr void set_bit(uint32_t b) {
+    size_t array_index = b / BITS_PER_ELEMENT;
+    uint32_t element_index = static_cast<uint32_t>(b % BITS_PER_ELEMENT);
+    bit_utils::set_bit(storage[array_index], element_index);
+  }
+
+  LIBC_INLINE constexpr void clear_bit(uint32_t b) {
+    size_t array_index = b / BITS_PER_ELEMENT;
+    uint32_t element_index = static_cast<uint32_t>(b % BITS_PER_ELEMENT);
+    bit_utils::clear_bit(storage[array_index], element_index);
+  }
+
+  LIBC_INLINE constexpr bool read_bit(uint32_t b) const {
+    size_t array_index = b / BITS_PER_ELEMENT;
+    uint32_t element_index = static_cast<uint32_t>(b % BITS_PER_ELEMENT);
+    return bit_utils::read_bit(storage[array_index], element_index);
+  }
+};
+
+} // namespace flat_tlsf
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_BITFIELD_H
diff --git a/libc/src/__support/flat_tlsf/chunk.h b/libc/src/__support/flat_tlsf/chunk.h
new file mode 100644
index 0000000000000..62cfa56f62799
--- /dev/null
+++ b/libc/src/__support/flat_tlsf/chunk.h
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Provide chunk utility functions for the flat_tlsf allocator.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_CHUNK_H
+#define LLVM_LIBC_SRC___SUPPORT_FLAT_TLSF_CHUNK_H
+
+#include "src/__support/flat_tlsf/bit_utils.h"
+#include "src/__support/flat_tlsf/common.h"
+#include "src/__support/flat_tlsf/node.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace flat_tlsf {
+namespace chunk {
+
+LIBC_INLINE bool is_chunk_size(Byte *base, Byte *end) {
+  return end >= base + CHUNK_UNIT;
+}
+
+LIBC_INLINE constexpr size_t required_chunk_size(size_t size) {
+  size_t size_with_tag = size + 1;
+  size_t align_offset = (-size_with_tag) & (CHUNK_UNIT - 1);
+  return size_with_tag + align_offset;
+}
+
+LIBC_INLINE Byte *alloc_to_end(Byte *base, size_t size) {
+  return base + required_chunk_size(size);
+}
+
+LIBC_INLINE Node *gap_base_to_node(Byte *base) {
+  return reinterpret_cast<Node *>(base + GAP_NODE_OFFSET);
+}
+
+LIBC_INLINE uint32_t *gap_base_to_bin(Byte *base) {
+  return reinterpret_cast<uint32_t *>(base + GAP_BIN_OFFSET);
+}
+
+LIBC_INLINE size_t *gap_base_to_size(Byte *base) {
+  return reinterpret_cast<size_t *>(base + GAP_LOW_SIZE_OFFSET);
+}
+
+...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/200075


More information about the libc-commits mailing list