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 ¤t : 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