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; |
27 | 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 | |
32 | LIBC_INLINE static void block(Ptr __restrict dst, CPtr __restrict src) { |
33 | block_offset(dst, src, offset: 0); |
34 | } |
35 | |
36 | LIBC_INLINE static void tail(Ptr __restrict dst, CPtr __restrict src, |
37 | size_t count) { |
38 | block_offset(dst, src, offset: count - SIZE); |
39 | } |
40 | |
41 | 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 | |
47 | 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 | |
58 | 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, offset: 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; |
69 | 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 | |
80 | LIBC_INLINE static void tail(Ptr dst, uint8_t value, size_t count) { |
81 | block(dst: dst + count - SIZE, value); |
82 | } |
83 | |
84 | 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 | |
89 | 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: 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; |
105 | 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 | |
111 | 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 | |
116 | 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 | |
121 | 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; |
132 | 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 | |
138 | 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 | |
143 | 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 | |
148 | 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 | |