aboutsummaryrefslogtreecommitdiff
path: root/libgo/runtime/go-memmove.c
blob: 1dbd2b39273471256764d61d4af747e1d6e7c90e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* go-memmove.c -- memmove

   Copyright 2021 The Go Authors. All rights reserved.
   Use of this source code is governed by a BSD-style
   license that can be found in the LICENSE file.  */

#include "runtime.h"

void gomemmove(void *, void *, uintptr)
  __asm__ (GOSYM_PREFIX "runtime.memmove")
  __attribute__ ((no_split_stack));

// This implementation is necessary since
// the __builtin_memmove might use __libc_memmove
// which doesn't require atomicity of pointer-sized
// moves.

void
gomemmove(void *dst, void *src, uintptr len)
{
  const uintptr ptr_size = sizeof(dst);
  uintptr tail;
  uintptr rem;
  uintptr dwords;
  uintptr i;
  char *bdst, *bsrc;

  if (len == 0) {
    return;
  }

  // We expect pointer-containing values to be pointer-aligned.
  // If these pointers are not aligned, they don't contain pointers.
  if ((uintptr)dst % ptr_size != 0 || (uintptr)src % ptr_size != 0 || len < ptr_size) {
    __builtin_memmove(dst, src, len);
    return;
  }

  bdst = (char*)dst;
  bsrc = (char*)src;

  // Move the tail bytes to make the backward move easier.
  rem = len;
  tail = rem % ptr_size;
  if (tail > 0) {
    __builtin_memmove(bdst+rem-tail, bsrc+rem-tail, tail);
    rem -= tail;
  }

  // Must now be pointer alignment and rem is multiple of ptr_size.
  dwords = rem / ptr_size;

  // Determine if a backwards move is needed.
  // Forward or backward, move all words.

  if ((uintptr)(bdst - bsrc) < rem) {
    bdst += rem - ptr_size;
    bsrc += rem - ptr_size;
    for (i = 0; i<dwords; i++) {
      *(uintptr*)bdst = *(uintptr*)bsrc;
      bdst -= ptr_size;
      bsrc -= ptr_size;
    }
  } else {
    for (i = 0; i<dwords; i++) {
      *(uintptr*)bdst = *(uintptr*)bsrc;
      bdst += ptr_size;
      bsrc += ptr_size;
    }
  }
}