Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
152894e
[libc] implement `memalignment`
hulxv Mar 21, 2025
000e4e2
chore: fix formatting of `memalignment.h`
hulxv Mar 21, 2025
845184e
test: adding tests for `memalignment`
hulxv Mar 21, 2025
224d792
chore: fix formatting of `memalignment_test.cpp`
hulxv Mar 21, 2025
76b752d
[libc] add `memalignment` to `x86_64` entrypoints
hulxv Mar 22, 2025
40ed080
[libc] fix header of `memalignment`
hulxv Mar 22, 2025
ce731cc
[libc] add `memalignment` to other architectures entrypoints
hulxv Mar 22, 2025
4593534
[libc] add `memalignment` to `stdlib-mallic.yaml`
hulxv Mar 22, 2025
8b50acb
[libc] improve `memalignment`
hulxv Mar 22, 2025
a2ae994
chore: correct file extension of `memalignment`
hulxv Mar 22, 2025
931115f
refactor: use `cpp::countr_zero` instead of `__builtin_ctzg`
hulxv Mar 22, 2025
ff7a9bc
build: add `memalignment` to `CMakeLists.txt`
hulxv Mar 22, 2025
edc13a9
chore: add new line to the EOF of `memalignment_test.cpp`
hulxv Mar 22, 2025
5ab7da5
fix: `memalignment` build entrypoints
hulxv Mar 22, 2025
23320f4
fix: correct the standard of `memalignment`
hulxv Mar 23, 2025
eb201b3
build: correct build entry for `memalignment`
hulxv Mar 23, 2025
c1f9e6f
test: add `AlignasSpecifiedAlignment` for `memalignment` unit tests
hulxv Mar 23, 2025
0a8b610
build: remove wrong entrypoint
hulxv Mar 23, 2025
373c02d
[libc] missing newline
hulxv Mar 25, 2025
5dab7c5
[libc] move `memalignment` to `stdlib.yaml`
hulxv Mar 25, 2025
af0644a
[libc] fix header of `memalignment_test.cpp`
hulxv Mar 25, 2025
4c0d249
[libc] move `libc.src.stdlib.memalignment`to correct entrypoints
hulxv Mar 25, 2025
ac80029
[libc] remove wrong external entrypoint in `stdlib`
hulxv Mar 25, 2025
203ce17
Merge branch 'main' into libc/feat/memalignment
hulxv Mar 26, 2025
e8c38bd
Update libc/src/stdlib/memalignment.cpp
jhuber6 Mar 26, 2025
46d9f09
[libc] add header to `memalignment.cpp`
hulxv Mar 27, 2025
cee9d85
fix formatting
hulxv Mar 27, 2025
3b56885
[libc] remove `MallocedPointers`
hulxv Mar 28, 2025
9d04fa4
[libc] fix wrong header
hulxv Mar 28, 2025
778f87d
fix formatting
hulxv Mar 28, 2025
9e5616d
[libc][test] fix wrong expectation in `LlvmLibcMemAlignmentTest.Speci…
hulxv Mar 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.free
libc.src.stdlib.malloc
libc.src.stdlib.realloc
libc.src.stdlib.memalignment

# stdio.h entrypoints
libc.src.stdio.fprintf
Expand Down
19 changes: 19 additions & 0 deletions libc/src/stdlib/memalignment.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "src/stdlib/memalignment.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(size_t, memalignment, (const void *p)) {
if (p == NULL) {
return 0;
}

uintptr_t addr = (uintptr_t)p;

// Find the rightmost set bit, which represents the maximum alignment
// The alignment is a power of two, so we need to find the largest
// power of two that divides the address
return addr & (~addr + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return addr & (~addr + 1);
return addr & (~addr + 1);

I can't decide if it would be better to just use ctz. They reduce to the same ASM https://godbolt.org/z/qTjxc6dPn.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made up my mind, the bit twiddling is good here, while 1ull << cpp::count_trailing_zeroes(addr) is probably easier to read, I think it performs worse for 64-bit values.

Copy link
Member Author

@hulxv hulxv Mar 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then going with __builtin_ctzg is better?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the opposite.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does 1ull << cpp::count_trailing_zeroes(addr) exist? I don't find it anywhere. what about using countr_zeros?

}

} // namespace LIBC_NAMESPACE_DECL
22 changes: 22 additions & 0 deletions libc/src/stdlib/memalignment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Implementation header for memalignment --------------------------*- C++
//-*-===//
//
// 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 LLVM_LIBC_SRC_STDLIB_MEM_ALIGNMENT_H
#define LLVM_LIBC_SRC_STDLIB_MEM_ALIGNMENT_H

#include "src/__support/macros/config.h"
#include <stddef.h>

namespace LIBC_NAMESPACE_DECL {

size_t memalignment(const void *p);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_STDLIB_LDIV_H
12 changes: 12 additions & 0 deletions libc/test/src/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -457,4 +457,16 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.stdlib.free
)
endif()
add_libc_test(
memalignment_test
# The EXPECT_EXITS test is only availible for unit tests.
UNIT_TEST_ONLY
SUITE
libc-stdlib-tests
SRCS
memalignment_test.cpp
DEPENDS
libc.include.stdlib
libc.src.stdlib.memalignment
)
endif()
67 changes: 67 additions & 0 deletions libc/test/src/stdlib/memalignment_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//===-- Unittests for memalignment ---------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "src/stdlib/free.h"
#include "src/stdlib/malloc.h"
#include "src/stdlib/memalignment.h"
#include "test/UnitTest/Test.h"

#include <stdint.h>

TEST(LlvmLibcMemAlignmentTest, NullPointer) {
void *ptr = nullptr;
EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr), static_cast<size_t>(0));
}

TEST(LlvmLibcMemAlignmentTest, MallocedPointers) {
int *int_ptr = reinterpret_cast<int *>(LIBC_NAMESPACE::malloc(sizeof(int)));
EXPECT_NE(reinterpret_cast<void *>(int_ptr), static_cast<void *>(nullptr));

size_t int_alignment = LIBC_NAMESPACE::memalignment(int_ptr);
EXPECT_GE(int_alignment, alignof(int));

LIBC_NAMESPACE::free(int_ptr);

// Allocate a double (typically 8-byte aligned)
double *double_ptr =
reinterpret_cast<double *>(LIBC_NAMESPACE::malloc(sizeof(double)));
EXPECT_NE(reinterpret_cast<void *>(double_ptr), static_cast<void *>(nullptr));

size_t double_alignment = LIBC_NAMESPACE::memalignment(double_ptr);
EXPECT_GE(double_alignment, alignof(double));

EXPECT_EQ(double_alignment & (double_alignment - 1), static_cast<size_t>(0));

LIBC_NAMESPACE::free(double_ptr);
}

TEST(LlvmLibcMemAlignmentTest, SpecificAlignment) {

// These addresses have known alignment patterns - if we can construct them
uintptr_t addr_align2 = 0x2; // 2-byte aligned
uintptr_t addr_align4 = 0x4; // 4-byte aligned
uintptr_t addr_align8 = 0x8; // 8-byte aligned
uintptr_t addr_align16 = 0x10; // 16-byte aligned
uintptr_t addr_align32 = 0x20; // 32-byte aligned

void *ptr_align2 = reinterpret_cast<void *>(addr_align2);
void *ptr_align4 = reinterpret_cast<void *>(addr_align4);
void *ptr_align8 = reinterpret_cast<void *>(addr_align8);
void *ptr_align16 = reinterpret_cast<void *>(addr_align16);
void *ptr_align32 = reinterpret_cast<void *>(addr_align32);

EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align2), static_cast<size_t>(2));
EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align4), static_cast<size_t>(4));
EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align8), static_cast<size_t>(8));
EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align16), static_cast<size_t>(16));
EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align32), static_cast<size_t>(32));

uintptr_t addr_complex = 0x1234560; // 16-byte aligned (ends in 0)
void *ptr_complex = reinterpret_cast<void *>(addr_complex);
EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_complex), static_cast<size_t>(16));
}
Loading