1 //===-- Implementation using the __builtin_XXX_inline ---------------------===// 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 // 9 // This file provides generic C++ building blocks to compose memory functions. 10 // They rely on the compiler to generate the best possible code through the use 11 // of the `__builtin_XXX_inline` builtins. These builtins are currently only 12 // available in Clang. 13 // 14 //===----------------------------------------------------------------------===// 15 #ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_OP_BUILTIN_H 16 #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_OP_BUILTIN_H 17 18 #include "src/__support/CPP/type_traits.h" 19 #include "src/string/memory_utils/utils.h" 20 21 namespace LIBC_NAMESPACE::builtin { 22 23 /////////////////////////////////////////////////////////////////////////////// 24 // Memcpy 25 template <size_t Size> struct Memcpy { 26 static constexpr size_t SIZE = Size; block_offsetMemcpy27 LIBC_INLINE static void block_offset(Ptr __restrict dst, CPtr __restrict src, 28 size_t offset) { 29 memcpy_inline<Size>(dst + offset, src + offset); 30 } 31 blockMemcpy32 LIBC_INLINE static void block(Ptr __restrict dst, CPtr __restrict src) { 33 block_offset(dst, src, 0); 34 } 35 tailMemcpy36 LIBC_INLINE static void tail(Ptr __restrict dst, CPtr __restrict src, 37 size_t count) { 38 block_offset(dst, src, count - SIZE); 39 } 40 head_tailMemcpy41 LIBC_INLINE static void head_tail(Ptr __restrict dst, CPtr __restrict src, 42 size_t count) { 43 block(dst, src); 44 tail(dst, src, count); 45 } 46 loop_and_tail_offsetMemcpy47 LIBC_INLINE static void loop_and_tail_offset(Ptr __restrict dst, 48 CPtr __restrict src, 49 size_t count, size_t offset) { 50 static_assert(Size > 1, "a loop of size 1 does not need tail"); 51 do { 52 block_offset(dst, src, offset); 53 offset += SIZE; 54 } while (offset < count - SIZE); 55 tail(dst, src, count); 56 } 57 loop_and_tailMemcpy58 LIBC_INLINE static void loop_and_tail(Ptr __restrict dst, CPtr __restrict src, 59 size_t count) { 60 return loop_and_tail_offset(dst, src, count, 0); 61 } 62 }; 63 64 /////////////////////////////////////////////////////////////////////////////// 65 // Memset 66 template <size_t Size> struct Memset { 67 using ME = Memset; 68 static constexpr size_t SIZE = Size; blockMemset69 LIBC_INLINE static void block(Ptr dst, uint8_t value) { 70 #ifdef LLVM_LIBC_HAS_BUILTIN_MEMSET_INLINE 71 __builtin_memset_inline(dst, value, Size); 72 #else 73 static_assert(cpp::always_false<decltype(Size)>, 74 "Missing __builtin_memset_inline"); 75 (void)dst; 76 (void)value; 77 #endif 78 } 79 tailMemset80 LIBC_INLINE static void tail(Ptr dst, uint8_t value, size_t count) { 81 block(dst + count - SIZE, value); 82 } 83 head_tailMemset84 LIBC_INLINE static void head_tail(Ptr dst, uint8_t value, size_t count) { 85 block(dst, value); 86 tail(dst, value, count); 87 } 88 loop_and_tailMemset89 LIBC_INLINE static void loop_and_tail(Ptr dst, uint8_t value, size_t count) { 90 static_assert(Size > 1, "a loop of size 1 does not need tail"); 91 size_t offset = 0; 92 do { 93 block(dst + offset, value); 94 offset += SIZE; 95 } while (offset < count - SIZE); 96 tail(dst, value, count); 97 } 98 }; 99 100 /////////////////////////////////////////////////////////////////////////////// 101 // Bcmp 102 template <size_t Size> struct Bcmp { 103 using ME = Bcmp; 104 static constexpr size_t SIZE = Size; blockBcmp105 LIBC_INLINE static BcmpReturnType block(CPtr, CPtr) { 106 static_assert(cpp::always_false<decltype(Size)>, 107 "Missing __builtin_memcmp_inline"); 108 return BcmpReturnType::zero(); 109 } 110 tailBcmp111 LIBC_INLINE static BcmpReturnType tail(CPtr, CPtr, size_t) { 112 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 113 return BcmpReturnType::zero(); 114 } 115 head_tailBcmp116 LIBC_INLINE static BcmpReturnType head_tail(CPtr, CPtr, size_t) { 117 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 118 return BcmpReturnType::zero(); 119 } 120 loop_and_tailBcmp121 LIBC_INLINE static BcmpReturnType loop_and_tail(CPtr, CPtr, size_t) { 122 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 123 return BcmpReturnType::zero(); 124 } 125 }; 126 127 /////////////////////////////////////////////////////////////////////////////// 128 // Memcmp 129 template <size_t Size> struct Memcmp { 130 using ME = Memcmp; 131 static constexpr size_t SIZE = Size; blockMemcmp132 LIBC_INLINE static MemcmpReturnType block(CPtr, CPtr) { 133 static_assert(cpp::always_false<decltype(Size)>, 134 "Missing __builtin_memcmp_inline"); 135 return MemcmpReturnType::zero(); 136 } 137 tailMemcmp138 LIBC_INLINE static MemcmpReturnType tail(CPtr, CPtr, size_t) { 139 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 140 return MemcmpReturnType::zero(); 141 } 142 head_tailMemcmp143 LIBC_INLINE static MemcmpReturnType head_tail(CPtr, CPtr, size_t) { 144 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 145 return MemcmpReturnType::zero(); 146 } 147 loop_and_tailMemcmp148 LIBC_INLINE static MemcmpReturnType loop_and_tail(CPtr, CPtr, size_t) { 149 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 150 return MemcmpReturnType::zero(); 151 } 152 }; 153 154 } // namespace LIBC_NAMESPACE::builtin 155 156 #endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_OP_BUILTIN_H 157