Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libc / src / string / memory_utils / op_builtin.h
blobcfa58e43d74550d78fb89ac90f112dfb96643bbc
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.
14 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_OP_BUILTIN_H
16 #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_OP_BUILTIN_H
18 #include "src/string/memory_utils/utils.h"
20 namespace LIBC_NAMESPACE::builtin {
22 ///////////////////////////////////////////////////////////////////////////////
23 // Memcpy
24 template <size_t Size> struct Memcpy {
25 static constexpr size_t SIZE = Size;
26 LIBC_INLINE static void block_offset(Ptr __restrict dst, CPtr __restrict src,
27 size_t offset) {
28 #ifdef LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE
29 return __builtin_memcpy_inline(dst + offset, src + offset, SIZE);
30 #else
31 // The codegen may be suboptimal.
32 for (size_t i = 0; i < Size; ++i)
33 dst[i + offset] = src[i + offset];
34 #endif
37 LIBC_INLINE static void block(Ptr __restrict dst, CPtr __restrict src) {
38 block_offset(dst, src, 0);
41 LIBC_INLINE static void tail(Ptr __restrict dst, CPtr __restrict src,
42 size_t count) {
43 block_offset(dst, src, count - SIZE);
46 LIBC_INLINE static void head_tail(Ptr __restrict dst, CPtr __restrict src,
47 size_t count) {
48 block(dst, src);
49 tail(dst, src, count);
52 LIBC_INLINE static void loop_and_tail_offset(Ptr __restrict dst,
53 CPtr __restrict src,
54 size_t count, size_t offset) {
55 static_assert(Size > 1, "a loop of size 1 does not need tail");
56 do {
57 block_offset(dst, src, offset);
58 offset += SIZE;
59 } while (offset < count - SIZE);
60 tail(dst, src, count);
63 LIBC_INLINE static void loop_and_tail(Ptr __restrict dst, CPtr __restrict src,
64 size_t count) {
65 return loop_and_tail_offset(dst, src, count, 0);
69 ///////////////////////////////////////////////////////////////////////////////
70 // Memset
71 template <size_t Size> struct Memset {
72 using ME = Memset;
73 static constexpr size_t SIZE = Size;
74 LIBC_INLINE static void block(Ptr dst, uint8_t value) {
75 #ifdef LLVM_LIBC_HAS_BUILTIN_MEMSET_INLINE
76 __builtin_memset_inline(dst, value, Size);
77 #else
78 deferred_static_assert("Missing __builtin_memset_inline");
79 (void)dst;
80 (void)value;
81 #endif
84 LIBC_INLINE static void tail(Ptr dst, uint8_t value, size_t count) {
85 block(dst + count - SIZE, value);
88 LIBC_INLINE static void head_tail(Ptr dst, uint8_t value, size_t count) {
89 block(dst, value);
90 tail(dst, value, count);
93 LIBC_INLINE static void loop_and_tail(Ptr dst, uint8_t value, size_t count) {
94 static_assert(Size > 1, "a loop of size 1 does not need tail");
95 size_t offset = 0;
96 do {
97 block(dst + offset, value);
98 offset += SIZE;
99 } while (offset < count - SIZE);
100 tail(dst, value, count);
104 ///////////////////////////////////////////////////////////////////////////////
105 // Bcmp
106 template <size_t Size> struct Bcmp {
107 using ME = Bcmp;
108 static constexpr size_t SIZE = Size;
109 LIBC_INLINE static BcmpReturnType block(CPtr, CPtr) {
110 deferred_static_assert("Missing __builtin_memcmp_inline");
111 return BcmpReturnType::ZERO();
114 LIBC_INLINE static BcmpReturnType tail(CPtr, CPtr, size_t) {
115 deferred_static_assert("Not implemented");
116 return BcmpReturnType::ZERO();
119 LIBC_INLINE static BcmpReturnType head_tail(CPtr, CPtr, size_t) {
120 deferred_static_assert("Not implemented");
121 return BcmpReturnType::ZERO();
124 LIBC_INLINE static BcmpReturnType loop_and_tail(CPtr, CPtr, size_t) {
125 deferred_static_assert("Not implemented");
126 return BcmpReturnType::ZERO();
130 ///////////////////////////////////////////////////////////////////////////////
131 // Memcmp
132 template <size_t Size> struct Memcmp {
133 using ME = Memcmp;
134 static constexpr size_t SIZE = Size;
135 LIBC_INLINE static MemcmpReturnType block(CPtr, CPtr) {
136 deferred_static_assert("Missing __builtin_memcmp_inline");
137 return MemcmpReturnType::ZERO();
140 LIBC_INLINE static MemcmpReturnType tail(CPtr, CPtr, size_t) {
141 deferred_static_assert("Not implemented");
142 return MemcmpReturnType::ZERO();
145 LIBC_INLINE static MemcmpReturnType head_tail(CPtr, CPtr, size_t) {
146 deferred_static_assert("Not implemented");
147 return MemcmpReturnType::ZERO();
150 LIBC_INLINE static MemcmpReturnType loop_and_tail(CPtr, CPtr, size_t) {
151 deferred_static_assert("Not implemented");
152 return MemcmpReturnType::ZERO();
156 } // namespace LIBC_NAMESPACE::builtin
158 #endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_OP_BUILTIN_H