-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[libc] implement memalignment
#132493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc] implement memalignment
#132493
Changes from 5 commits
152894e
000e4e2
845184e
224d792
76b752d
40ed080
ce731cc
4593534
8b50acb
a2ae994
931115f
ff7a9bc
edc13a9
5ab7da5
23320f4
eb201b3
c1f9e6f
0a8b610
373c02d
5dab7c5
af0644a
4c0d249
ac80029
203ce17
e8c38bd
46d9f09
cee9d85
3b56885
9d04fa4
778f87d
9e5616d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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; | ||||||
| } | ||||||
hulxv marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| uintptr_t addr = (uintptr_t)p; | ||||||
hulxv marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| // 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); | ||||||
|
||||||
| 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the opposite.
There was a problem hiding this comment.
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?
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| //===-- Implementation header for memalignment --------------------------*- C++ | ||
| //-*-===// | ||
hulxv marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // | ||
| // 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| //===-- Unittests for memalignment ---------------------------------------===// | ||
hulxv marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // | ||
| // 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) { | ||
|
|
||
hulxv marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // 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)); | ||
hulxv marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
hulxv marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.