memcpy.cpp 2.3 KB
//===-- Implementation of memcpy ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/string/memcpy.h"
#include "src/__support/common.h"
#include "src/string/memory_utils/memcpy_utils.h"

namespace __llvm_libc {

// Design rationale
// ================
//
// Using a profiler to observe size distributions for calls into libc
// functions, it was found most operations act on a small number of bytes.
// This makes it important to favor small sizes.
//
// The tests for `count` are in ascending order so the cost of branching is
// proportional to the cost of copying.
//
// The function is written in C++ for several reasons:
// - The compiler can __see__ the code, this is useful when performing Profile
//   Guided Optimization as the optimized code can take advantage of branching
//   probabilities.
// - It also allows for easier customization and favors testing multiple
//   implementation parameters.
// - As compilers and processors get better, the generated code is improved
//   with little change on the code side.
static void memcpy_impl(char *__restrict dst, const char *__restrict src,
                        size_t count) {
  if (count == 0)
    return;
  if (count == 1)
    return CopyBlock<1>(dst, src);
  if (count == 2)
    return CopyBlock<2>(dst, src);
  if (count == 3)
    return CopyBlock<3>(dst, src);
  if (count == 4)
    return CopyBlock<4>(dst, src);
  if (count < 8)
    return CopyBlockOverlap<4>(dst, src, count);
  if (count < 16)
    return CopyBlockOverlap<8>(dst, src, count);
  if (count < 32)
    return CopyBlockOverlap<16>(dst, src, count);
  if (count < 64)
    return CopyBlockOverlap<32>(dst, src, count);
  if (count < 128)
    return CopyBlockOverlap<64>(dst, src, count);
  return CopyAlignedBlocks<32>(dst, src, count);
}

void *LLVM_LIBC_ENTRYPOINT(memcpy)(void *__restrict dst,
                                   const void *__restrict src, size_t size) {
  memcpy_impl(reinterpret_cast<char *>(dst),
              reinterpret_cast<const char *>(src), size);
  return dst;
}

} // namespace __llvm_libc