17f5d7bc8SGuillaume Chatelet #define LLVM_LIBC_USE_BUILTIN_MEMCPY_INLINE 0
2f6f53e99SGuillaume Chatelet #define LLVM_LIBC_USE_BUILTIN_MEMSET_INLINE 0
37f5d7bc8SGuillaume Chatelet 
47f5d7bc8SGuillaume Chatelet #include "utils/UnitTest/Test.h"
57f5d7bc8SGuillaume Chatelet #include <src/__support/CPP/Array.h>
67f5d7bc8SGuillaume Chatelet #include <src/string/memory_utils/algorithm.h>
77f5d7bc8SGuillaume Chatelet #include <src/string/memory_utils/backends.h>
87f5d7bc8SGuillaume Chatelet 
9*98007e97SGuillaume Chatelet #include <sstream>
107f5d7bc8SGuillaume Chatelet 
117f5d7bc8SGuillaume Chatelet namespace __llvm_libc {
127f5d7bc8SGuillaume Chatelet 
137f5d7bc8SGuillaume Chatelet struct alignas(64) Buffer : cpp::Array<char, 128> {
contains__llvm_libc::Buffer147f5d7bc8SGuillaume Chatelet   bool contains(const char *ptr) const {
157f5d7bc8SGuillaume Chatelet     return ptr >= data() && ptr < (data() + size());
167f5d7bc8SGuillaume Chatelet   }
getOffset__llvm_libc::Buffer177f5d7bc8SGuillaume Chatelet   size_t getOffset(const char *ptr) const { return ptr - data(); }
fill__llvm_libc::Buffer187f5d7bc8SGuillaume Chatelet   void fill(char c) {
197f5d7bc8SGuillaume Chatelet     for (auto itr = begin(); itr != end(); ++itr)
207f5d7bc8SGuillaume Chatelet       *itr = c;
217f5d7bc8SGuillaume Chatelet   }
227f5d7bc8SGuillaume Chatelet };
237f5d7bc8SGuillaume Chatelet 
247f5d7bc8SGuillaume Chatelet static Buffer buffer1;
257f5d7bc8SGuillaume Chatelet static Buffer buffer2;
26*98007e97SGuillaume Chatelet static std::ostringstream LOG;
277f5d7bc8SGuillaume Chatelet 
287f5d7bc8SGuillaume Chatelet struct TestBackend {
297f5d7bc8SGuillaume Chatelet   static constexpr bool IS_BACKEND_TYPE = true;
307f5d7bc8SGuillaume Chatelet 
log__llvm_libc::TestBackend317f5d7bc8SGuillaume Chatelet   template <typename T> static void log(const char *Action, const char *ptr) {
327f5d7bc8SGuillaume Chatelet     LOG << Action << "<" << sizeof(T) << "> ";
337f5d7bc8SGuillaume Chatelet     if (buffer1.contains(ptr))
347f5d7bc8SGuillaume Chatelet       LOG << "a[" << buffer1.getOffset(ptr) << "]";
357f5d7bc8SGuillaume Chatelet     else if (buffer2.contains(ptr))
367f5d7bc8SGuillaume Chatelet       LOG << "b[" << buffer2.getOffset(ptr) << "]";
377f5d7bc8SGuillaume Chatelet     LOG << "\n";
387f5d7bc8SGuillaume Chatelet   }
397f5d7bc8SGuillaume Chatelet 
407f5d7bc8SGuillaume Chatelet   template <typename T, Temporality TS, Aligned AS>
load__llvm_libc::TestBackend417f5d7bc8SGuillaume Chatelet   static T load(const T *src) {
427f5d7bc8SGuillaume Chatelet     log<T>((AS == Aligned::YES ? "LdA" : "LdU"),
437f5d7bc8SGuillaume Chatelet            reinterpret_cast<const char *>(src));
447f5d7bc8SGuillaume Chatelet     return Scalar64BitBackend::load<T, TS, AS>(src);
457f5d7bc8SGuillaume Chatelet   }
467f5d7bc8SGuillaume Chatelet 
477f5d7bc8SGuillaume Chatelet   template <typename T, Temporality TS, Aligned AS>
store__llvm_libc::TestBackend487f5d7bc8SGuillaume Chatelet   static void store(T *dst, T value) {
497f5d7bc8SGuillaume Chatelet     log<T>((AS == Aligned::YES ? "StA" : "StU"),
507f5d7bc8SGuillaume Chatelet            reinterpret_cast<const char *>(dst));
517f5d7bc8SGuillaume Chatelet     Scalar64BitBackend::store<T, TS, AS>(dst, value);
527f5d7bc8SGuillaume Chatelet   }
537f5d7bc8SGuillaume Chatelet 
splat__llvm_libc::TestBackend547f5d7bc8SGuillaume Chatelet   template <typename T> static inline T splat(ubyte value) {
557f5d7bc8SGuillaume Chatelet     LOG << "Splat<" << sizeof(T) << "> " << (unsigned)value << '\n';
567f5d7bc8SGuillaume Chatelet     return Scalar64BitBackend::splat<T>(value);
577f5d7bc8SGuillaume Chatelet   }
587f5d7bc8SGuillaume Chatelet 
notEquals__llvm_libc::TestBackend597f5d7bc8SGuillaume Chatelet   template <typename T> static inline uint64_t notEquals(T v1, T v2) {
607f5d7bc8SGuillaume Chatelet     LOG << "Neq<" << sizeof(T) << ">\n";
617f5d7bc8SGuillaume Chatelet     return Scalar64BitBackend::notEquals<T>(v1, v2);
627f5d7bc8SGuillaume Chatelet   }
637f5d7bc8SGuillaume Chatelet 
threeWayCmp__llvm_libc::TestBackend647f5d7bc8SGuillaume Chatelet   template <typename T> static inline int32_t threeWayCmp(T v1, T v2) {
657f5d7bc8SGuillaume Chatelet     LOG << "Diff<" << sizeof(T) << ">\n";
667f5d7bc8SGuillaume Chatelet     return Scalar64BitBackend::threeWayCmp<T>(v1, v2);
677f5d7bc8SGuillaume Chatelet   }
687f5d7bc8SGuillaume Chatelet 
697f5d7bc8SGuillaume Chatelet   template <size_t Size>
707f5d7bc8SGuillaume Chatelet   using getNextType = Scalar64BitBackend::getNextType<Size>;
717f5d7bc8SGuillaume Chatelet };
727f5d7bc8SGuillaume Chatelet 
737f5d7bc8SGuillaume Chatelet struct LlvmLibcAlgorithm : public testing::Test {
SetUp__llvm_libc::LlvmLibcAlgorithm747f5d7bc8SGuillaume Chatelet   void SetUp() override {
75*98007e97SGuillaume Chatelet     LOG = std::ostringstream();
767f5d7bc8SGuillaume Chatelet     LOG << '\n';
777f5d7bc8SGuillaume Chatelet   }
787f5d7bc8SGuillaume Chatelet 
fillEqual__llvm_libc::LlvmLibcAlgorithm797f5d7bc8SGuillaume Chatelet   void fillEqual() {
807f5d7bc8SGuillaume Chatelet     buffer1.fill('a');
817f5d7bc8SGuillaume Chatelet     buffer2.fill('a');
827f5d7bc8SGuillaume Chatelet   }
837f5d7bc8SGuillaume Chatelet 
fillDifferent__llvm_libc::LlvmLibcAlgorithm847f5d7bc8SGuillaume Chatelet   void fillDifferent() {
857f5d7bc8SGuillaume Chatelet     buffer1.fill('a');
867f5d7bc8SGuillaume Chatelet     buffer2.fill('b');
877f5d7bc8SGuillaume Chatelet   }
887f5d7bc8SGuillaume Chatelet 
getTrace__llvm_libc::LlvmLibcAlgorithm897f5d7bc8SGuillaume Chatelet   const char *getTrace() {
907f5d7bc8SGuillaume Chatelet     trace_ = LOG.str();
917f5d7bc8SGuillaume Chatelet     return trace_.c_str();
927f5d7bc8SGuillaume Chatelet   }
937f5d7bc8SGuillaume Chatelet 
stripComments__llvm_libc::LlvmLibcAlgorithm94*98007e97SGuillaume Chatelet   const char *stripComments(const char *expected) {
957f5d7bc8SGuillaume Chatelet     expected_.clear();
96*98007e97SGuillaume Chatelet     std::stringstream ss(expected);
97*98007e97SGuillaume Chatelet     std::string line;
98*98007e97SGuillaume Chatelet     while (std::getline(ss, line, '\n')) {
997f5d7bc8SGuillaume Chatelet       const auto pos = line.find('#');
1007f5d7bc8SGuillaume Chatelet       if (pos == std::string::npos) {
1017f5d7bc8SGuillaume Chatelet         expected_ += line;
1027f5d7bc8SGuillaume Chatelet       } else {
1037f5d7bc8SGuillaume Chatelet         auto log = line.substr(0, pos);
1047f5d7bc8SGuillaume Chatelet         while (!log.empty() && std::isspace(log.back()))
1057f5d7bc8SGuillaume Chatelet           log.pop_back();
1067f5d7bc8SGuillaume Chatelet         expected_ += log;
1077f5d7bc8SGuillaume Chatelet       }
108*98007e97SGuillaume Chatelet       expected_ += '\n';
1097f5d7bc8SGuillaume Chatelet     }
1107f5d7bc8SGuillaume Chatelet     return expected_.c_str();
1117f5d7bc8SGuillaume Chatelet   }
1127f5d7bc8SGuillaume Chatelet 
buf1__llvm_libc::LlvmLibcAlgorithm1137f5d7bc8SGuillaume Chatelet   template <size_t Align = 1> SrcAddr<Align> buf1(size_t offset = 0) const {
1147f5d7bc8SGuillaume Chatelet     return buffer1.data() + offset;
1157f5d7bc8SGuillaume Chatelet   }
buf2__llvm_libc::LlvmLibcAlgorithm1167f5d7bc8SGuillaume Chatelet   template <size_t Align = 1> SrcAddr<Align> buf2(size_t offset = 0) const {
1177f5d7bc8SGuillaume Chatelet     return buffer2.data() + offset;
1187f5d7bc8SGuillaume Chatelet   }
dst__llvm_libc::LlvmLibcAlgorithm1197f5d7bc8SGuillaume Chatelet   template <size_t Align = 1> DstAddr<Align> dst(size_t offset = 0) const {
1207f5d7bc8SGuillaume Chatelet     return buffer1.data() + offset;
1217f5d7bc8SGuillaume Chatelet   }
src__llvm_libc::LlvmLibcAlgorithm1227f5d7bc8SGuillaume Chatelet   template <size_t Align = 1> SrcAddr<Align> src(size_t offset = 0) const {
1237f5d7bc8SGuillaume Chatelet     return buffer2.data() + offset;
1247f5d7bc8SGuillaume Chatelet   }
1257f5d7bc8SGuillaume Chatelet 
1267f5d7bc8SGuillaume Chatelet private:
1277f5d7bc8SGuillaume Chatelet   std::string trace_;
1287f5d7bc8SGuillaume Chatelet   std::string expected_;
1297f5d7bc8SGuillaume Chatelet };
1307f5d7bc8SGuillaume Chatelet 
1317f5d7bc8SGuillaume Chatelet using _8 = SizedOp<TestBackend, 8>;
1327f5d7bc8SGuillaume Chatelet 
1337f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
1347f5d7bc8SGuillaume Chatelet //// Testing fixed fized forward operations
1357f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
1367f5d7bc8SGuillaume Chatelet 
1377f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
1387f5d7bc8SGuillaume Chatelet // Copy
1397f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,copy_1)1407f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, copy_1) {
1417f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 1>::copy(dst(), src());
1427f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
1437f5d7bc8SGuillaume Chatelet LdU<1> b[0]
1447f5d7bc8SGuillaume Chatelet StU<1> a[0]
1457f5d7bc8SGuillaume Chatelet )"));
1467f5d7bc8SGuillaume Chatelet }
1477f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,copy_15)1487f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, copy_15) {
1497f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 15>::copy(dst(), src());
1507f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
1517f5d7bc8SGuillaume Chatelet LdU<8> b[0]
1527f5d7bc8SGuillaume Chatelet StU<8> a[0]
1537f5d7bc8SGuillaume Chatelet LdU<4> b[8]
1547f5d7bc8SGuillaume Chatelet StU<4> a[8]
1557f5d7bc8SGuillaume Chatelet LdU<2> b[12]
1567f5d7bc8SGuillaume Chatelet StU<2> a[12]
1577f5d7bc8SGuillaume Chatelet LdU<1> b[14]
1587f5d7bc8SGuillaume Chatelet StU<1> a[14]
1597f5d7bc8SGuillaume Chatelet )"));
1607f5d7bc8SGuillaume Chatelet }
1617f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,copy_16)1627f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, copy_16) {
1637f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 16>::copy(dst(), src());
1647f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
1657f5d7bc8SGuillaume Chatelet LdU<8> b[0]
1667f5d7bc8SGuillaume Chatelet StU<8> a[0]
1677f5d7bc8SGuillaume Chatelet LdU<8> b[8]
1687f5d7bc8SGuillaume Chatelet StU<8> a[8]
1697f5d7bc8SGuillaume Chatelet )"));
1707f5d7bc8SGuillaume Chatelet }
171f6f53e99SGuillaume Chatelet 
1727f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
1737f5d7bc8SGuillaume Chatelet // Move
1747f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,move_1)1757f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, move_1) {
1767f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 1>::move(dst(), src());
1777f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
1787f5d7bc8SGuillaume Chatelet LdU<1> b[0]
1797f5d7bc8SGuillaume Chatelet StU<1> a[0]
1807f5d7bc8SGuillaume Chatelet )"));
1817f5d7bc8SGuillaume Chatelet }
1827f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,move_15)1837f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, move_15) {
1847f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 15>::move(dst(), src());
1857f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
1867f5d7bc8SGuillaume Chatelet LdU<8> b[0]
1877f5d7bc8SGuillaume Chatelet LdU<4> b[8]
1887f5d7bc8SGuillaume Chatelet LdU<2> b[12]
1897f5d7bc8SGuillaume Chatelet LdU<1> b[14]
1907f5d7bc8SGuillaume Chatelet StU<1> a[14]
1917f5d7bc8SGuillaume Chatelet StU<2> a[12]
1927f5d7bc8SGuillaume Chatelet StU<4> a[8]
1937f5d7bc8SGuillaume Chatelet StU<8> a[0]
1947f5d7bc8SGuillaume Chatelet )"));
1957f5d7bc8SGuillaume Chatelet }
1967f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,move_16)1977f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, move_16) {
1987f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 16>::move(dst(), src());
1997f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2007f5d7bc8SGuillaume Chatelet LdU<8> b[0]
2017f5d7bc8SGuillaume Chatelet LdU<8> b[8]
2027f5d7bc8SGuillaume Chatelet StU<8> a[8]
2037f5d7bc8SGuillaume Chatelet StU<8> a[0]
2047f5d7bc8SGuillaume Chatelet )"));
2057f5d7bc8SGuillaume Chatelet }
2067f5d7bc8SGuillaume Chatelet 
2077f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
2087f5d7bc8SGuillaume Chatelet // set
2097f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,set_1)2107f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, set_1) {
2117f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 1>::set(dst(), ubyte{42});
2127f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2137f5d7bc8SGuillaume Chatelet Splat<1> 42
2147f5d7bc8SGuillaume Chatelet StU<1> a[0]
2157f5d7bc8SGuillaume Chatelet )"));
2167f5d7bc8SGuillaume Chatelet }
2177f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,set_15)2187f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, set_15) {
2197f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 15>::set(dst(), ubyte{42});
2207f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2217f5d7bc8SGuillaume Chatelet Splat<8> 42
2227f5d7bc8SGuillaume Chatelet StU<8> a[0]
2237f5d7bc8SGuillaume Chatelet Splat<4> 42
2247f5d7bc8SGuillaume Chatelet StU<4> a[8]
2257f5d7bc8SGuillaume Chatelet Splat<2> 42
2267f5d7bc8SGuillaume Chatelet StU<2> a[12]
2277f5d7bc8SGuillaume Chatelet Splat<1> 42
2287f5d7bc8SGuillaume Chatelet StU<1> a[14]
2297f5d7bc8SGuillaume Chatelet )"));
2307f5d7bc8SGuillaume Chatelet }
2317f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,set_16)2327f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, set_16) {
2337f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 16>::set(dst(), ubyte{42});
2347f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2357f5d7bc8SGuillaume Chatelet Splat<8> 42
2367f5d7bc8SGuillaume Chatelet StU<8> a[0]
2377f5d7bc8SGuillaume Chatelet Splat<8> 42
2387f5d7bc8SGuillaume Chatelet StU<8> a[8]
2397f5d7bc8SGuillaume Chatelet )"));
2407f5d7bc8SGuillaume Chatelet }
2417f5d7bc8SGuillaume Chatelet 
2427f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
2437f5d7bc8SGuillaume Chatelet // different
2447f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,different_1)2457f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, different_1) {
2467f5d7bc8SGuillaume Chatelet   fillEqual();
2477f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 1>::isDifferent(buf1(), buf2());
2487f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2497f5d7bc8SGuillaume Chatelet LdU<1> a[0]
2507f5d7bc8SGuillaume Chatelet LdU<1> b[0]
2517f5d7bc8SGuillaume Chatelet Neq<1>
2527f5d7bc8SGuillaume Chatelet )"));
2537f5d7bc8SGuillaume Chatelet }
2547f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,different_15)2557f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, different_15) {
2567f5d7bc8SGuillaume Chatelet   fillEqual();
2577f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 15>::isDifferent(buf1(), buf2());
2587f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2597f5d7bc8SGuillaume Chatelet LdU<8> a[0]
2607f5d7bc8SGuillaume Chatelet LdU<8> b[0]
2617f5d7bc8SGuillaume Chatelet Neq<8>
2627f5d7bc8SGuillaume Chatelet LdU<4> a[8]
2637f5d7bc8SGuillaume Chatelet LdU<4> b[8]
2647f5d7bc8SGuillaume Chatelet Neq<4>
2657f5d7bc8SGuillaume Chatelet LdU<2> a[12]
2667f5d7bc8SGuillaume Chatelet LdU<2> b[12]
2677f5d7bc8SGuillaume Chatelet Neq<2>
2687f5d7bc8SGuillaume Chatelet LdU<1> a[14]
2697f5d7bc8SGuillaume Chatelet LdU<1> b[14]
2707f5d7bc8SGuillaume Chatelet Neq<1>
2717f5d7bc8SGuillaume Chatelet )"));
2727f5d7bc8SGuillaume Chatelet }
2737f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,different_15_no_shortcircuit)2747f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, different_15_no_shortcircuit) {
2757f5d7bc8SGuillaume Chatelet   fillDifferent();
2767f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 15>::isDifferent(buf1(), buf2());
2777f5d7bc8SGuillaume Chatelet   // If buffer compare isDifferent we continue to aggregate.
2787f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2797f5d7bc8SGuillaume Chatelet LdU<8> a[0]
2807f5d7bc8SGuillaume Chatelet LdU<8> b[0]
2817f5d7bc8SGuillaume Chatelet Neq<8>
2827f5d7bc8SGuillaume Chatelet LdU<4> a[8]
2837f5d7bc8SGuillaume Chatelet LdU<4> b[8]
2847f5d7bc8SGuillaume Chatelet Neq<4>
2857f5d7bc8SGuillaume Chatelet LdU<2> a[12]
2867f5d7bc8SGuillaume Chatelet LdU<2> b[12]
2877f5d7bc8SGuillaume Chatelet Neq<2>
2887f5d7bc8SGuillaume Chatelet LdU<1> a[14]
2897f5d7bc8SGuillaume Chatelet LdU<1> b[14]
2907f5d7bc8SGuillaume Chatelet Neq<1>
2917f5d7bc8SGuillaume Chatelet )"));
2927f5d7bc8SGuillaume Chatelet }
2937f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,different_16)2947f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, different_16) {
2957f5d7bc8SGuillaume Chatelet   fillEqual();
2967f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 16>::isDifferent(buf1(), buf2());
2977f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
2987f5d7bc8SGuillaume Chatelet LdU<8> a[0]
2997f5d7bc8SGuillaume Chatelet LdU<8> b[0]
3007f5d7bc8SGuillaume Chatelet Neq<8>
3017f5d7bc8SGuillaume Chatelet LdU<8> a[8]
3027f5d7bc8SGuillaume Chatelet LdU<8> b[8]
3037f5d7bc8SGuillaume Chatelet Neq<8>
3047f5d7bc8SGuillaume Chatelet )"));
3057f5d7bc8SGuillaume Chatelet }
3067f5d7bc8SGuillaume Chatelet 
3077f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
3087f5d7bc8SGuillaume Chatelet // three_way_cmp
3097f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,three_way_cmp_eq_1)3107f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, three_way_cmp_eq_1) {
3117f5d7bc8SGuillaume Chatelet   fillEqual();
3127f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 1>::threeWayCmp(buf1(), buf2());
3137f5d7bc8SGuillaume Chatelet   // Buffer compare equal, returning 0 and no call to Diff.
3147f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
3157f5d7bc8SGuillaume Chatelet LdU<1> a[0]
3167f5d7bc8SGuillaume Chatelet LdU<1> b[0]
3177f5d7bc8SGuillaume Chatelet Diff<1>
3187f5d7bc8SGuillaume Chatelet )"));
3197f5d7bc8SGuillaume Chatelet }
3207f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,three_way_cmp_eq_15)3217f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, three_way_cmp_eq_15) {
3227f5d7bc8SGuillaume Chatelet   fillEqual();
3237f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 15>::threeWayCmp(buf1(), buf2());
3247f5d7bc8SGuillaume Chatelet   // Buffer compare equal, returning 0 and no call to Diff.
3257f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
3267f5d7bc8SGuillaume Chatelet LdU<8> a[0]
3277f5d7bc8SGuillaume Chatelet LdU<8> b[0]
3287f5d7bc8SGuillaume Chatelet Diff<8>
3297f5d7bc8SGuillaume Chatelet LdU<4> a[8]
3307f5d7bc8SGuillaume Chatelet LdU<4> b[8]
3317f5d7bc8SGuillaume Chatelet Diff<4>
3327f5d7bc8SGuillaume Chatelet LdU<2> a[12]
3337f5d7bc8SGuillaume Chatelet LdU<2> b[12]
3347f5d7bc8SGuillaume Chatelet Diff<2>
3357f5d7bc8SGuillaume Chatelet LdU<1> a[14]
3367f5d7bc8SGuillaume Chatelet LdU<1> b[14]
3377f5d7bc8SGuillaume Chatelet Diff<1>
3387f5d7bc8SGuillaume Chatelet )"));
3397f5d7bc8SGuillaume Chatelet }
3407f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,three_way_cmp_neq_15_shortcircuit)3417f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, three_way_cmp_neq_15_shortcircuit) {
3427f5d7bc8SGuillaume Chatelet   fillDifferent();
3437f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 16>::threeWayCmp(buf1(), buf2());
3447f5d7bc8SGuillaume Chatelet   // If buffer compare isDifferent we stop early.
3457f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
3467f5d7bc8SGuillaume Chatelet LdU<8> a[0]
3477f5d7bc8SGuillaume Chatelet LdU<8> b[0]
3487f5d7bc8SGuillaume Chatelet Diff<8>
3497f5d7bc8SGuillaume Chatelet )"));
3507f5d7bc8SGuillaume Chatelet }
3517f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,three_way_cmp_eq_16)3527f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, three_way_cmp_eq_16) {
3537f5d7bc8SGuillaume Chatelet   fillEqual();
3547f5d7bc8SGuillaume Chatelet   SizedOp<TestBackend, 16>::threeWayCmp(buf1(), buf2());
3557f5d7bc8SGuillaume Chatelet   // Buffer compare equal, returning 0 and no call to Diff.
3567f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
3577f5d7bc8SGuillaume Chatelet LdU<8> a[0]
3587f5d7bc8SGuillaume Chatelet LdU<8> b[0]
3597f5d7bc8SGuillaume Chatelet Diff<8>
3607f5d7bc8SGuillaume Chatelet LdU<8> a[8]
3617f5d7bc8SGuillaume Chatelet LdU<8> b[8]
3627f5d7bc8SGuillaume Chatelet Diff<8>
3637f5d7bc8SGuillaume Chatelet )"));
3647f5d7bc8SGuillaume Chatelet }
3657f5d7bc8SGuillaume Chatelet 
3667f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
3677f5d7bc8SGuillaume Chatelet //// Testing skip operations
3687f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
3697f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,skip_and_set)3707f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, skip_and_set) {
3717f5d7bc8SGuillaume Chatelet   Skip<11>::Then<SizedOp<TestBackend, 1>>::set(dst(), ubyte{42});
3727f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
3737f5d7bc8SGuillaume Chatelet Splat<1> 42
3747f5d7bc8SGuillaume Chatelet StU<1> a[11]
3757f5d7bc8SGuillaume Chatelet )"));
3767f5d7bc8SGuillaume Chatelet }
3777f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,skip_and_different_1)3787f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, skip_and_different_1) {
3797f5d7bc8SGuillaume Chatelet   Skip<11>::Then<SizedOp<TestBackend, 1>>::isDifferent(buf1(), buf2());
3807f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
3817f5d7bc8SGuillaume Chatelet LdU<1> a[11]
3827f5d7bc8SGuillaume Chatelet LdU<1> b[11]
3837f5d7bc8SGuillaume Chatelet Neq<1>
3847f5d7bc8SGuillaume Chatelet )"));
3857f5d7bc8SGuillaume Chatelet }
3867f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,skip_and_three_way_cmp_8)3877f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, skip_and_three_way_cmp_8) {
3887f5d7bc8SGuillaume Chatelet   Skip<11>::Then<SizedOp<TestBackend, 1>>::threeWayCmp(buf1(), buf2());
3897f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
3907f5d7bc8SGuillaume Chatelet LdU<1> a[11]
3917f5d7bc8SGuillaume Chatelet LdU<1> b[11]
3927f5d7bc8SGuillaume Chatelet Diff<1>
3937f5d7bc8SGuillaume Chatelet )"));
3947f5d7bc8SGuillaume Chatelet }
3957f5d7bc8SGuillaume Chatelet 
3967f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
3977f5d7bc8SGuillaume Chatelet //// Testing tail operations
3987f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
3997f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,tail_copy_8)4007f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, tail_copy_8) {
4017f5d7bc8SGuillaume Chatelet   Tail<_8>::copy(dst(), src(), 16);
4027f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4037f5d7bc8SGuillaume Chatelet LdU<8> b[8]
4047f5d7bc8SGuillaume Chatelet StU<8> a[8]
4057f5d7bc8SGuillaume Chatelet )"));
4067f5d7bc8SGuillaume Chatelet }
4077f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,tail_move_8)4087f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, tail_move_8) {
4097f5d7bc8SGuillaume Chatelet   Tail<_8>::move(dst(), src(), 16);
4107f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4117f5d7bc8SGuillaume Chatelet LdU<8> b[8]
4127f5d7bc8SGuillaume Chatelet StU<8> a[8]
4137f5d7bc8SGuillaume Chatelet )"));
4147f5d7bc8SGuillaume Chatelet }
4157f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,tail_set_8)4167f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, tail_set_8) {
4177f5d7bc8SGuillaume Chatelet   Tail<_8>::set(dst(), ubyte{42}, 16);
4187f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4197f5d7bc8SGuillaume Chatelet Splat<8> 42
4207f5d7bc8SGuillaume Chatelet StU<8> a[8]
4217f5d7bc8SGuillaume Chatelet )"));
4227f5d7bc8SGuillaume Chatelet }
4237f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,tail_different_8)4247f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, tail_different_8) {
4257f5d7bc8SGuillaume Chatelet   fillEqual();
4267f5d7bc8SGuillaume Chatelet   Tail<_8>::isDifferent(buf1(), buf2(), 16);
4277f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4287f5d7bc8SGuillaume Chatelet LdU<8> a[8]
4297f5d7bc8SGuillaume Chatelet LdU<8> b[8]
4307f5d7bc8SGuillaume Chatelet Neq<8>
4317f5d7bc8SGuillaume Chatelet )"));
4327f5d7bc8SGuillaume Chatelet }
4337f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,tail_three_way_cmp_8)4347f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, tail_three_way_cmp_8) {
4357f5d7bc8SGuillaume Chatelet   fillEqual();
4367f5d7bc8SGuillaume Chatelet   Tail<_8>::threeWayCmp(buf1(), buf2(), 16);
4377f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4387f5d7bc8SGuillaume Chatelet LdU<8> a[8]
4397f5d7bc8SGuillaume Chatelet LdU<8> b[8]
4407f5d7bc8SGuillaume Chatelet Diff<8>
4417f5d7bc8SGuillaume Chatelet )"));
4427f5d7bc8SGuillaume Chatelet }
4437f5d7bc8SGuillaume Chatelet 
4447f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
4457f5d7bc8SGuillaume Chatelet //// Testing HeadTail operations
4467f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
4477f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,head_tail_copy_8)4487f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, head_tail_copy_8) {
4497f5d7bc8SGuillaume Chatelet   HeadTail<_8>::copy(dst(), src(), 16);
4507f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4517f5d7bc8SGuillaume Chatelet LdU<8> b[0]
4527f5d7bc8SGuillaume Chatelet StU<8> a[0]
4537f5d7bc8SGuillaume Chatelet LdU<8> b[8]
4547f5d7bc8SGuillaume Chatelet StU<8> a[8]
4557f5d7bc8SGuillaume Chatelet )"));
4567f5d7bc8SGuillaume Chatelet }
4577f5d7bc8SGuillaume Chatelet 
4587f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
4597f5d7bc8SGuillaume Chatelet //// Testing Loop operations
4607f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
4617f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,loop_copy_one_iteration_and_tail)4627f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, loop_copy_one_iteration_and_tail) {
4637f5d7bc8SGuillaume Chatelet   Loop<_8>::copy(dst(), src(), 10);
4647f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4657f5d7bc8SGuillaume Chatelet LdU<8> b[0]
4667f5d7bc8SGuillaume Chatelet StU<8> a[0] # covers 0-7
4677f5d7bc8SGuillaume Chatelet LdU<8> b[2]
4687f5d7bc8SGuillaume Chatelet StU<8> a[2] # covers 2-9
4697f5d7bc8SGuillaume Chatelet )"));
4707f5d7bc8SGuillaume Chatelet }
4717f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,loop_copy_two_iteration_and_tail)4727f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, loop_copy_two_iteration_and_tail) {
4737f5d7bc8SGuillaume Chatelet   Loop<_8>::copy(dst(), src(), 17);
4747f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4757f5d7bc8SGuillaume Chatelet LdU<8> b[0]
4767f5d7bc8SGuillaume Chatelet StU<8> a[0] # covers 0-7
4777f5d7bc8SGuillaume Chatelet LdU<8> b[8]
4787f5d7bc8SGuillaume Chatelet StU<8> a[8] # covers 8-15
4797f5d7bc8SGuillaume Chatelet LdU<8> b[9]
4807f5d7bc8SGuillaume Chatelet StU<8> a[9] # covers 9-16
4817f5d7bc8SGuillaume Chatelet )"));
4827f5d7bc8SGuillaume Chatelet }
4837f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,loop_with_one_turn_is_inefficient_but_ok)4847f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, loop_with_one_turn_is_inefficient_but_ok) {
4857f5d7bc8SGuillaume Chatelet   Loop<_8>::copy(dst(), src(), 8);
4867f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4877f5d7bc8SGuillaume Chatelet LdU<8> b[0]
4887f5d7bc8SGuillaume Chatelet StU<8> a[0] # first iteration covers 0-7
4897f5d7bc8SGuillaume Chatelet LdU<8> b[0] # tail also covers 0-7 but since Loop is supposed to be used
4907f5d7bc8SGuillaume Chatelet StU<8> a[0] # with a sufficient number of iterations the tail cost is amortised
4917f5d7bc8SGuillaume Chatelet )"));
4927f5d7bc8SGuillaume Chatelet }
4937f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,loop_with_round_number_of_turn)4947f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, loop_with_round_number_of_turn) {
4957f5d7bc8SGuillaume Chatelet   Loop<_8>::copy(dst(), src(), 24);
4967f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
4977f5d7bc8SGuillaume Chatelet LdU<8> b[0]
4987f5d7bc8SGuillaume Chatelet StU<8> a[0] # first iteration covers 0-7
4997f5d7bc8SGuillaume Chatelet LdU<8> b[8]
5007f5d7bc8SGuillaume Chatelet StU<8> a[8] # second iteration covers 8-15
5017f5d7bc8SGuillaume Chatelet LdU<8> b[16]
5027f5d7bc8SGuillaume Chatelet StU<8> a[16]
5037f5d7bc8SGuillaume Chatelet )"));
5047f5d7bc8SGuillaume Chatelet }
5057f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,dst_aligned_loop)5067f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, dst_aligned_loop) {
5077f5d7bc8SGuillaume Chatelet   Loop<_8>::copy(dst<16>(), src(), 23);
5087f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
5097f5d7bc8SGuillaume Chatelet LdU<8> b[0]
5107f5d7bc8SGuillaume Chatelet StA<8> a[0] # store is aligned on 16B
5117f5d7bc8SGuillaume Chatelet LdU<8> b[8]
5127f5d7bc8SGuillaume Chatelet StA<8> a[8] # subsequent stores are aligned
5137f5d7bc8SGuillaume Chatelet LdU<8> b[15]
5147f5d7bc8SGuillaume Chatelet StU<8> a[15] # Tail is always unaligned
5157f5d7bc8SGuillaume Chatelet )"));
5167f5d7bc8SGuillaume Chatelet }
5177f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,aligned_loop)5187f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, aligned_loop) {
5197f5d7bc8SGuillaume Chatelet   Loop<_8>::copy(dst<16>(), src<8>(), 23);
5207f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
5217f5d7bc8SGuillaume Chatelet LdA<8> b[0] # load is aligned on 8B
5227f5d7bc8SGuillaume Chatelet StA<8> a[0] # store is aligned on 16B
5237f5d7bc8SGuillaume Chatelet LdA<8> b[8] # subsequent loads are aligned
5247f5d7bc8SGuillaume Chatelet StA<8> a[8] # subsequent stores are aligned
5257f5d7bc8SGuillaume Chatelet LdU<8> b[15] # Tail is always unaligned
5267f5d7bc8SGuillaume Chatelet StU<8> a[15] # Tail is always unaligned
5277f5d7bc8SGuillaume Chatelet )"));
5287f5d7bc8SGuillaume Chatelet }
5297f5d7bc8SGuillaume Chatelet 
5307f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
5317f5d7bc8SGuillaume Chatelet //// Testing Align operations
5327f5d7bc8SGuillaume Chatelet ///////////////////////////////////////////////////////////////////////////////
5337f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,align_dst_copy_8)5347f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, align_dst_copy_8) {
5357f5d7bc8SGuillaume Chatelet   Align<_8, Arg::Dst>::Then<Loop<_8>>::copy(dst(2), src(3), 31);
5367f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
5377f5d7bc8SGuillaume Chatelet LdU<8> b[3]
5387f5d7bc8SGuillaume Chatelet StU<8> a[2] # First store covers unaligned bytes
5397f5d7bc8SGuillaume Chatelet LdU<8> b[9]
5407f5d7bc8SGuillaume Chatelet StA<8> a[8] # First aligned store
5417f5d7bc8SGuillaume Chatelet LdU<8> b[17]
5427f5d7bc8SGuillaume Chatelet StA<8> a[16] # Subsequent stores are aligned
5437f5d7bc8SGuillaume Chatelet LdU<8> b[25]
5447f5d7bc8SGuillaume Chatelet StA<8> a[24] # Subsequent stores are aligned
5457f5d7bc8SGuillaume Chatelet LdU<8> b[26]
5467f5d7bc8SGuillaume Chatelet StU<8> a[25] # Last store covers remaining bytes
5477f5d7bc8SGuillaume Chatelet )"));
5487f5d7bc8SGuillaume Chatelet }
5497f5d7bc8SGuillaume Chatelet 
TEST_F(LlvmLibcAlgorithm,align_src_copy_8)5507f5d7bc8SGuillaume Chatelet TEST_F(LlvmLibcAlgorithm, align_src_copy_8) {
5517f5d7bc8SGuillaume Chatelet   Align<_8, Arg::Src>::Then<Loop<_8>>::copy(dst(2), src(3), 31);
5527f5d7bc8SGuillaume Chatelet   EXPECT_STREQ(getTrace(), stripComments(R"(
5537f5d7bc8SGuillaume Chatelet LdU<8> b[3] # First load covers unaligned bytes
5547f5d7bc8SGuillaume Chatelet StU<8> a[2]
5557f5d7bc8SGuillaume Chatelet LdA<8> b[8] # First aligned load
5567f5d7bc8SGuillaume Chatelet StU<8> a[7]
5577f5d7bc8SGuillaume Chatelet LdA<8> b[16] # Subsequent loads are aligned
5587f5d7bc8SGuillaume Chatelet StU<8> a[15]
5597f5d7bc8SGuillaume Chatelet LdA<8> b[24] # Subsequent loads are aligned
5607f5d7bc8SGuillaume Chatelet StU<8> a[23]
5617f5d7bc8SGuillaume Chatelet LdU<8> b[26] # Last load covers remaining bytes
5627f5d7bc8SGuillaume Chatelet StU<8> a[25]
5637f5d7bc8SGuillaume Chatelet )"));
5647f5d7bc8SGuillaume Chatelet }
5657f5d7bc8SGuillaume Chatelet 
5667f5d7bc8SGuillaume Chatelet } // namespace __llvm_libc
567