[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