summaryrefslogtreecommitdiffstats
path: root/main/glib/memcpy.c
blob: 3cfbfa34f9edc40cc01558d70ece05af69dea115 (plain) (blame)
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "config.h"
#include <ctype.h>
#include "genlib.h"
#include "stddefs.h"

#ifndef MEMCPY_CHUNK
#define MEMCPY_CHUNK (256*1024)
#endif

/* memcpy():
 *  Copy n bytes from 'from' to 'to'; return 'to'.
 *	This version of memcpy() tries to take advantage of address alignment.
 *  The goal is to do as many of the copies on 4-byte aligned addresses,
 *  falling back to 2-byte alignment, and finally, if there is no other
 *  way, simple byte-by-byte copy.
 *  Note that there is some point where the amount of overhead may exceed
 *  the byte count; hence, this will take longer for small byte counts.
 *  The assumption here is that small byte count memcpy() calls don't really
 *  care.
 */
char *
memcpy(char *to,char *from,int count)
{
	char	*to_copy, *end;
#if INCLUDE_QUICKMEMCPY
	char	*tend;
#endif

	to_copy = to;

#if INCLUDE_QUICKMEMCPY
	/* If count is greater than 8, get fancy, else just do byte-copy... */
	if (count > 8) {
		/* Attempt to optimize the transfer here... */
		if (((int)to & 3) && ((int)from & 3)) {
			/* If from and to pointers are both unaligned to the
			 * same degree then we can do a few char copies to get them
			 * 4-byte aligned and then do a lot of 4-byte aligned copies.
			 */
			if (((int)to & 3) == ((int)from & 3)) {
				while((int)to & 3) {
					*to++ = *from++;
					count--;
				}
			}
			/* If from and to pointers are both odd, but different, then
			 * we can increment them both by 1 and do a bunch of 2-byte
			 * aligned copies...
			 */
			else if (((int)to & 1) && ((int)from & 1)) {
				*to++ = *from++;
				count--;
			}
		}
	
		/* If both pointers are now 4-byte aligned or 2-byte aligned,
		 * take advantage of that here...
		 */
		if (!((int)to & 3) && !((int)from & 3)) {
			tend = end = to + (count & ~3);
			count = count & 3;
#ifdef WATCHDOG_ENABLED
			do {
				tend = (end - to <= MEMCPY_CHUNK) ? end : to + MEMCPY_CHUNK;
#endif
				while(to < tend) {
					*(ulong *)to = *(ulong *)from;
					from += 4;
					to += 4;
				}
#ifdef WATCHDOG_ENABLED
				WATCHDOG_MACRO;
			} while (tend != end);
#endif
		}
		else if (!((int)to & 1) && !((int)from & 1)) {
			tend = end = to + (count & ~1);
			count = count & 1;
#ifdef WATCHDOG_ENABLED
			do {
				tend = (end - to <= MEMCPY_CHUNK) ? end : to + MEMCPY_CHUNK;
#endif
				while(to < tend) {
					*(ushort *)to = *(ushort *)from;
					from += 2;
					to += 2;
				}
#ifdef WATCHDOG_ENABLED
				WATCHDOG_MACRO;
			} while (tend != end);
#endif
		}
	}
#endif

	if (count) {
		end = to + count;
		while(to < end)
			*to++ = *from++;
	}
	return(to_copy);
}

void
bcopy(char *from, char *to, int size)
{
	memcpy(to,from,size);
}