diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt index 8b51942d30fe8..9e9de9ed1569d 100644 --- a/libc/config/baremetal/aarch64/entrypoints.txt +++ b/libc/config/baremetal/aarch64/entrypoints.txt @@ -231,6 +231,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.llabs libc.src.stdlib.lldiv libc.src.stdlib.malloc + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.rand libc.src.stdlib.realloc diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt index 0170d18dceef7..38e585e43c776 100644 --- a/libc/config/darwin/arm/entrypoints.txt +++ b/libc/config/darwin/arm/entrypoints.txt @@ -82,6 +82,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.rand libc.src.stdlib.srand diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt index 19230cde47198..c55b6aa275690 100644 --- a/libc/config/darwin/x86_64/entrypoints.txt +++ b/libc/config/darwin/x86_64/entrypoints.txt @@ -78,6 +78,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.strtod libc.src.stdlib.strtof diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt index a5d32c8eda39f..0d32f37a86f07 100644 --- a/libc/config/gpu/amdgpu/entrypoints.txt +++ b/libc/config/gpu/amdgpu/entrypoints.txt @@ -172,6 +172,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.qsort_r libc.src.stdlib.rand diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt index f553f7cc2b210..57a3ed576da23 100644 --- a/libc/config/gpu/nvptx/entrypoints.txt +++ b/libc/config/gpu/nvptx/entrypoints.txt @@ -172,6 +172,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.qsort_r libc.src.stdlib.rand diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index bca0b13feb1a0..27e4c7035165a 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -191,6 +191,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.qsort_r libc.src.stdlib.rand diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index 9b09cc583904c..05e8e9e308168 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -156,6 +156,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.qsort_r libc.src.stdlib.strtod diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 9cf05ef6d5a61..b2329d30efb54 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -188,6 +188,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.qsort_r libc.src.stdlib.rand diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index ac281e8d39066..5086315600ce6 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -193,6 +193,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.qsort_r libc.src.stdlib.rand diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index 319815e590425..8ec5760bef84e 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -79,6 +79,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv + libc.src.stdlib.memalignment libc.src.stdlib.qsort libc.src.stdlib.strtod libc.src.stdlib.strtof diff --git a/libc/include/stdlib.yaml b/libc/include/stdlib.yaml index b308df98a6090..a6204ce3afee3 100644 --- a/libc/include/stdlib.yaml +++ b/libc/include/stdlib.yaml @@ -133,6 +133,12 @@ functions: arguments: - type: long long - type: long long + - name: memalignment + standards: + - stdc + return_type: size_t + arguments: + - type: const void * - name: posix_memalign standards: - posix diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt index 63eb358717656..74ae864f72e23 100644 --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -345,6 +345,17 @@ add_entrypoint_object( .rand_util ) +add_entrypoint_object( + memalignment + SRCS + memalignment.cpp + HDRS + memalignment.h + DEPENDS + libc.src.__support.common + libc.hdr.types.size_t +) + if(NOT LIBC_TARGET_OS_IS_BAREMETAL AND NOT LIBC_TARGET_OS_IS_GPU) if(LLVM_LIBC_INCLUDE_SCUDO) set(SCUDO_DEPS "") diff --git a/libc/src/stdlib/memalignment.cpp b/libc/src/stdlib/memalignment.cpp new file mode 100644 index 0000000000000..f06e7bf0f2d0d --- /dev/null +++ b/libc/src/stdlib/memalignment.cpp @@ -0,0 +1,25 @@ +//===-- Implementation 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdlib/memalignment.h" +#include "src/__support/CPP/bit.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, memalignment, (const void *p)) { + if (p == nullptr) + return 0; + + uintptr_t addr = reinterpret_cast(p); + + return size_t(1) << cpp::countr_zero(addr); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/memalignment.h b/libc/src/stdlib/memalignment.h new file mode 100644 index 0000000000000..b7c7430af8c8e --- /dev/null +++ b/libc/src/stdlib/memalignment.h @@ -0,0 +1,21 @@ +//===-- 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 "hdr/types/size_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +size_t memalignment(const void *p); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDLIB_LDIV_H diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt index 90d7b7a55dbe6..302971a078c17 100644 --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -368,6 +368,17 @@ add_libc_test( libc.src.stdlib.srand ) +add_libc_test( + memalignment_test + SUITE + libc-stdlib-tests + SRCS + memalignment_test.cpp + DEPENDS + libc.include.stdlib + libc.src.stdlib.memalignment +) + if(LLVM_LIBC_FULL_BUILD) add_libc_test( diff --git a/libc/test/src/stdlib/memalignment_test.cpp b/libc/test/src/stdlib/memalignment_test.cpp new file mode 100644 index 0000000000000..2ca1b79e69e36 --- /dev/null +++ b/libc/test/src/stdlib/memalignment_test.cpp @@ -0,0 +1,59 @@ +//===-- 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/memalignment.h" +#include "test/UnitTest/Test.h" + +#include + +TEST(LlvmLibcMemAlignmentTest, NullPointer) { + void *ptr = nullptr; + EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr), static_cast(0)); +} + +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(addr_align2); + void *ptr_align4 = reinterpret_cast(addr_align4); + void *ptr_align8 = reinterpret_cast(addr_align8); + void *ptr_align16 = reinterpret_cast(addr_align16); + void *ptr_align32 = reinterpret_cast(addr_align32); + + EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align2), static_cast(2)); + EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align4), static_cast(4)); + EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align8), static_cast(8)); + EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align16), static_cast(16)); + EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_align32), static_cast(32)); + + uintptr_t addr_complex = 0x1234560; // 16-byte aligned (ends in 0) + void *ptr_complex = reinterpret_cast(addr_complex); + EXPECT_EQ(LIBC_NAMESPACE::memalignment(ptr_complex), static_cast(32)); +} + +TEST(LlvmLibcMemAlignmentTest, AlignasSpecifiedAlignment) { + alignas(16) static int aligned_16; + alignas(32) static int aligned_32; + alignas(64) static int aligned_64; + alignas(128) static int aligned_128; + alignas(256) static int aligned_256; + + EXPECT_GE(LIBC_NAMESPACE::memalignment(&aligned_16), static_cast(16)); + EXPECT_GE(LIBC_NAMESPACE::memalignment(&aligned_32), static_cast(32)); + EXPECT_GE(LIBC_NAMESPACE::memalignment(&aligned_64), static_cast(64)); + EXPECT_GE(LIBC_NAMESPACE::memalignment(&aligned_128), + static_cast(128)); + EXPECT_GE(LIBC_NAMESPACE::memalignment(&aligned_256), + static_cast(256)); +}