[libc-commits] [libc] 1b927b6 - [libc] add memmove basic building blocks

Guillaume Chatelet via libc-commits libc-commits at lists.llvm.org
Mon Nov 22 06:32:04 PST 2021


Author: Guillaume Chatelet
Date: 2021-11-22T14:31:56Z
New Revision: 1b927b68b66ef54d5cdc36eeecfe9a006e976f1b

URL: https://github.com/llvm/llvm-project/commit/1b927b68b66ef54d5cdc36eeecfe9a006e976f1b
DIFF: https://github.com/llvm/llvm-project/commit/1b927b68b66ef54d5cdc36eeecfe9a006e976f1b.diff

LOG: [libc] add memmove basic building blocks

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

Added: 
    

Modified: 
    libc/src/string/memory_utils/elements.h
    libc/src/string/memory_utils/elements_x86.h
    libc/test/src/string/memory_utils/elements_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/string/memory_utils/elements.h b/libc/src/string/memory_utils/elements.h
index 119e819958972..ff47f61c7902d 100644
--- a/libc/src/string/memory_utils/elements.h
+++ b/libc/src/string/memory_utils/elements.h
@@ -35,6 +35,15 @@ void Copy(char *__restrict dst, const char *__restrict src, size_t size) {
   Element::Copy(dst, src, size);
 }
 
+// Fixed-size move from 'src' to 'dst'.
+template <typename Element> void Move(char *dst, const char *src) {
+  Element::Move(dst, src);
+}
+// Runtime-size move from 'src' to 'dst'.
+template <typename Element> void Move(char *dst, const char *src, size_t size) {
+  Element::Move(dst, src, size);
+}
+
 // Fixed-size equality between 'lhs' and 'rhs'.
 template <typename Element> bool Equals(const char *lhs, const char *rhs) {
   return Element::Equals(lhs, rhs);
@@ -67,6 +76,9 @@ void SplatSet(char *dst, const unsigned char value, size_t size) {
   Element::SplatSet(dst, value, size);
 }
 
+// Stack placeholder for Move operations.
+template <typename Element> struct Storage { char bytes[Element::kSize]; };
+
 // Fixed-size Higher-Order Operations
 // ----------------------------------
 // - Repeated<Type, ElementCount>: Repeat the operation several times in a row.
@@ -83,6 +95,13 @@ template <typename Element, size_t ElementCount> struct Repeated {
     }
   }
 
+  static void Move(char *dst, const char *src) {
+    const auto Value = Element::Load(src);
+    Repeated<Element, ElementCount - 1>::Move(dst + Element::kSize,
+                                              src + Element::kSize);
+    Element::Store(dst, Value);
+  }
+
   static bool Equals(const char *lhs, const char *rhs) {
     for (size_t i = 0; i < ElementCount; ++i) {
       const size_t offset = i * Element::kSize;
@@ -109,6 +128,20 @@ template <typename Element, size_t ElementCount> struct Repeated {
       Element::SplatSet(dst + offset, value);
     }
   }
+
+  static Storage<Element> Load(const char *ptr) {
+    Storage<Element> value;
+    Copy(reinterpret_cast<char *>(&value), ptr);
+    return value;
+  }
+
+  static void Store(char *ptr, Storage<Element> value) {
+    Copy(ptr, reinterpret_cast<const char *>(&value));
+  }
+};
+
+template <typename Element> struct Repeated<Element, 0> {
+  static void Move(char *dst, const char *src) {}
 };
 
 // Chain the operation of several types.
@@ -124,6 +157,12 @@ template <typename Head, typename... Tail> struct Chained<Head, Tail...> {
     __llvm_libc::Copy<Head>(dst, src);
   }
 
+  static void Move(char *dst, const char *src) {
+    const auto Value = Head::Load(src);
+    Chained<Tail...>::Move(dst + Head::kSize, src + Head::kSize);
+    Head::Store(dst, Value);
+  }
+
   static bool Equals(const char *lhs, const char *rhs) {
     if (!__llvm_libc::Equals<Head>(lhs, rhs))
       return false;
@@ -146,6 +185,7 @@ template <typename Head, typename... Tail> struct Chained<Head, Tail...> {
 template <> struct Chained<> {
   static constexpr size_t kSize = 0;
   static void Copy(char *__restrict dst, const char *__restrict src) {}
+  static void Move(char *dst, const char *src) {}
   static bool Equals(const char *lhs, const char *rhs) { return true; }
   static int ThreeWayCompare(const char *lhs, const char *rhs) { return 0; }
   static void SplatSet(char *dst, const unsigned char value) {}
@@ -166,6 +206,13 @@ struct Overlap {
     ElementB::Copy(dst + kOffset, src + kOffset);
   }
 
+  static void Move(char *dst, const char *src) {
+    const auto ValueA = ElementA::Load(src);
+    const auto ValueB = ElementB::Load(src + kOffset);
+    ElementB::Store(dst + kOffset, ValueB);
+    ElementA::Store(dst, ValueA);
+  }
+
   static bool Equals(const char *lhs, const char *rhs) {
     if (!ElementA::Equals(lhs, rhs))
       return false;
@@ -241,6 +288,14 @@ template <typename T> struct HeadTail {
     Tail<T>::Copy(dst, src, size);
   }
 
+  static void Move(char *dst, const char *src, size_t size) {
+    const size_t offset = Tail<T>::offset(size);
+    const auto HeadValue = T::Load(src);
+    const auto TailValue = T::Load(src + offset);
+    T::Store(dst + offset, TailValue);
+    T::Store(dst, HeadValue);
+  }
+
   static bool Equals(const char *lhs, const char *rhs, size_t size) {
     if (!T::Equals(lhs, rhs))
       return false;
@@ -460,6 +515,16 @@ template <size_t Size> struct Builtin {
 #endif
   }
 
+  static void Move(char *dst, const char *src) {
+#if LLVM_LIBC_HAVE_MEMORY_SANITIZER || LLVM_LIBC_HAVE_ADDRESS_SANITIZER
+    ForLoopMove(dst, src);
+#elif __has_builtin(__builtin_memmove)
+    __builtin_memmove(dst, src, kSize);
+#else
+    ForLoopMove(dst, src);
+#endif
+  }
+
 #if __has_builtin(__builtin_memcmp_inline)
 #define LLVM_LIBC_MEMCMP __builtin_memcmp_inline
 #else
@@ -486,6 +551,11 @@ template <size_t Size> struct Builtin {
     for (size_t i = 0; i < kSize; ++i)
       dst[i] = src[i];
   }
+
+  static void ForLoopMove(char *dst, const char *src) {
+    for (size_t i = 0; i < kSize; ++i)
+      dst[i] = src[i];
+  }
 };
 
 using _1 = Builtin<1>;
@@ -512,6 +582,8 @@ template <typename T> struct Scalar {
     Store(dst, Load(src));
   }
 
+  static void Move(char *dst, const char *src) { Store(dst, Load(src)); }
+
   static bool Equals(const char *lhs, const char *rhs) {
     return Load(lhs) == Load(rhs);
   }
@@ -526,15 +598,17 @@ template <typename T> struct Scalar {
 
   static int ScalarThreeWayCompare(T a, T b);
 
-private:
   static T Load(const char *ptr) {
     T value;
     builtin::Builtin<kSize>::Copy(reinterpret_cast<char *>(&value), ptr);
     return value;
   }
+
   static void Store(char *ptr, T value) {
     builtin::Builtin<kSize>::Copy(ptr, reinterpret_cast<const char *>(&value));
   }
+
+private:
   static T GetSplattedValue(const unsigned char value) {
     return T(~0) / T(0xFF) * T(value);
   }

diff  --git a/libc/src/string/memory_utils/elements_x86.h b/libc/src/string/memory_utils/elements_x86.h
index 3b45275bad9ec..b67569bdd8cf2 100644
--- a/libc/src/string/memory_utils/elements_x86.h
+++ b/libc/src/string/memory_utils/elements_x86.h
@@ -34,6 +34,10 @@ template <typename Base> struct Vector : public Base {
     Base::Store(dst, Base::Load(src));
   }
 
+  static void Move(char *dst, const char *src) {
+    Base::Store(dst, Base::Load(src));
+  }
+
   static bool Equals(const char *a, const char *b) {
     return Base::NotEqualMask(Base::Load(a), Base::Load(b)) == 0;
   }

diff  --git a/libc/test/src/string/memory_utils/elements_test.cpp b/libc/test/src/string/memory_utils/elements_test.cpp
index b081a28470b32..3c269acb28859 100644
--- a/libc/test/src/string/memory_utils/elements_test.cpp
+++ b/libc/test/src/string/memory_utils/elements_test.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/__support/CPP/Array.h"
+#include "src/__support/CPP/ArrayRef.h"
 #include "src/string/memory_utils/elements.h"
 #include "utils/UnitTest/Test.h"
 
@@ -50,11 +51,16 @@ char GetRandomChar() {
   return seed;
 }
 
+void Randomize(cpp::MutableArrayRef<char> buffer) {
+  for (auto &current : buffer)
+    current = GetRandomChar();
+}
+
 template <typename Element> using Buffer = cpp::Array<char, Element::kSize>;
+
 template <typename Element> Buffer<Element> GetRandomBuffer() {
   Buffer<Element> buffer;
-  for (auto &current : buffer)
-    current = GetRandomChar();
+  Randomize(buffer);
   return buffer;
 }
 
@@ -66,6 +72,34 @@ TYPED_TEST(LlvmLibcMemoryElements, Copy, FixedSizeTypes) {
     EXPECT_EQ(Dst[i], buffer[i]);
 }
 
+template <typename T> T Copy(const T &Input) {
+  T Output;
+  for (size_t I = 0; I < Input.size(); ++I)
+    Output[I] = Input[I];
+  return Output;
+}
+
+TYPED_TEST(LlvmLibcMemoryElements, Move, FixedSizeTypes) {
+  constexpr size_t kSize = ParamType::kSize;
+  using LargeBuffer = cpp::Array<char, kSize * 2>;
+  LargeBuffer GroundTruth;
+  Randomize(GroundTruth);
+  // Forward, we move the kSize first bytes from offset 0 to kSize.
+  for (size_t Offset = 0; Offset < kSize; ++Offset) {
+    LargeBuffer Buffer = Copy(GroundTruth);
+    Move<ParamType>(&Buffer[Offset], &Buffer[0]);
+    for (size_t I = 0; I < kSize; ++I)
+      EXPECT_EQ(Buffer[I + Offset], GroundTruth[I]);
+  }
+  // Backward, we move the kSize last bytes from offset 0 to kSize.
+  for (size_t Offset = 0; Offset < kSize; ++Offset) {
+    LargeBuffer Buffer = Copy(GroundTruth);
+    Move<ParamType>(&Buffer[Offset], &Buffer[kSize]);
+    for (size_t I = 0; I < kSize; ++I)
+      EXPECT_EQ(Buffer[I + Offset], GroundTruth[kSize + I]);
+  }
+}
+
 TYPED_TEST(LlvmLibcMemoryElements, Equals, FixedSizeTypes) {
   const auto buffer = GetRandomBuffer<ParamType>();
   EXPECT_TRUE(Equals<ParamType>(buffer.data(), buffer.data()));


        


More information about the libc-commits mailing list