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