[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 ¤t : buffer)
+ current = GetRandomChar();
+}
+
template <typename Element> using Buffer = cpp::Array<char, Element::kSize>;
+
template <typename Element> Buffer<Element> GetRandomBuffer() {
Buffer<Element> buffer;
- for (auto ¤t : 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