From 436c8f4420a62e7d3601693f4097bc6e6a5ee9f4 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Thu, 1 Dec 2022 10:06:36 +0000 Subject: [PATCH] [reland][libc] Add bcopy Differential Revision: https://reviews.llvm.org/D138994 --- libc/config/darwin/arm/entrypoints.txt | 1 + libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/arm/entrypoints.txt | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/config/windows/entrypoints.txt | 1 + libc/docs/strings.rst | 1 + libc/spec/llvm_libc_ext.td | 5 + libc/src/string/CMakeLists.txt | 9 +- libc/src/string/bcopy.cpp | 19 ++++ libc/src/string/bcopy.h | 20 ++++ libc/test/src/string/CMakeLists.txt | 12 ++ libc/test/src/string/bcopy_test.cpp | 104 ++++++++++++++++++ .../llvm-project-overlay/libc/BUILD.bazel | 11 ++ .../libc/test/src/string/BUILD.bazel | 12 ++ 14 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 libc/src/string/bcopy.cpp create mode 100644 libc/src/string/bcopy.h create mode 100644 libc/test/src/string/bcopy_test.cpp diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt index cd500736ac17..d16bf0816e54 100644 --- a/libc/config/darwin/arm/entrypoints.txt +++ b/libc/config/darwin/arm/entrypoints.txt @@ -19,6 +19,7 @@ set(TARGET_LIBC_ENTRYPOINTS # string.h entrypoints libc.src.string.bcmp + libc.src.string.bcopy libc.src.string.bzero libc.src.string.memccpy libc.src.string.memchr diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 8db3b795a83b..a67165e96f66 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -28,6 +28,7 @@ set(TARGET_LIBC_ENTRYPOINTS # string.h entrypoints libc.src.string.bcmp + libc.src.string.bcopy libc.src.string.bzero libc.src.string.memccpy libc.src.string.memchr diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index c88cbb1c3b5e..725365231af5 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -19,6 +19,7 @@ set(TARGET_LIBC_ENTRYPOINTS # string.h entrypoints libc.src.string.bcmp + libc.src.string.bcopy libc.src.string.bzero libc.src.string.memccpy libc.src.string.memchr diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index e9e173a83101..14043b039041 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -28,6 +28,7 @@ set(TARGET_LIBC_ENTRYPOINTS # string.h entrypoints libc.src.string.bcmp + libc.src.string.bcopy libc.src.string.bzero libc.src.string.memccpy libc.src.string.memchr diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index 69a0acab6ad5..bf52c8caccdf 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -19,6 +19,7 @@ set(TARGET_LIBC_ENTRYPOINTS # string.h entrypoints libc.src.string.bcmp + libc.src.string.bcopy libc.src.string.bzero libc.src.string.memccpy libc.src.string.memchr diff --git a/libc/docs/strings.rst b/libc/docs/strings.rst index c47513493786..50b479bf2117 100644 --- a/libc/docs/strings.rst +++ b/libc/docs/strings.rst @@ -36,6 +36,7 @@ Function Name Available ============= ========= bzero |check| bcmp |check| +bcopy |check| memcpy |check| memset |check| memcmp |check| diff --git a/libc/spec/llvm_libc_ext.td b/libc/spec/llvm_libc_ext.td index 76f06223756d..731671f7306b 100644 --- a/libc/spec/llvm_libc_ext.td +++ b/libc/spec/llvm_libc_ext.td @@ -5,6 +5,11 @@ def LLVMLibcExt : StandardSpec<"llvm_libc_ext"> { [], // Types [], // Enumerations [ + FunctionSpec< + "bcopy", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, FunctionSpec< "bzero", RetValSpec, diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt index 7719178da457..422d24c13131 100644 --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -20,6 +20,14 @@ add_header_library( .memory_utils.memcpy_implementation ) +add_entrypoint_object( + bcopy + SRCS + bcopy.cpp + HDRS + bcopy.h +) + add_entrypoint_object( memccpy SRCS @@ -28,7 +36,6 @@ add_entrypoint_object( memccpy.h ) - add_entrypoint_object( mempcpy SRCS diff --git a/libc/src/string/bcopy.cpp b/libc/src/string/bcopy.cpp new file mode 100644 index 000000000000..9653c73f1305 --- /dev/null +++ b/libc/src/string/bcopy.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of bcopy -------------------------------------------===// +// +// 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/bcopy.h" +#include "src/__support/common.h" +#include "src/string/memory_utils/memmove_implementations.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(void, bcopy, (const void *src, void *dst, size_t count)) { + return inline_memmove(dst, src, count); +} + +} // namespace __llvm_libc diff --git a/libc/src/string/bcopy.h b/libc/src/string/bcopy.h new file mode 100644 index 000000000000..12de749d4640 --- /dev/null +++ b/libc/src/string/bcopy.h @@ -0,0 +1,20 @@ +//===-- Implementation header for bcopy -------------------------*- 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_BCOPY_H +#define LLVM_LIBC_SRC_STRING_BCOPY_H + +#include // size_t + +namespace __llvm_libc { + +void bcopy(const void *src, void *dest, size_t count); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STRING_BCOPY_H diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt index b0b352913cc9..8b427cc2d116 100644 --- a/libc/test/src/string/CMakeLists.txt +++ b/libc/test/src/string/CMakeLists.txt @@ -2,6 +2,18 @@ add_libc_testsuite(libc_string_unittests) add_subdirectory(memory_utils) +add_libc_unittest( + bcopy_test + SUITE + libc_string_unittests + SRCS + bcopy_test.cpp + DEPENDS + libc.src.string.bcopy + LINK_LIBRARIES + LibcMemoryHelpers +) + add_libc_unittest( memccpy_test SUITE diff --git a/libc/test/src/string/bcopy_test.cpp b/libc/test/src/string/bcopy_test.cpp new file mode 100644 index 000000000000..fa57d2502c2d --- /dev/null +++ b/libc/test/src/string/bcopy_test.cpp @@ -0,0 +1,104 @@ +//===-- Unittests for bcopy -----------------------------------------------===// +// +// 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/__support/CPP/span.h" +#include "src/string/bcopy.h" +#include "utils/UnitTest/MemoryMatcher.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::cpp::array; +using __llvm_libc::cpp::span; + +TEST(LlvmLibcBcopyTest, MoveZeroByte) { + char Buffer[] = {'a', 'b', 'y', 'z'}; + const char Expected[] = {'a', 'b', 'y', 'z'}; + void *const Dst = Buffer; + __llvm_libc::bcopy(Buffer + 2, Dst, 0); + ASSERT_MEM_EQ(Buffer, Expected); +} + +TEST(LlvmLibcBcopyTest, DstAndSrcPointToSameAddress) { + char Buffer[] = {'a', 'b'}; + const char Expected[] = {'a', 'b'}; + void *const Dst = Buffer; + __llvm_libc::bcopy(Buffer, Dst, 1); + ASSERT_MEM_EQ(Buffer, Expected); +} + +TEST(LlvmLibcBcopyTest, DstStartsBeforeSrc) { + // Set boundary at beginning and end for not overstepping when + // copy forward or backward. + char Buffer[] = {'z', 'a', 'b', 'c', 'z'}; + const char Expected[] = {'z', 'b', 'c', 'c', 'z'}; + void *const Dst = Buffer + 1; + __llvm_libc::bcopy(Buffer + 2, Dst, 2); + ASSERT_MEM_EQ(Buffer, Expected); +} + +TEST(LlvmLibcBcopyTest, DstStartsAfterSrc) { + char Buffer[] = {'z', 'a', 'b', 'c', 'z'}; + const char Expected[] = {'z', 'a', 'a', 'b', 'z'}; + void *const Dst = Buffer + 2; + __llvm_libc::bcopy(Buffer + 1, Dst, 2); + ASSERT_MEM_EQ(Buffer, Expected); +} + +// e.g. `Dst` follow `src`. +// str: [abcdefghij] +// [__src_____] +// [_____Dst__] +TEST(LlvmLibcBcopyTest, SrcFollowDst) { + char Buffer[] = {'z', 'a', 'b', 'z'}; + const char Expected[] = {'z', 'b', 'b', 'z'}; + void *const Dst = Buffer + 1; + __llvm_libc::bcopy(Buffer + 2, Dst, 1); + ASSERT_MEM_EQ(Buffer, Expected); +} + +TEST(LlvmLibcBcopyTest, DstFollowSrc) { + char Buffer[] = {'z', 'a', 'b', 'z'}; + const char Expected[] = {'z', 'a', 'a', 'z'}; + void *const Dst = Buffer + 2; + __llvm_libc::bcopy(Buffer + 1, Dst, 1); + ASSERT_MEM_EQ(Buffer, Expected); +} + +static constexpr int kMaxSize = 512; + +char GetRandomChar() { + static constexpr const uint64_t A = 1103515245; + static constexpr const uint64_t C = 12345; + static constexpr const uint64_t M = 1ULL << 31; + static uint64_t Seed = 123456789; + Seed = (A * Seed + C) % M; + return Seed; +} + +void Randomize(span Buffer) { + for (auto ¤t : Buffer) + current = GetRandomChar(); +} + +TEST(LlvmLibcBcopyTest, SizeSweep) { + using LargeBuffer = array; + LargeBuffer GroundTruth; + Randomize(GroundTruth); + for (int Size = 0; Size < kMaxSize; ++Size) { + for (int Offset = -Size; Offset < Size; ++Offset) { + LargeBuffer Buffer = GroundTruth; + LargeBuffer Expected = GroundTruth; + size_t DstOffset = kMaxSize; + size_t SrcOffset = kMaxSize + Offset; + for (int I = 0; I < Size; ++I) + Expected[DstOffset + I] = GroundTruth[SrcOffset + I]; + void *const Dst = Buffer.data() + DstOffset; + __llvm_libc::bcopy(Buffer.data() + SrcOffset, Dst, Size); + ASSERT_MEM_EQ(Buffer, Expected); + } + } +} diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 1aafa2a8473b..48c84fc96e69 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -1124,6 +1124,17 @@ libc_function( ], ) +libc_function( + name = "bcopy", + srcs = ["src/string/bcopy.cpp"], + hdrs = ["src/string/bcopy.h"], + features = no_sanitize_features, + deps = [ + ":__support_common", + ":string_memory_utils", + ], +) + libc_function( name = "memcmp", srcs = ["src/string/memcmp.cpp"], diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/string/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/string/BUILD.bazel index 8ccc62767696..cfda301ff2d7 100644 --- a/utils/bazel/llvm-project-overlay/libc/test/src/string/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/test/src/string/BUILD.bazel @@ -146,6 +146,18 @@ libc_test( ], ) +libc_test( + name = "bcopy_test", + srcs = ["bcopy_test.cpp"], + libc_function_deps = [ + "//libc:bcopy", + ], + deps = [ + "//libc:__support_cpp_span", + "//libc/utils/UnitTest:memory_matcher", + ], +) + libc_test( name = "memcmp_test", srcs = ["memcmp_test.cpp"],