diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2014-08-06 04:26:52 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2014-08-29 22:06:57 -0400 |
commit | 77b3625763ae4d5aa6aaa9d44fbc1bfec6b29335 (patch) | |
tree | 74b12e2669da8653932f48f1ca3816eef4bf6324 | |
parent | 7d1a47cf13726c95ac46027156cc12dd9da5b855 (diff) | |
download | rockbox-77b3625763ae4d5aa6aaa9d44fbc1bfec6b29335.tar.gz rockbox-77b3625763ae4d5aa6aaa9d44fbc1bfec6b29335.zip |
Add mempcpy implementation
A GNU extension that returns dst + size instead of dst. It's a nice
shortcut when copying strings with a known size or back-to-back blocks
and you have to do it often.
May of course be called directly or alternately through
__builtin_mempcpy in some compiler versions.
For ASM on native targets, it is implemented as an alternate entrypoint
to memcpy which adds minimal code and overhead.
Change-Id: I4cbb3483f6df3c1007247fe0a95fd7078737462b
-rw-r--r-- | firmware/asm/SOURCES | 4 | ||||
-rw-r--r-- | firmware/asm/arm/memcpy.S | 10 | ||||
-rw-r--r-- | firmware/asm/m68k/memcpy.S | 10 | ||||
-rw-r--r-- | firmware/asm/mempcpy.c | 47 | ||||
-rw-r--r-- | firmware/asm/mips/memcpy.S | 11 | ||||
-rw-r--r-- | firmware/asm/sh/memcpy.S | 8 | ||||
-rw-r--r-- | firmware/include/string-extra.h | 12 | ||||
-rw-r--r-- | firmware/libc/include/string.h | 1 |
8 files changed, 99 insertions, 4 deletions
diff --git a/firmware/asm/SOURCES b/firmware/asm/SOURCES index a9293b4297..ebb6951071 100644 --- a/firmware/asm/SOURCES +++ b/firmware/asm/SOURCES | |||
@@ -7,6 +7,10 @@ memset.c | |||
7 | strlen.c | 7 | strlen.c |
8 | #endif | 8 | #endif |
9 | 9 | ||
10 | #if defined(WIN32) || defined(APPLICATION) | ||
11 | mempcpy.c | ||
12 | #endif | ||
13 | |||
10 | #if (defined(SANSA_E200) || defined(GIGABEAT_F) || defined(GIGABEAT_S) || \ | 14 | #if (defined(SANSA_E200) || defined(GIGABEAT_F) || defined(GIGABEAT_S) || \ |
11 | defined(CREATIVE_ZVx) || defined(SANSA_CONNECT) || defined(SANSA_FUZEPLUS) || \ | 15 | defined(CREATIVE_ZVx) || defined(SANSA_CONNECT) || defined(SANSA_FUZEPLUS) || \ |
12 | defined(COWON_D2) || defined(MINI2440) || defined(SAMSUNG_YPR0) || \ | 16 | defined(COWON_D2) || defined(MINI2440) || defined(SAMSUNG_YPR0) || \ |
diff --git a/firmware/asm/arm/memcpy.S b/firmware/asm/arm/memcpy.S index 2a55fb5656..83d43293e6 100644 --- a/firmware/asm/arm/memcpy.S +++ b/firmware/asm/arm/memcpy.S | |||
@@ -36,17 +36,25 @@ | |||
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ | 38 | /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ |
39 | /* Prototype: void *mempcpy(void *dest, const void *src, size_t n); */ | ||
39 | 40 | ||
40 | .section .icode,"ax",%progbits | 41 | .section .icode,"ax",%progbits |
41 | 42 | ||
42 | .align 2 | 43 | .align 2 |
43 | .global memcpy | 44 | .global memcpy |
44 | .type memcpy,%function | 45 | .type memcpy,%function |
46 | .global mempcpy | ||
47 | .type mempcpy,%function | ||
48 | |||
49 | mempcpy: | ||
50 | add r3, r0, r2 | ||
51 | stmfd sp!, {r3, r4, lr} | ||
52 | b 0f | ||
45 | 53 | ||
46 | memcpy: | 54 | memcpy: |
47 | stmfd sp!, {r0, r4, lr} | 55 | stmfd sp!, {r0, r4, lr} |
48 | 56 | ||
49 | subs r2, r2, #4 | 57 | 0: subs r2, r2, #4 |
50 | blt 8f | 58 | blt 8f |
51 | ands ip, r0, #3 | 59 | ands ip, r0, #3 |
52 | bne 9f | 60 | bne 9f |
diff --git a/firmware/asm/m68k/memcpy.S b/firmware/asm/m68k/memcpy.S index 9762e31e02..a88ac3d091 100644 --- a/firmware/asm/m68k/memcpy.S +++ b/firmware/asm/m68k/memcpy.S | |||
@@ -27,6 +27,8 @@ | |||
27 | .global memcpy | 27 | .global memcpy |
28 | .global __memcpy_fwd_entry | 28 | .global __memcpy_fwd_entry |
29 | .type memcpy,@function | 29 | .type memcpy,@function |
30 | .global mempcpy | ||
31 | .type mempcpy,@function | ||
30 | 32 | ||
31 | /* Copies <length> bytes of data in memory from <source> to <dest> | 33 | /* Copies <length> bytes of data in memory from <source> to <dest> |
32 | * This version is optimized for speed | 34 | * This version is optimized for speed |
@@ -53,6 +55,14 @@ | |||
53 | * long+3) it writes longwords only. Same goes for word aligned destinations | 55 | * long+3) it writes longwords only. Same goes for word aligned destinations |
54 | * if FULLSPEED is undefined. | 56 | * if FULLSPEED is undefined. |
55 | */ | 57 | */ |
58 | mempcpy: | ||
59 | move.l (4,%sp),%a1 /* Destination */ | ||
60 | move.l (8,%sp),%a0 /* Source */ | ||
61 | move.l (12,%sp),%d1 /* Length */ | ||
62 | |||
63 | add.l %d1,(4,%sp) /* retval=Destination + Length */ | ||
64 | bra.b __memcpy_fwd_entry | ||
65 | |||
56 | memcpy: | 66 | memcpy: |
57 | move.l (4,%sp),%a1 /* Destination */ | 67 | move.l (4,%sp),%a1 /* Destination */ |
58 | move.l (8,%sp),%a0 /* Source */ | 68 | move.l (8,%sp),%a0 /* Source */ |
diff --git a/firmware/asm/mempcpy.c b/firmware/asm/mempcpy.c new file mode 100644 index 0000000000..2b1ccecbe8 --- /dev/null +++ b/firmware/asm/mempcpy.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | FUNCTION | ||
3 | <<mempcpy>>---copy memory regions and return end pointer | ||
4 | |||
5 | ANSI_SYNOPSIS | ||
6 | #include <string.h> | ||
7 | void* mempcpy(void *<[out]>, const void *<[in]>, size_t <[n]>); | ||
8 | |||
9 | TRAD_SYNOPSIS | ||
10 | void *mempcpy(<[out]>, <[in]>, <[n]> | ||
11 | void *<[out]>; | ||
12 | void *<[in]>; | ||
13 | size_t <[n]>; | ||
14 | |||
15 | DESCRIPTION | ||
16 | This function copies <[n]> bytes from the memory region | ||
17 | pointed to by <[in]> to the memory region pointed to by | ||
18 | <[out]>. | ||
19 | |||
20 | If the regions overlap, the behavior is undefined. | ||
21 | |||
22 | RETURNS | ||
23 | <<mempcpy>> returns a pointer to the byte following the | ||
24 | last byte copied to the <[out]> region. | ||
25 | |||
26 | PORTABILITY | ||
27 | <<mempcpy>> is a GNU extension. | ||
28 | |||
29 | <<mempcpy>> requires no supporting OS subroutines. | ||
30 | |||
31 | */ | ||
32 | |||
33 | #include "config.h" | ||
34 | #include "_ansi.h" /* for _DEFUN */ | ||
35 | #include <string.h> | ||
36 | |||
37 | /* This may be conjoined with memcpy in <cpu>/memcpy.S to get it nearly for | ||
38 | free */ | ||
39 | |||
40 | _PTR | ||
41 | _DEFUN (mempcpy, (dst0, src0, len0), | ||
42 | _PTR dst0 _AND | ||
43 | _CONST _PTR src0 _AND | ||
44 | size_t len0) | ||
45 | { | ||
46 | return memcpy(dst0, src0, len0) + len0; | ||
47 | } | ||
diff --git a/firmware/asm/mips/memcpy.S b/firmware/asm/mips/memcpy.S index edbf5ac5eb..ec1625bb4f 100644 --- a/firmware/asm/mips/memcpy.S +++ b/firmware/asm/mips/memcpy.S | |||
@@ -43,8 +43,16 @@ | |||
43 | 43 | ||
44 | .global memcpy | 44 | .global memcpy |
45 | .type memcpy, %function | 45 | .type memcpy, %function |
46 | .global mempcpy | ||
47 | .type mempcpy, %function | ||
46 | 48 | ||
47 | .set noreorder | 49 | .set noreorder |
50 | mempcpy: | ||
51 | slti t0, a2, 8 # Less than 8? | ||
52 | bne t0, zero, last8 | ||
53 | addu v0, a0, a2 # exit value = s1 + n | ||
54 | b 1f | ||
55 | xor t0, a1, a0 # Find a0/a1 displacement (fill delay) | ||
48 | 56 | ||
49 | memcpy: | 57 | memcpy: |
50 | slti t0, a2, 8 # Less than 8? | 58 | slti t0, a2, 8 # Less than 8? |
@@ -52,7 +60,8 @@ memcpy: | |||
52 | move v0, a0 # Setup exit value before too late | 60 | move v0, a0 # Setup exit value before too late |
53 | 61 | ||
54 | xor t0, a1, a0 # Find a0/a1 displacement | 62 | xor t0, a1, a0 # Find a0/a1 displacement |
55 | andi t0, 0x3 | 63 | |
64 | 1: andi t0, 0x3 | ||
56 | bne t0, zero, shift # Go handle the unaligned case | 65 | bne t0, zero, shift # Go handle the unaligned case |
57 | subu t1, zero, a1 | 66 | subu t1, zero, a1 |
58 | andi t1, 0x3 # a0/a1 are aligned, but are we | 67 | andi t1, 0x3 # a0/a1 are aligned, but are we |
diff --git a/firmware/asm/sh/memcpy.S b/firmware/asm/sh/memcpy.S index 59c5801ac0..3d623c48cd 100644 --- a/firmware/asm/sh/memcpy.S +++ b/firmware/asm/sh/memcpy.S | |||
@@ -24,8 +24,10 @@ | |||
24 | 24 | ||
25 | .align 2 | 25 | .align 2 |
26 | .global _memcpy | 26 | .global _memcpy |
27 | .global _mempcpy | ||
27 | .global ___memcpy_fwd_entry | 28 | .global ___memcpy_fwd_entry |
28 | .type _memcpy,@function | 29 | .type _memcpy,@function |
30 | .type _mempcpy,@function | ||
29 | 31 | ||
30 | /* Copies <length> bytes of data in memory from <source> to <dest> | 32 | /* Copies <length> bytes of data in memory from <source> to <dest> |
31 | * This version is optimized for speed | 33 | * This version is optimized for speed |
@@ -51,6 +53,10 @@ | |||
51 | * The instruction order is devised in a way to utilize the pipelining | 53 | * The instruction order is devised in a way to utilize the pipelining |
52 | * of the SH1 to the max. The routine also tries to utilize fast page mode. | 54 | * of the SH1 to the max. The routine also tries to utilize fast page mode. |
53 | */ | 55 | */ |
56 | _mempcpy: | ||
57 | mov r4,r7 /* store dest + length for returning */ | ||
58 | bra ___memcpy_fwd_entry | ||
59 | add r6,r7 | ||
54 | 60 | ||
55 | _memcpy: | 61 | _memcpy: |
56 | mov r4,r7 /* store dest for returning */ | 62 | mov r4,r7 /* store dest for returning */ |
@@ -217,3 +223,5 @@ ___memcpy_fwd_entry: | |||
217 | mov r7,r0 /* return dest start address */ | 223 | mov r7,r0 /* return dest start address */ |
218 | .end: | 224 | .end: |
219 | .size _memcpy,.end-_memcpy | 225 | .size _memcpy,.end-_memcpy |
226 | .size _mempcpy,.end-_mempcpy | ||
227 | |||
diff --git a/firmware/include/string-extra.h b/firmware/include/string-extra.h index bae250d7c9..6a9e0c77be 100644 --- a/firmware/include/string-extra.h +++ b/firmware/include/string-extra.h | |||
@@ -18,8 +18,8 @@ | |||
18 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | #ifndef STRING_EXTRA_H | |
22 | 22 | #define STRING_EXTRA_H | |
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include "strlcpy.h" | 24 | #include "strlcpy.h" |
25 | #include "strlcat.h" | 25 | #include "strlcat.h" |
@@ -27,3 +27,11 @@ | |||
27 | #include "strcasestr.h" | 27 | #include "strcasestr.h" |
28 | #include "strtok_r.h" | 28 | #include "strtok_r.h" |
29 | #include "memset16.h" | 29 | #include "memset16.h" |
30 | |||
31 | #if defined(WIN32) || defined(APPLICATION) | ||
32 | #ifndef mempcpy | ||
33 | #define mempcpy __builtin_mempcpy | ||
34 | #endif | ||
35 | #endif | ||
36 | |||
37 | #endif /* STRING_EXTRA_H */ | ||
diff --git a/firmware/libc/include/string.h b/firmware/libc/include/string.h index 9346611aee..9815c62805 100644 --- a/firmware/libc/include/string.h +++ b/firmware/libc/include/string.h | |||
@@ -20,6 +20,7 @@ extern "C" { | |||
20 | _PTR _EXFUN(memchr,(const _PTR, int, size_t)); | 20 | _PTR _EXFUN(memchr,(const _PTR, int, size_t)); |
21 | int _EXFUN(memcmp,(const _PTR, const _PTR, size_t)); | 21 | int _EXFUN(memcmp,(const _PTR, const _PTR, size_t)); |
22 | _PTR _EXFUN(memcpy,(_PTR, const _PTR, size_t)); | 22 | _PTR _EXFUN(memcpy,(_PTR, const _PTR, size_t)); |
23 | _PTR _EXFUN(mempcpy,(_PTR, const _PTR, size_t)); | ||
23 | _PTR _EXFUN(memmove,(_PTR, const _PTR, size_t)); | 24 | _PTR _EXFUN(memmove,(_PTR, const _PTR, size_t)); |
24 | _PTR _EXFUN(memset,(_PTR, int, size_t)); | 25 | _PTR _EXFUN(memset,(_PTR, int, size_t)); |
25 | char *_EXFUN(strcat,(char *, const char *)); | 26 | char *_EXFUN(strcat,(char *, const char *)); |