diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 06832a41221dd..c32773f67cda5 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -51,6 +51,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.mempcpy libc.src.string.memrchr libc.src.string.memset + libc.src.string.memset_explicit libc.src.string.rindex libc.src.string.stpcpy libc.src.string.stpncpy diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index bc10512d942fa..fef6a92d06aff 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -51,6 +51,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.mempcpy libc.src.string.memrchr libc.src.string.memset + libc.src.string.memset_explicit libc.src.string.rindex libc.src.string.stpcpy libc.src.string.stpncpy diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 94ac62966f3ba..c8f26eb1e07e0 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -234,6 +234,11 @@ def StdC : StandardSpec<"stdc"> { RetValSpec, [ArgSpec, ArgSpec, ArgSpec] >, + FunctionSpec< + "memset_explicit", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, FunctionSpec< "strcpy", RetValSpec, diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt index 1c893280e8a3c..56588ffafb86f 100644 --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -441,6 +441,17 @@ add_entrypoint_object( .memory_utils.inline_memcpy ) +add_entrypoint_object( + memset_explicit + SRCS + memset_explicit.cpp + HDRS + memset_explicit.h + DEPENDS + .string_utils + .memory_utils.inline_memset +) + # Helper to define a function with multiple implementations # - Computes flags to satisfy required/rejected features and arch, # - Declares an entry point, diff --git a/libc/src/string/memset_explicit.cpp b/libc/src/string/memset_explicit.cpp new file mode 100644 index 0000000000000..a8656d1e791e8 --- /dev/null +++ b/libc/src/string/memset_explicit.cpp @@ -0,0 +1,25 @@ +//===-- Implementation of memset_explicit ---------------------------------===// +// +// 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/string/memset_explicit.h" +#include "src/__support/common.h" +#include "src/string/memory_utils/inline_memset.h" + +namespace LIBC_NAMESPACE { + +[[gnu::noinline]] LLVM_LIBC_FUNCTION(void *, memset_explicit, + (void *dst, int value, size_t count)) { + // Use the inline memset function to set the memory. + inline_memset(dst, static_cast(value), count); + // avoid dead store elimination + // The asm itself should also be sufficient to behave as a compiler barrier. + asm("" : : "r"(dst) : "memory"); + return dst; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/string/memset_explicit.h b/libc/src/string/memset_explicit.h new file mode 100644 index 0000000000000..f6c189761a123 --- /dev/null +++ b/libc/src/string/memset_explicit.h @@ -0,0 +1,20 @@ +//===-- Implementation header for memset_explicit ---------------*- 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_STRING_MEMSET_EXPLICIT_H +#define LLVM_LIBC_SRC_STRING_MEMSET_EXPLICIT_H + +#include // size_t + +namespace LIBC_NAMESPACE { + +[[gnu::noinline]] void *memset_explicit(void *ptr, int value, size_t count); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_STRING_MEMSET_EXPLICIT_H diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt index 6088289532d77..c1caec5fd912c 100644 --- a/libc/test/src/string/CMakeLists.txt +++ b/libc/test/src/string/CMakeLists.txt @@ -418,6 +418,16 @@ add_libc_test( libc.src.string.strxfrm ) +add_libc_test( + memset_explicit_test + SUITE + libc-string-tests + SRCS + memset_explicit_test.cpp + DEPENDS + libc.src.string.memset_explicit +) + # Tests all implementations that can run on the target CPU. function(add_libc_multi_impl_test name) get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations) diff --git a/libc/test/src/string/memset_explicit_test.cpp b/libc/test/src/string/memset_explicit_test.cpp new file mode 100644 index 0000000000000..bb5111bd639e3 --- /dev/null +++ b/libc/test/src/string/memset_explicit_test.cpp @@ -0,0 +1,31 @@ +//===-- Unittests for memset_explicit -------------------------------------===// +// +// 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 "memory_utils/memory_check_utils.h" +#include "src/string/memset_explicit.h" +#include "test/UnitTest/Test.h" + +namespace LIBC_NAMESPACE { + +// Apply the same tests as memset + +static inline void Adaptor(cpp::span p1, uint8_t value, size_t size) { + LIBC_NAMESPACE::memset_explicit(p1.begin(), value, size); +} + +TEST(LlvmLibcmemsetExplicitTest, SizeSweep) { + static constexpr size_t kMaxSize = 400; + Buffer DstBuffer(kMaxSize); + for (size_t size = 0; size < kMaxSize; ++size) { + const char value = size % 10; + auto dst = DstBuffer.span().subspan(0, size); + ASSERT_TRUE((CheckMemset(dst, value, size))); + } +} + +} // namespace LIBC_NAMESPACE