1 //===-- Implementation of memmove -----------------------------------------===//
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 #include "src/string/memmove.h"
10 #include "src/__support/common.h"
11 #include "src/stdlib/abs_utils.h"
12 #include "src/string/memcpy.h"
13 #include <stddef.h> // size_t, ptrdiff_t
14 
15 namespace __llvm_libc {
16 
17 static inline void move_byte_forward(char *dest_m, const char *src_m,
18                                      size_t count) {
19   for (size_t offset = 0; count; --count, ++offset)
20     dest_m[offset] = src_m[offset];
21 }
22 
23 static inline void move_byte_backward(char *dest_m, const char *src_m,
24                                       size_t count) {
25   for (size_t offset = count - 1; count; --count, --offset)
26     dest_m[offset] = src_m[offset];
27 }
28 
29 LLVM_LIBC_FUNCTION(void *, memmove,
30                    (void *dest, const void *src, size_t count)) {
31   char *dest_c = reinterpret_cast<char *>(dest);
32   const char *src_c = reinterpret_cast<const char *>(src);
33 
34   // If the distance between src_c and dest_c is equal to or greater
35   // than count (integer_abs(src_c - dest_c) >= count), they would not overlap.
36   // e.g.   greater     equal       overlapping
37   //        [12345678]  [12345678]  [12345678]
38   // src_c: [_ab_____]  [_ab_____]  [_ab_____]
39   // dest_c:[_____yz_]  [___yz___]  [__yz____]
40 
41   // Use memcpy if src_c and dest_c do not overlap.
42   if (__llvm_libc::integer_abs(src_c - dest_c) >= static_cast<ptrdiff_t>(count))
43     return __llvm_libc::memcpy(dest_c, src_c, count);
44 
45   // Overlap cases.
46   // If dest_c starts before src_c (dest_c < src_c), copy forward(pointer add 1)
47   // from beginning to end.
48   // If dest_c starts after src_c (dest_c > src_c), copy backward(pointer add
49   // -1) from end to beginning.
50   // If dest_c and src_c start at the same address (dest_c == src_c),
51   // just return dest.
52   // e.g.    forward      backward
53   //             *-->        <--*
54   // src_c : [___abcde_]  [_abcde___]
55   // dest_c: [_abc--___]  [___--cde_]
56 
57   // TODO: Optimize `move_byte_xxx(...)` functions.
58   if (dest_c < src_c)
59     move_byte_forward(dest_c, src_c, count);
60   if (dest_c > src_c)
61     move_byte_backward(dest_c, src_c, count);
62   return dest;
63 }
64 
65 } // namespace __llvm_libc
66