[libc] Add a reasonably optimized version for bcmp
authorGuillaume Chatelet <gchatelet@google.com>
Tue, 30 Nov 2021 10:52:34 +0000 (10:52 +0000)
committerGuillaume Chatelet <gchatelet@google.com>
Tue, 30 Nov 2021 10:52:34 +0000 (10:52 +0000)
This is based on current memcmp implementation.

Differential Revision: https://reviews.llvm.org/D114432

libc/src/string/CMakeLists.txt
libc/src/string/bcmp.cpp
libc/src/string/memory_utils/CMakeLists.txt
libc/src/string/memory_utils/bcmp_implementations.h [new file with mode: 0644]
libc/test/src/string/bcmp_test.cpp

index 2d52b36..9bd1f53 100644 (file)
@@ -271,7 +271,7 @@ endfunction()
 
 function(add_bcmp bcmp_name)
   add_implementation(bcmp ${bcmp_name}
-    SRCS ${LIBC_BCMP_SRC}
+    SRCS ${LIBC_SOURCE_DIR}/src/string/bcmp.cpp
     HDRS ${LIBC_SOURCE_DIR}/src/string/bcmp.h
     DEPENDS
       .memory_utils.memory_utils
@@ -284,7 +284,6 @@ function(add_bcmp bcmp_name)
 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)
@@ -292,7 +291,6 @@ if(${LIBC_TARGET_ARCHITECTURE_IS_X86})
   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()
index 196f327..963a7f5 100644 (file)
@@ -8,20 +8,14 @@
 
 #include "src/string/bcmp.h"
 #include "src/__support/common.h"
+#include "src/string/memory_utils/bcmp_implementations.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;
+  return inline_bcmp(static_cast<const char *>(lhs),
+                     static_cast<const char *>(rhs), count);
 }
 
 } // namespace __llvm_libc
index f2bc09e..51bbff3 100644 (file)
@@ -3,6 +3,10 @@ add_header_library(
   HDRS
     utils.h
     elements.h
+    bcmp_implementations.h
+    memcmp_implementations.h
+    memcpy_implementations.h
+    memset_implementations.h
 )
 
 add_header_library(
diff --git a/libc/src/string/memory_utils/bcmp_implementations.h b/libc/src/string/memory_utils/bcmp_implementations.h
new file mode 100644 (file)
index 0000000..ec94af2
--- /dev/null
@@ -0,0 +1,61 @@
+//===-- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_BCMP_IMPLEMENTATIONS_H
+#define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_BCMP_IMPLEMENTATIONS_H
+
+#include "src/__support/architectures.h"
+#include "src/__support/common.h"
+#include "src/string/memory_utils/elements.h"
+
+#include <stddef.h> // size_t
+
+namespace __llvm_libc {
+
+// Fixed-size difference between 'lhs' and 'rhs'.
+template <typename Element> bool Differs(const char *lhs, const char *rhs) {
+  return !Element::Equals(lhs, rhs);
+}
+// Runtime-size difference between 'lhs' and 'rhs'.
+template <typename Element>
+bool Differs(const char *lhs, const char *rhs, size_t size) {
+  return !Element::Equals(lhs, rhs, size);
+}
+
+static inline int inline_bcmp(const char *lhs, const char *rhs, size_t count) {
+#if defined(LLVM_LIBC_ARCH_X86)
+  using namespace ::__llvm_libc::x86;
+#elif defined(LLVM_LIBC_ARCH_AARCH64)
+  using namespace ::__llvm_libc::aarch64;
+#else
+  using namespace ::__llvm_libc::scalar;
+#endif
+  if (count == 0)
+    return 0;
+  if (count == 1)
+    return Differs<_1>(lhs, rhs);
+  if (count == 2)
+    return Differs<_2>(lhs, rhs);
+  if (count == 3)
+    return Differs<_3>(lhs, rhs);
+  if (count <= 8)
+    return Differs<HeadTail<_4>>(lhs, rhs, count);
+  if (count <= 16)
+    return Differs<HeadTail<_8>>(lhs, rhs, count);
+  if (count <= 32)
+    return Differs<HeadTail<_16>>(lhs, rhs, count);
+  if (count <= 64)
+    return Differs<HeadTail<_32>>(lhs, rhs, count);
+  if (count <= 128)
+    return Differs<HeadTail<_64>>(lhs, rhs, count);
+  return Differs<Align<_32>::Then<Loop<_32>>>(lhs, rhs, count);
+}
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_BCMP_IMPLEMENTATIONS_H
index 7c2353f..dfcad7a 100644 (file)
@@ -24,13 +24,13 @@ TEST(LlvmLibcBcmpTest, LhsRhsAreTheSame) {
 TEST(LlvmLibcBcmpTest, LhsBeforeRhsLexically) {
   const char *lhs = "ab";
   const char *rhs = "ac";
-  EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, 2), 1);
+  EXPECT_NE(__llvm_libc::bcmp(lhs, rhs, 2), 0);
 }
 
 TEST(LlvmLibcBcmpTest, LhsAfterRhsLexically) {
   const char *lhs = "ac";
   const char *rhs = "ab";
-  EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, 2), 1);
+  EXPECT_NE(__llvm_libc::bcmp(lhs, rhs, 2), 0);
 }
 
 TEST(LlvmLibcBcmpTest, Sweep) {
@@ -52,7 +52,7 @@ TEST(LlvmLibcBcmpTest, Sweep) {
   reset(rhs);
   for (size_t i = 0; i < kMaxSize; ++i) {
     rhs[i] = 'b';
-    EXPECT_EQ(__llvm_libc::bcmp(lhs, rhs, kMaxSize), 1);
+    EXPECT_NE(__llvm_libc::bcmp(lhs, rhs, kMaxSize), 0);
     rhs[i] = 'a';
   }
 }