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/__support/macros/config.h" 20 #include "src/string/memory_utils/utils.h" 21 22 namespace LIBC_NAMESPACE_DECL { 23 namespace builtin { 24 25 /////////////////////////////////////////////////////////////////////////////// 26 // Memcpy 27 template <size_t Size> struct Memcpy { 28 static constexpr size_t SIZE = Size; block_offsetMemcpy29 LIBC_INLINE static void block_offset(Ptr __restrict dst, CPtr __restrict src, 30 size_t offset) { 31 memcpy_inline<Size>(dst + offset, src + offset); 32 } 33 blockMemcpy34 LIBC_INLINE static void block(Ptr __restrict dst, CPtr __restrict src) { 35 block_offset(dst, src, 0); 36 } 37 tailMemcpy38 LIBC_INLINE static void tail(Ptr __restrict dst, CPtr __restrict src, 39 size_t count) { 40 block_offset(dst, src, count - SIZE); 41 } 42 head_tailMemcpy43 LIBC_INLINE static void head_tail(Ptr __restrict dst, CPtr __restrict src, 44 size_t count) { 45 block(dst, src); 46 tail(dst, src, count); 47 } 48 loop_and_tail_offsetMemcpy49 LIBC_INLINE static void loop_and_tail_offset(Ptr __restrict dst, 50 CPtr __restrict src, 51 size_t count, size_t offset) { 52 static_assert(Size > 1, "a loop of size 1 does not need tail"); 53 do { 54 block_offset(dst, src, offset); 55 offset += SIZE; 56 } while (offset < count - SIZE); 57 tail(dst, src, count); 58 } 59 loop_and_tailMemcpy60 LIBC_INLINE static void loop_and_tail(Ptr __restrict dst, CPtr __restrict src, 61 size_t count) { 62 return loop_and_tail_offset(dst, src, count, 0); 63 } 64 }; 65 66 /////////////////////////////////////////////////////////////////////////////// 67 // Memset 68 template <size_t Size> struct Memset { 69 using ME = Memset; 70 static constexpr size_t SIZE = Size; blockMemset71 LIBC_INLINE static void block(Ptr dst, uint8_t value) { 72 #ifdef LLVM_LIBC_HAS_BUILTIN_MEMSET_INLINE 73 __builtin_memset_inline(dst, value, Size); 74 #else 75 static_assert(cpp::always_false<decltype(Size)>, 76 "Missing __builtin_memset_inline"); 77 (void)dst; 78 (void)value; 79 #endif 80 } 81 tailMemset82 LIBC_INLINE static void tail(Ptr dst, uint8_t value, size_t count) { 83 block(dst + count - SIZE, value); 84 } 85 head_tailMemset86 LIBC_INLINE static void head_tail(Ptr dst, uint8_t value, size_t count) { 87 block(dst, value); 88 tail(dst, value, count); 89 } 90 loop_and_tailMemset91 LIBC_INLINE static void loop_and_tail(Ptr dst, uint8_t value, size_t count) { 92 static_assert(Size > 1, "a loop of size 1 does not need tail"); 93 size_t offset = 0; 94 do { 95 block(dst + offset, value); 96 offset += SIZE; 97 } while (offset < count - SIZE); 98 tail(dst, value, count); 99 } 100 }; 101 102 /////////////////////////////////////////////////////////////////////////////// 103 // Bcmp 104 template <size_t Size> struct Bcmp { 105 using ME = Bcmp; 106 static constexpr size_t SIZE = Size; blockBcmp107 LIBC_INLINE static BcmpReturnType block(CPtr, CPtr) { 108 static_assert(cpp::always_false<decltype(Size)>, 109 "Missing __builtin_memcmp_inline"); 110 return BcmpReturnType::zero(); 111 } 112 tailBcmp113 LIBC_INLINE static BcmpReturnType tail(CPtr, CPtr, size_t) { 114 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 115 return BcmpReturnType::zero(); 116 } 117 head_tailBcmp118 LIBC_INLINE static BcmpReturnType head_tail(CPtr, CPtr, size_t) { 119 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 120 return BcmpReturnType::zero(); 121 } 122 loop_and_tailBcmp123 LIBC_INLINE static BcmpReturnType loop_and_tail(CPtr, CPtr, size_t) { 124 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 125 return BcmpReturnType::zero(); 126 } 127 }; 128 129 /////////////////////////////////////////////////////////////////////////////// 130 // Memcmp 131 template <size_t Size> struct Memcmp { 132 using ME = Memcmp; 133 static constexpr size_t SIZE = Size; blockMemcmp134 LIBC_INLINE static MemcmpReturnType block(CPtr, CPtr) { 135 static_assert(cpp::always_false<decltype(Size)>, 136 "Missing __builtin_memcmp_inline"); 137 return MemcmpReturnType::zero(); 138 } 139 tailMemcmp140 LIBC_INLINE static MemcmpReturnType tail(CPtr, CPtr, size_t) { 141 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 142 return MemcmpReturnType::zero(); 143 } 144 head_tailMemcmp145 LIBC_INLINE static MemcmpReturnType head_tail(CPtr, CPtr, size_t) { 146 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 147 return MemcmpReturnType::zero(); 148 } 149 loop_and_tailMemcmp150 LIBC_INLINE static MemcmpReturnType loop_and_tail(CPtr, CPtr, size_t) { 151 static_assert(cpp::always_false<decltype(Size)>, "Not implemented"); 152 return MemcmpReturnType::zero(); 153 } 154 }; 155 156 } // namespace builtin 157 } // namespace LIBC_NAMESPACE_DECL 158 159 #endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_OP_BUILTIN_H 160