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_backward(char *dst, const char *src,
19                                       size_t count) {
20   for (size_t offset = count - 1; count; --count, --offset)
21     dst[offset] = src[offset];
22 }
23 
24 static void memmove_impl(char *dst, const char *src, size_t count) {
25 
26   // If the distance between `src` and `dst` is equal to or greater
27   // than count (integerAbs(src - dst) >= count), they would not overlap.
28   // e.g. greater     equal       overlapping
29   //      [12345678]  [12345678]  [12345678]
30   // src: [_ab_____]  [_ab_____]  [_ab_____]
31   // dst: [_____yz_]  [___yz___]  [__yz____]
32 
33   // Call `memcpy` when `src` and `dst` do not overlap.
34   if (__llvm_libc::integerAbs(src - dst) >= static_cast<ptrdiff_t>(count))
35     __llvm_libc::memcpy(dst, src, count);
36 
37   // Overlap cases.
38   // If `dst` starts before `src` (dst < src), copy forward from beginning to
39   // end. If `dst` starts after `src` (dst > src), copy backward from end to
40   // beginning. If `dst` and `src` start at the same address (dst == src), do
41   // nothing.
42   // e.g. forward      backward
43   //             *->    <-*
44   // src: [___abcde_]  [_abcde___]
45   // dst: [_abc--___]  [___--cde_]
46 
47   // In `memcpy` implementation, it copies bytes forward from beginning to
48   // end. Otherwise, `memmove` unit tests will break.
49   if (dst < src)
50     __llvm_libc::memcpy(dst, src, count);
51 
52   // TODO: Optimize `move_byte_xxx(...)` functions.
53   if (dst > src)
54     move_byte_backward(dst, src, count);
55 }
56 
57 LLVM_LIBC_FUNCTION(void *, memmove,
58                    (void *dst, const void *src, size_t count)) {
59   memmove_impl(reinterpret_cast<char *>(dst),
60                reinterpret_cast<const char *>(src), count);
61   return dst;
62 }
63 
64 } // namespace __llvm_libc
65