[libc] Add a trivial implementation for bcmp
authorGuillaume Chatelet <gchatelet@google.com>
Thu, 19 Aug 2021 17:55:16 +0000 (17:55 +0000)
committerGuillaume Chatelet <gchatelet@google.com>
Thu, 19 Aug 2021 17:55:16 +0000 (17:55 +0000)
Differential Revision: https://reviews.llvm.org/D108225

libc/benchmarks/CMakeLists.txt
libc/benchmarks/LibcMemoryBenchmarkMain.cpp
libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/spec/llvm_libc_ext.td
libc/src/string/CMakeLists.txt
libc/src/string/bcmp.cpp [new file with mode: 0644]
libc/src/string/bcmp.h [new file with mode: 0644]
libc/test/src/string/CMakeLists.txt
libc/test/src/string/bcmp_test.cpp [new file with mode: 0644]

index ba46fae..3eece74 100644 (file)
@@ -171,6 +171,7 @@ add_libc_multi_impl_benchmark(memcpy)
 add_libc_multi_impl_benchmark(memset)
 add_libc_multi_impl_benchmark(bzero)
 add_libc_multi_impl_benchmark(memcmp)
+add_libc_multi_impl_benchmark(bcmp)
 
 #==============================================================================
 # Google Benchmarking tool
@@ -188,6 +189,7 @@ target_link_libraries(libc.benchmarks.memory_functions.opt_host
   PRIVATE
   libc-memory-benchmark
   libc.src.string.memcmp_opt_host
+  libc.src.string.bcmp_opt_host
   libc.src.string.memcpy_opt_host
   libc.src.string.memset_opt_host
   libc.src.string.bzero_opt_host
index 30bbfd4..8539402 100644 (file)
@@ -27,6 +27,7 @@ extern void *memcpy(void *__restrict, const void *__restrict, size_t);
 extern void *memset(void *, int, size_t);
 extern void bzero(void *, size_t);
 extern int memcmp(const void *, const void *, size_t);
+extern int bcmp(const void *, const void *, size_t);
 
 } // namespace __llvm_libc
 
@@ -76,6 +77,9 @@ using BenchmarkSetup = SetSetup;
 #elif defined(LIBC_BENCHMARK_FUNCTION_MEMCMP)
 #define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_MEMCMP
 using BenchmarkSetup = ComparisonSetup;
+#elif defined(LIBC_BENCHMARK_FUNCTION_BCMP)
+#define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_BCMP
+using BenchmarkSetup = ComparisonSetup;
 #else
 #error "Missing LIBC_BENCHMARK_FUNCTION_XXX definition"
 #endif
index 055f990..e48b3a7 100644 (file)
@@ -28,6 +28,7 @@ extern void *memcpy(void *__restrict, const void *__restrict, size_t);
 extern void *memset(void *, int, size_t);
 extern void bzero(void *, size_t);
 extern int memcmp(const void *, const void *, size_t);
+extern int bcmp(const void *, const void *, size_t);
 
 } // namespace __llvm_libc
 
@@ -38,6 +39,9 @@ static constexpr MemcpyConfiguration kMemcpyConfigurations[] = {
 static constexpr MemcmpConfiguration kMemcmpConfigurations[] = {
     {__llvm_libc::memcmp, "__llvm_libc::memcmp"}};
 
+static constexpr MemcmpConfiguration kBcmpConfigurations[] = {
+    {__llvm_libc::bcmp, "__llvm_libc::bcmp"}};
+
 static constexpr MemsetConfiguration kMemsetConfigurations[] = {
     {__llvm_libc::memset, "__llvm_libc::memset"}};
 
@@ -116,6 +120,8 @@ BENCHMARK_MEMORY_FUNCTION(BM_Memcpy, CopySetup, MemcpyConfiguration,
                           llvm::makeArrayRef(kMemcpyConfigurations));
 BENCHMARK_MEMORY_FUNCTION(BM_Memcmp, ComparisonSetup, MemcmpConfiguration,
                           llvm::makeArrayRef(kMemcmpConfigurations));
+BENCHMARK_MEMORY_FUNCTION(BM_Bcmp, ComparisonSetup, MemcmpConfiguration,
+                          llvm::makeArrayRef(kBcmpConfigurations));
 BENCHMARK_MEMORY_FUNCTION(BM_Memset, SetSetup, MemsetConfiguration,
                           llvm::makeArrayRef(kMemsetConfigurations));
 BENCHMARK_MEMORY_FUNCTION(BM_Bzero, SetSetup, BzeroConfiguration,
index 21bbaa4..0bb899c 100644 (file)
@@ -21,6 +21,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.errno.__errno_location
 
     # string.h entrypoints
+    libc.src.string.bcmp
     libc.src.string.bzero
     libc.src.string.memchr
     libc.src.string.memcmp
index 6e163c1..e99fb4e 100644 (file)
@@ -21,6 +21,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.errno.__errno_location
 
     # string.h entrypoints
+    libc.src.string.bcmp
     libc.src.string.bzero
     libc.src.string.memchr
     libc.src.string.memcmp
index a70eb18..cffeb2e 100644 (file)
@@ -8,8 +8,21 @@ def LLVMLibcExt : StandardSpec<"llvm_libc_ext"> {
           FunctionSpec<
               "bzero",
               RetValSpec<VoidType>,
-              [ArgSpec<VoidPtr>,
-               ArgSpec<SizeTType>]
+              [ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
+          >,
+      ]
+  >;
+
+  HeaderSpec String = HeaderSpec<
+      "string.h",
+      [], // Macros
+      [], // Types
+      [], // Enumerations
+      [
+          FunctionSpec<
+              "bcmp",
+              RetValSpec<IntType>,
+              [ArgSpec<ConstVoidPtr>, ArgSpec<ConstVoidPtr>, ArgSpec<SizeTType>]
           >,
       ]
   >;
@@ -23,10 +36,7 @@ def LLVMLibcExt : StandardSpec<"llvm_libc_ext"> {
           FunctionSpec<
               "__assert_fail",
               RetValSpec<NoReturn>,
-              [ArgSpec<ConstCharPtr>,
-               ArgSpec<ConstCharPtr>,
-               ArgSpec<UnsignedType>,
-               ArgSpec<ConstCharPtr>,]
+              [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>, ArgSpec<UnsignedType>, ArgSpec<ConstCharPtr>]
 
           >,
       ]
index a7dbac3..e41f0e1 100644 (file)
@@ -331,3 +331,35 @@ else()
   add_memcmp(memcmp_opt_host          COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE})
   add_memcmp(memcmp)
 endif()
+
+# ------------------------------------------------------------------------------
+# bcmp
+# ------------------------------------------------------------------------------
+
+function(add_bcmp bcmp_name)
+  add_implementation(bcmp ${bcmp_name}
+    SRCS ${LIBC_BCMP_SRC}
+    HDRS ${LIBC_SOURCE_DIR}/src/string/bcmp.h
+    DEPENDS
+      .memory_utils.memory_utils
+      libc.include.string
+    COMPILE_OPTIONS
+      -fno-builtin-memcmp
+      -fno-builtin-bcmp
+    ${ARGN}
+  )
+endfunction()
+
+if(${LIBC_TARGET_ARCHITECTURE_IS_X86})
+  set(LIBC_BCMP_SRC ${LIBC_SOURCE_DIR}/src/string/bcmp.cpp)
+  add_bcmp(bcmp_x86_64_opt_sse2   COMPILE_OPTIONS -march=k8             REQUIRE SSE2)
+  add_bcmp(bcmp_x86_64_opt_sse4   COMPILE_OPTIONS -march=nehalem        REQUIRE SSE4_2)
+  add_bcmp(bcmp_x86_64_opt_avx2   COMPILE_OPTIONS -march=haswell        REQUIRE AVX2)
+  add_bcmp(bcmp_x86_64_opt_avx512 COMPILE_OPTIONS -march=skylake-avx512 REQUIRE AVX512F)
+  add_bcmp(bcmp_opt_host          COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE})
+  add_bcmp(bcmp)
+else()
+  set(LIBC_BCMP_SRC ${LIBC_SOURCE_DIR}/src/string/bcmp.cpp)
+  add_bcmp(bcmp_opt_host          COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE})
+  add_bcmp(bcmp)
+endif()
diff --git a/libc/src/string/bcmp.cpp b/libc/src/string/bcmp.cpp
new file mode 100644 (file)
index 0000000..196f327
--- /dev/null
@@ -0,0 +1,27 @@
+//===-- Implementation of bcmp --------------------------------------------===//
+//
+// 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/bcmp.h"
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, bcmp,
+                   (const void *lhs, const void *rhs, size_t count)) {
+  const unsigned char *_lhs = reinterpret_cast<const unsigned char *>(lhs);
+  const unsigned char *_rhs = reinterpret_cast<const unsigned char *>(rhs);
+  for (size_t i = 0; i < count; ++i) {
+    if (_lhs[i] != _rhs[i]) {
+      return 1;
+    }
+  }
+  // count is 0 or _lhs and _rhs are the same.
+  return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/bcmp.h b/libc/src/string/bcmp.h
new file mode 100644 (file)
index 0000000..6503240
--- /dev/null
@@ -0,0 +1,20 @@
+//===-- Implementation header for bzero -------------------------*- 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_BCMP_H
+#define LLVM_LIBC_SRC_STRING_BCMP_H
+
+#include <stddef.h> // size_t
+
+namespace __llvm_libc {
+
+int bcmp(const void *lhs, const void *rhs, size_t count);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_BCMP_H
index ee91210..c8e8812 100644 (file)
@@ -199,4 +199,5 @@ add_libc_multi_impl_test(memcpy SRCS memcpy_test.cpp)
 add_libc_multi_impl_test(memset SRCS memset_test.cpp)
 add_libc_multi_impl_test(bzero SRCS bzero_test.cpp)
 add_libc_multi_impl_test(memcmp SRCS memcmp_test.cpp)
+add_libc_multi_impl_test(bcmp SRCS bcmp_test.cpp)
 add_libc_multi_impl_test(memmove SRCS memmove_test.cpp)
diff --git a/libc/test/src/string/bcmp_test.cpp b/libc/test/src/string/bcmp_test.cpp
new file mode 100644 (file)
index 0000000..7c2353f
--- /dev/null
@@ -0,0 +1,58 @@
+//===-- Unittests for bcmp ------------------------------------------------===//
+//
+// 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/bcmp.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcBcmpTest, CmpZeroByte) {
+  const char *lhs = "ab";
+  const char *rhs = "bc";
+  EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, 0), 0);
+}
+
+TEST(LlvmLibcBcmpTest, LhsRhsAreTheSame) {
+  const char *lhs = "ab";
+  const char *rhs = "ab";
+  EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, 2), 0);
+}
+
+TEST(LlvmLibcBcmpTest, LhsBeforeRhsLexically) {
+  const char *lhs = "ab";
+  const char *rhs = "ac";
+  EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, 2), 1);
+}
+
+TEST(LlvmLibcBcmpTest, LhsAfterRhsLexically) {
+  const char *lhs = "ac";
+  const char *rhs = "ab";
+  EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, 2), 1);
+}
+
+TEST(LlvmLibcBcmpTest, Sweep) {
+  static constexpr size_t kMaxSize = 1024;
+  char lhs[kMaxSize];
+  char rhs[kMaxSize];
+
+  const auto reset = [](char *const ptr) {
+    for (size_t i = 0; i < kMaxSize; ++i)
+      ptr[i] = 'a';
+  };
+
+  reset(lhs);
+  reset(rhs);
+  for (size_t i = 0; i < kMaxSize; ++i)
+    EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, i), 0);
+
+  reset(lhs);
+  reset(rhs);
+  for (size_t i = 0; i < kMaxSize; ++i) {
+    rhs[i] = 'b';
+    EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, kMaxSize), 1);
+    rhs[i] = 'a';
+  }
+}