167fe3bd3SGuillaume Chatelet //===-- Unittests for backends --------------------------------------------===//
267fe3bd3SGuillaume Chatelet //
367fe3bd3SGuillaume Chatelet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
467fe3bd3SGuillaume Chatelet // See https://llvm.org/LICENSE.txt for license information.
567fe3bd3SGuillaume Chatelet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
667fe3bd3SGuillaume Chatelet //
767fe3bd3SGuillaume Chatelet //===----------------------------------------------------------------------===//
867fe3bd3SGuillaume Chatelet 
967fe3bd3SGuillaume Chatelet #include "src/__support/CPP/Array.h"
1067fe3bd3SGuillaume Chatelet #include "src/__support/CPP/ArrayRef.h"
1167fe3bd3SGuillaume Chatelet #include "src/__support/CPP/Bit.h"
1267fe3bd3SGuillaume Chatelet #include "src/__support/architectures.h"
1367fe3bd3SGuillaume Chatelet #include "src/string/memory_utils/backends.h"
1467fe3bd3SGuillaume Chatelet #include "utils/UnitTest/Test.h"
1567fe3bd3SGuillaume Chatelet #include <string.h>
1667fe3bd3SGuillaume Chatelet 
1767fe3bd3SGuillaume Chatelet namespace __llvm_libc {
1867fe3bd3SGuillaume Chatelet 
1967fe3bd3SGuillaume Chatelet template <size_t Size> using Buffer = cpp::Array<char, Size>;
2067fe3bd3SGuillaume Chatelet 
GetRandomChar()2167fe3bd3SGuillaume Chatelet static char GetRandomChar() {
2267fe3bd3SGuillaume Chatelet   // Implementation of C++ minstd_rand seeded with 123456789.
2367fe3bd3SGuillaume Chatelet   // https://en.cppreference.com/w/cpp/numeric/random
2467fe3bd3SGuillaume Chatelet   // "Minimum standard", recommended by Park, Miller, and Stockmeyer in 1993
2567fe3bd3SGuillaume Chatelet   static constexpr const uint64_t a = 48271;
2667fe3bd3SGuillaume Chatelet   static constexpr const uint64_t c = 0;
2767fe3bd3SGuillaume Chatelet   static constexpr const uint64_t m = 2147483647;
2867fe3bd3SGuillaume Chatelet   static uint64_t seed = 123456789;
2967fe3bd3SGuillaume Chatelet   seed = (a * seed + c) % m;
3067fe3bd3SGuillaume Chatelet   return seed;
3167fe3bd3SGuillaume Chatelet }
3267fe3bd3SGuillaume Chatelet 
Randomize(cpp::MutableArrayRef<char> buffer)3367fe3bd3SGuillaume Chatelet static void Randomize(cpp::MutableArrayRef<char> buffer) {
3467fe3bd3SGuillaume Chatelet   for (auto &current : buffer)
3567fe3bd3SGuillaume Chatelet     current = GetRandomChar();
3667fe3bd3SGuillaume Chatelet }
3767fe3bd3SGuillaume Chatelet 
GetRandomBuffer()3867fe3bd3SGuillaume Chatelet template <size_t Size> static Buffer<Size> GetRandomBuffer() {
3967fe3bd3SGuillaume Chatelet   Buffer<Size> buffer;
4067fe3bd3SGuillaume Chatelet   Randomize(buffer);
4167fe3bd3SGuillaume Chatelet   return buffer;
4267fe3bd3SGuillaume Chatelet }
4367fe3bd3SGuillaume Chatelet 
4467fe3bd3SGuillaume Chatelet template <typename Backend, size_t Size> struct Conf {
4567fe3bd3SGuillaume Chatelet   static_assert(Backend::IS_BACKEND_TYPE);
4667fe3bd3SGuillaume Chatelet   using BufferT = Buffer<Size>;
4767fe3bd3SGuillaume Chatelet   using T = typename Backend::template getNextType<Size>;
4867fe3bd3SGuillaume Chatelet   static_assert(sizeof(T) == Size);
4967fe3bd3SGuillaume Chatelet   static constexpr size_t SIZE = Size;
5067fe3bd3SGuillaume Chatelet 
splat__llvm_libc::Conf5167fe3bd3SGuillaume Chatelet   static BufferT splat(ubyte value) {
5267fe3bd3SGuillaume Chatelet     return bit_cast<BufferT>(Backend::template splat<T>(value));
5367fe3bd3SGuillaume Chatelet   }
5467fe3bd3SGuillaume Chatelet 
notEquals__llvm_libc::Conf5567fe3bd3SGuillaume Chatelet   static uint64_t notEquals(const BufferT &v1, const BufferT &v2) {
5667fe3bd3SGuillaume Chatelet     return Backend::template notEquals<T>(bit_cast<T>(v1), bit_cast<T>(v2));
5767fe3bd3SGuillaume Chatelet   }
5867fe3bd3SGuillaume Chatelet 
threeWayCmp__llvm_libc::Conf5967fe3bd3SGuillaume Chatelet   static int32_t threeWayCmp(const BufferT &v1, const BufferT &v2) {
6067fe3bd3SGuillaume Chatelet     return Backend::template threeWayCmp<T>(bit_cast<T>(v1), bit_cast<T>(v2));
6167fe3bd3SGuillaume Chatelet   }
6267fe3bd3SGuillaume Chatelet };
6367fe3bd3SGuillaume Chatelet 
6467fe3bd3SGuillaume Chatelet using FunctionTypes = testing::TypeList< //
6567fe3bd3SGuillaume Chatelet #if defined(LLVM_LIBC_ARCH_X86)          //
6667fe3bd3SGuillaume Chatelet     Conf<X86Backend, 1>,                 //
6767fe3bd3SGuillaume Chatelet     Conf<X86Backend, 2>,                 //
6867fe3bd3SGuillaume Chatelet     Conf<X86Backend, 4>,                 //
6967fe3bd3SGuillaume Chatelet     Conf<X86Backend, 8>,                 //
7067fe3bd3SGuillaume Chatelet #if HAS_M128
7167fe3bd3SGuillaume Chatelet     Conf<X86Backend, 16>, //
7267fe3bd3SGuillaume Chatelet #endif
7367fe3bd3SGuillaume Chatelet #if HAS_M256
7467fe3bd3SGuillaume Chatelet     Conf<X86Backend, 32>, //
7567fe3bd3SGuillaume Chatelet #endif
7667fe3bd3SGuillaume Chatelet #if HAS_M512
7767fe3bd3SGuillaume Chatelet     Conf<X86Backend, 64>, //
7867fe3bd3SGuillaume Chatelet #endif
7967fe3bd3SGuillaume Chatelet #endif                           // defined(LLVM_LIBC_ARCH_X86)
8067fe3bd3SGuillaume Chatelet     Conf<Scalar64BitBackend, 1>, //
8167fe3bd3SGuillaume Chatelet     Conf<Scalar64BitBackend, 2>, //
8267fe3bd3SGuillaume Chatelet     Conf<Scalar64BitBackend, 4>, //
8367fe3bd3SGuillaume Chatelet     Conf<Scalar64BitBackend, 8>  //
8467fe3bd3SGuillaume Chatelet     >;
8567fe3bd3SGuillaume Chatelet 
TYPED_TEST(LlvmLibcMemoryBackend,splat,FunctionTypes)8667fe3bd3SGuillaume Chatelet TYPED_TEST(LlvmLibcMemoryBackend, splat, FunctionTypes) {
8767fe3bd3SGuillaume Chatelet   for (auto value : cpp::Array<uint8_t, 3>{0u, 1u, 255u}) {
8867fe3bd3SGuillaume Chatelet     alignas(64) const auto stored = ParamType::splat(bit_cast<ubyte>(value));
8967fe3bd3SGuillaume Chatelet     for (size_t i = 0; i < ParamType::SIZE; ++i)
9067fe3bd3SGuillaume Chatelet       EXPECT_EQ(bit_cast<uint8_t>(stored[i]), value);
9167fe3bd3SGuillaume Chatelet   }
9267fe3bd3SGuillaume Chatelet }
9367fe3bd3SGuillaume Chatelet 
TYPED_TEST(LlvmLibcMemoryBackend,notEquals,FunctionTypes)9467fe3bd3SGuillaume Chatelet TYPED_TEST(LlvmLibcMemoryBackend, notEquals, FunctionTypes) {
9567fe3bd3SGuillaume Chatelet   alignas(64) const auto a = GetRandomBuffer<ParamType::SIZE>();
96*a83034efSSiva Chandra Reddy   EXPECT_EQ(ParamType::notEquals(a, a), uint64_t(0));
9767fe3bd3SGuillaume Chatelet   for (size_t i = 0; i < a.size(); ++i) {
9867fe3bd3SGuillaume Chatelet     alignas(64) auto b = a;
9967fe3bd3SGuillaume Chatelet     ++b[i];
100*a83034efSSiva Chandra Reddy     EXPECT_NE(ParamType::notEquals(a, b), uint64_t(0));
101*a83034efSSiva Chandra Reddy     EXPECT_NE(ParamType::notEquals(b, a), uint64_t(0));
10267fe3bd3SGuillaume Chatelet   }
10367fe3bd3SGuillaume Chatelet }
10467fe3bd3SGuillaume Chatelet 
TYPED_TEST(LlvmLibcMemoryBackend,threeWayCmp,FunctionTypes)10567fe3bd3SGuillaume Chatelet TYPED_TEST(LlvmLibcMemoryBackend, threeWayCmp, FunctionTypes) {
10667fe3bd3SGuillaume Chatelet   alignas(64) const auto a = GetRandomBuffer<ParamType::SIZE>();
10767fe3bd3SGuillaume Chatelet   EXPECT_EQ(ParamType::threeWayCmp(a, a), 0);
10867fe3bd3SGuillaume Chatelet   for (size_t i = 0; i < a.size(); ++i) {
10967fe3bd3SGuillaume Chatelet     alignas(64) auto b = a;
11067fe3bd3SGuillaume Chatelet     ++b[i];
11167fe3bd3SGuillaume Chatelet     const auto cmp = memcmp(&a, &b, sizeof(a));
11267fe3bd3SGuillaume Chatelet     ASSERT_NE(cmp, 0);
11367fe3bd3SGuillaume Chatelet     if (cmp > 0) {
11467fe3bd3SGuillaume Chatelet       EXPECT_GT(ParamType::threeWayCmp(a, b), 0);
11567fe3bd3SGuillaume Chatelet       EXPECT_LT(ParamType::threeWayCmp(b, a), 0);
11667fe3bd3SGuillaume Chatelet     } else {
11767fe3bd3SGuillaume Chatelet       EXPECT_LT(ParamType::threeWayCmp(a, b), 0);
11867fe3bd3SGuillaume Chatelet       EXPECT_GT(ParamType::threeWayCmp(b, a), 0);
11967fe3bd3SGuillaume Chatelet     }
12067fe3bd3SGuillaume Chatelet   }
12167fe3bd3SGuillaume Chatelet }
12267fe3bd3SGuillaume Chatelet 
12367fe3bd3SGuillaume Chatelet template <typename Backend, size_t Size, Temporality TS, Aligned AS>
12467fe3bd3SGuillaume Chatelet struct LoadStoreConf {
12567fe3bd3SGuillaume Chatelet   static_assert(Backend::IS_BACKEND_TYPE);
12667fe3bd3SGuillaume Chatelet   using BufferT = Buffer<Size>;
12767fe3bd3SGuillaume Chatelet   using T = typename Backend::template getNextType<Size>;
12867fe3bd3SGuillaume Chatelet   static_assert(sizeof(T) == Size);
12967fe3bd3SGuillaume Chatelet   static constexpr size_t SIZE = Size;
13067fe3bd3SGuillaume Chatelet 
load__llvm_libc::LoadStoreConf13167fe3bd3SGuillaume Chatelet   static BufferT load(const BufferT &ref) {
13267fe3bd3SGuillaume Chatelet     const auto *ptr = bit_cast<const T *>(ref.data());
13367fe3bd3SGuillaume Chatelet     const T value = Backend::template load<T, TS, AS>(ptr);
13467fe3bd3SGuillaume Chatelet     return bit_cast<BufferT>(value);
13567fe3bd3SGuillaume Chatelet   }
13667fe3bd3SGuillaume Chatelet 
store__llvm_libc::LoadStoreConf13767fe3bd3SGuillaume Chatelet   static void store(BufferT &ref, const BufferT value) {
13867fe3bd3SGuillaume Chatelet     auto *ptr = bit_cast<T *>(ref.data());
13967fe3bd3SGuillaume Chatelet     Backend::template store<T, TS, AS>(ptr, bit_cast<T>(value));
14067fe3bd3SGuillaume Chatelet   }
14167fe3bd3SGuillaume Chatelet };
14267fe3bd3SGuillaume Chatelet 
14367fe3bd3SGuillaume Chatelet using LoadStoreTypes = testing::TypeList<                              //
14467fe3bd3SGuillaume Chatelet #if defined(LLVM_LIBC_ARCH_X86)                                        //
14567fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 1, Temporality::TEMPORAL, Aligned::NO>,  //
14667fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 1, Temporality::TEMPORAL, Aligned::YES>, //
14767fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 2, Temporality::TEMPORAL, Aligned::NO>,  //
14867fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 2, Temporality::TEMPORAL, Aligned::YES>, //
14967fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 4, Temporality::TEMPORAL, Aligned::NO>,  //
15067fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 4, Temporality::TEMPORAL, Aligned::YES>, //
15167fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 8, Temporality::TEMPORAL, Aligned::NO>,  //
15267fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 8, Temporality::TEMPORAL, Aligned::YES>, //
15367fe3bd3SGuillaume Chatelet #if HAS_M128
15467fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 16, Temporality::TEMPORAL, Aligned::NO>,      //
15567fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 16, Temporality::TEMPORAL, Aligned::YES>,     //
15667fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 16, Temporality::NON_TEMPORAL, Aligned::YES>, //
15767fe3bd3SGuillaume Chatelet #endif
15867fe3bd3SGuillaume Chatelet #if HAS_M256
15967fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 32, Temporality::TEMPORAL, Aligned::NO>,      //
16067fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 32, Temporality::TEMPORAL, Aligned::YES>,     //
16167fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 32, Temporality::NON_TEMPORAL, Aligned::YES>, //
16267fe3bd3SGuillaume Chatelet #endif
16367fe3bd3SGuillaume Chatelet #if HAS_M512
16467fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 64, Temporality::TEMPORAL, Aligned::NO>,      //
16567fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 64, Temporality::TEMPORAL, Aligned::YES>,     //
16667fe3bd3SGuillaume Chatelet     LoadStoreConf<X86Backend, 64, Temporality::NON_TEMPORAL, Aligned::YES>, //
16767fe3bd3SGuillaume Chatelet #endif
16867fe3bd3SGuillaume Chatelet #endif // defined(LLVM_LIBC_ARCH_X86)
16967fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 1, Temporality::TEMPORAL, Aligned::NO>, //
17067fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 1, Temporality::TEMPORAL,
17167fe3bd3SGuillaume Chatelet                   Aligned::YES>,                                              //
17267fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 2, Temporality::TEMPORAL, Aligned::NO>, //
17367fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 2, Temporality::TEMPORAL,
17467fe3bd3SGuillaume Chatelet                   Aligned::YES>,                                              //
17567fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 4, Temporality::TEMPORAL, Aligned::NO>, //
17667fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 4, Temporality::TEMPORAL,
17767fe3bd3SGuillaume Chatelet                   Aligned::YES>,                                              //
17867fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 8, Temporality::TEMPORAL, Aligned::NO>, //
17967fe3bd3SGuillaume Chatelet     LoadStoreConf<Scalar64BitBackend, 8, Temporality::TEMPORAL, Aligned::YES> //
18067fe3bd3SGuillaume Chatelet     >;
18167fe3bd3SGuillaume Chatelet 
TYPED_TEST(LlvmLibcMemoryBackend,load,LoadStoreTypes)18267fe3bd3SGuillaume Chatelet TYPED_TEST(LlvmLibcMemoryBackend, load, LoadStoreTypes) {
18367fe3bd3SGuillaume Chatelet   alignas(64) const auto expected = GetRandomBuffer<ParamType::SIZE>();
18467fe3bd3SGuillaume Chatelet   const auto loaded = ParamType::load(expected);
18567fe3bd3SGuillaume Chatelet   for (size_t i = 0; i < ParamType::SIZE; ++i)
18667fe3bd3SGuillaume Chatelet     EXPECT_EQ(loaded[i], expected[i]);
18767fe3bd3SGuillaume Chatelet }
18867fe3bd3SGuillaume Chatelet 
TYPED_TEST(LlvmLibcMemoryBackend,store,LoadStoreTypes)18967fe3bd3SGuillaume Chatelet TYPED_TEST(LlvmLibcMemoryBackend, store, LoadStoreTypes) {
19067fe3bd3SGuillaume Chatelet   alignas(64) const auto expected = GetRandomBuffer<ParamType::SIZE>();
19167fe3bd3SGuillaume Chatelet   alignas(64) typename ParamType::BufferT stored;
19267fe3bd3SGuillaume Chatelet   ParamType::store(stored, expected);
19367fe3bd3SGuillaume Chatelet   for (size_t i = 0; i < ParamType::SIZE; ++i)
19467fe3bd3SGuillaume Chatelet     EXPECT_EQ(stored[i], expected[i]);
19567fe3bd3SGuillaume Chatelet }
19667fe3bd3SGuillaume Chatelet 
19767fe3bd3SGuillaume Chatelet } // namespace __llvm_libc
198