[libc-commits] [libc] [libc] Add aligned_alloc (PR #96586)

via libc-commits libc-commits at lists.llvm.org
Thu Jun 27 13:50:17 PDT 2024


================
@@ -357,6 +410,66 @@ void Block<OffsetType, kAlign>::free(Block *&block) {
   merge_next(block);
 }
 
+template <typename OffsetType, size_t kAlign>
+bool Block<OffsetType, kAlign>::can_allocate(size_t alignment,
+                                             size_t size) const {
+  if (is_usable_space_aligned(alignment) && inner_size() >= size)
+    return true; // Size and alignment constraints met.
+
+  // Either the alignment isn't met or we don't have enough size.
+  // If we don't meet alignment, we can always adjust such that we do meet the
+  // alignment. If we meet the alignment but just don't have enough size. This
+  // check will fail anyway.
+  size_t adjustment = padding_for_alignment(alignment);
+  return inner_size() >= size + adjustment;
+}
+
+template <typename OffsetType, size_t kAlign>
+typename Block<OffsetType, kAlign>::BlockInfo
+Block<OffsetType, kAlign>::allocate(Block *block, size_t alignment,
+                                    size_t size) {
+  BlockInfo info{block, /*prev=*/nullptr, /*next=*/nullptr};
+
+  if (!info.block->is_usable_space_aligned(alignment)) {
+    size_t adjustment = info.block->padding_for_alignment(alignment);
+    size_t new_inner_size = adjustment - BLOCK_OVERHEAD;
+    LIBC_ASSERT(new_inner_size % ALIGNMENT == 0 &&
+                "The adjustment calculation should always return a new size "
+                "that's a multiple of ALIGNMENT");
+
+    Block *original = info.block;
+    optional<Block *> maybe_aligned_block =
+        Block::split(original, adjustment - BLOCK_OVERHEAD);
+    LIBC_ASSERT(maybe_aligned_block.has_value() &&
+                "This split should always result in a new block. The check in "
+                "`can_allocate` ensures that we have enough space here to make "
+                "two blocks.");
+
+    Block *aligned_block = *maybe_aligned_block;
----------------
PiJoules wrote:

> While you're asserting that the optional is valid, won't that assert compile away in release mode? or is the LIBC_ASSERT handled differently?

I believe `LIBC_ASSERT` in release does nothing similar to normal `assert`.

> If it is compiled away, I think you still need to have some kind of guard when assigning aligned_block, right?. Maybe using .value_or(nullptr) is the right thing?

Ideally this function should just "always succeed" as long as a prior call to `can_allocate` works. As long as that returns true, then this should never be nullptr and we should have a valid block ptr. I added an assert at the very start of this function saying this function should only be called if `can_allocate` returned true.

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


More information about the libc-commits mailing list