1 //===-- Elementary operations for native scalar types ---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_BACKEND_SCALAR_H 9 #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_BACKEND_SCALAR_H 10 11 #include "src/__support/CPP/TypeTraits.h" // ConditionalType, EnableIfType 12 #include "src/__support/endian.h" 13 14 namespace __llvm_libc { 15 16 struct Scalar64BitBackend { 17 static constexpr bool IS_BACKEND_TYPE = true; 18 19 template <typename T> 20 static constexpr bool IsScalarType = 21 cpp::IsSameV<T, uint8_t> || cpp::IsSameV<T, uint16_t> || 22 cpp::IsSameV<T, uint32_t> || cpp::IsSameV<T, uint64_t>; 23 24 template <typename T, Temporality TS, Aligned AS> loadScalar64BitBackend25 static inline T load(const T *src) { 26 static_assert(IsScalarType<T>); 27 static_assert(TS == Temporality::TEMPORAL, 28 "Scalar load does not support non-temporal access"); 29 return *src; 30 } 31 32 template <typename T, Temporality TS, Aligned AS> storeScalar64BitBackend33 static inline void store(T *dst, T value) { 34 static_assert(IsScalarType<T>); 35 static_assert(TS == Temporality::TEMPORAL, 36 "Scalar store does not support non-temporal access"); 37 *dst = value; 38 } 39 splatScalar64BitBackend40 template <typename T> static inline T splat(ubyte value) { 41 static_assert(IsScalarType<T>); 42 return (T(~0ULL) / T(0xFF)) * T(value); 43 } 44 notEqualsScalar64BitBackend45 template <typename T> static inline uint64_t notEquals(T v1, T v2) { 46 static_assert(IsScalarType<T>); 47 return v1 ^ v2; 48 } 49 threeWayCmpScalar64BitBackend50 template <typename T> static inline int32_t threeWayCmp(T v1, T v2) { 51 DeferredStaticAssert("not implemented"); 52 } 53 54 // Returns the type to use to consume Size bytes. 55 template <size_t Size> 56 using getNextType = cpp::ConditionalType< 57 Size >= 8, uint64_t, 58 cpp::ConditionalType<Size >= 4, uint32_t, 59 cpp::ConditionalType<Size >= 2, uint16_t, uint8_t>>>; 60 }; 61 62 template <> 63 int32_t inline Scalar64BitBackend::threeWayCmp<uint8_t>(uint8_t a, uint8_t b) { 64 const int16_t la = Endian::to_big_endian(a); 65 const int16_t lb = Endian::to_big_endian(b); 66 return la - lb; 67 } 68 template <> 69 int32_t inline Scalar64BitBackend::threeWayCmp<uint16_t>(uint16_t a, 70 uint16_t b) { 71 const int32_t la = Endian::to_big_endian(a); 72 const int32_t lb = Endian::to_big_endian(b); 73 return la - lb; 74 } 75 template <> 76 int32_t inline Scalar64BitBackend::threeWayCmp<uint32_t>(uint32_t a, 77 uint32_t b) { 78 const uint32_t la = Endian::to_big_endian(a); 79 const uint32_t lb = Endian::to_big_endian(b); 80 return la > lb ? 1 : la < lb ? -1 : 0; 81 } 82 template <> 83 int32_t inline Scalar64BitBackend::threeWayCmp<uint64_t>(uint64_t a, 84 uint64_t b) { 85 const uint64_t la = Endian::to_big_endian(a); 86 const uint64_t lb = Endian::to_big_endian(b); 87 return la > lb ? 1 : la < lb ? -1 : 0; 88 } 89 90 namespace scalar { 91 using _1 = SizedOp<Scalar64BitBackend, 1>; 92 using _2 = SizedOp<Scalar64BitBackend, 2>; 93 using _3 = SizedOp<Scalar64BitBackend, 3>; 94 using _4 = SizedOp<Scalar64BitBackend, 4>; 95 using _8 = SizedOp<Scalar64BitBackend, 8>; 96 using _16 = SizedOp<Scalar64BitBackend, 16>; 97 using _32 = SizedOp<Scalar64BitBackend, 32>; 98 using _64 = SizedOp<Scalar64BitBackend, 64>; 99 using _128 = SizedOp<Scalar64BitBackend, 128>; 100 } // namespace scalar 101 102 } // namespace __llvm_libc 103 104 #endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_BACKEND_SCALAR_H 105