mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-08-27 20:19:18 +03:00
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@7533 3c298f89-4303-0410-b956-a3cf2f4a3e73
1140 lines
23 KiB
Diff
1140 lines
23 KiB
Diff
Subject: [PATCH] AVR32-optimized string operations
|
|
|
|
Add hand-optimized AVR32-specific string operations. Some of them
|
|
need a bit more testing, though.
|
|
|
|
---
|
|
|
|
libc/string/avr32/Makefile | 40 +++++++++++
|
|
libc/string/avr32/bcopy.S | 15 ++++
|
|
libc/string/avr32/bzero.S | 12 +++
|
|
libc/string/avr32/memchr.S | 62 +++++++++++++++++
|
|
libc/string/avr32/memcmp.S | 50 +++++++++++++
|
|
libc/string/avr32/memcpy.S | 110 ++++++++++++++++++++++++++++++
|
|
libc/string/avr32/memmove.S | 114 +++++++++++++++++++++++++++++++
|
|
libc/string/avr32/memset.S | 60 ++++++++++++++++
|
|
libc/string/avr32/strcat.S | 95 ++++++++++++++++++++++++++
|
|
libc/string/avr32/strcmp.S | 80 ++++++++++++++++++++++
|
|
libc/string/avr32/strcpy.S | 63 +++++++++++++++++
|
|
libc/string/avr32/stringtest.c | 144 ++++++++++++++++++++++++++++++++++++++++
|
|
libc/string/avr32/strlen.S | 52 ++++++++++++++
|
|
libc/string/avr32/strncpy.S | 77 +++++++++++++++++++++
|
|
libc/string/avr32/test_memcpy.c | 66 ++++++++++++++++++
|
|
15 files changed, 1040 insertions(+)
|
|
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/bcopy.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/bcopy.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,15 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+ .text
|
|
+ .global bcopy
|
|
+ .type bcopy, @function
|
|
+ .align 1
|
|
+bcopy:
|
|
+ /* Swap the first two arguments */
|
|
+ eor r11, r12
|
|
+ eor r12, r11
|
|
+ eor r11, r12
|
|
+ rjmp __memmove
|
|
+ .size bcopy, . - bcopy
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/bzero.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/bzero.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,12 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+ .text
|
|
+ .global bzero
|
|
+ .type bzero, @function
|
|
+ .align 1
|
|
+bzero:
|
|
+ mov r10, r11
|
|
+ mov r11, 0
|
|
+ rjmp __memset
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/Makefile
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/Makefile 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,40 @@
|
|
+# Makefile for uClibc
|
|
+#
|
|
+# Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org>
|
|
+#
|
|
+# This program is free software; you can redistribute it and/or modify it under
|
|
+# the terms of the GNU Library General Public License as published by the Free
|
|
+# Software Foundation; either version 2 of the License, or (at your option) any
|
|
+# later version.
|
|
+#
|
|
+# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
|
|
+# details.
|
|
+#
|
|
+# You should have received a copy of the GNU Library General Public License
|
|
+# along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
+
|
|
+TOPDIR=../../../
|
|
+include $(TOPDIR)Rules.mak
|
|
+
|
|
+SSRC := bcopy.S bzero.S memcmp.S memcpy.S memmove.S
|
|
+SSRC += memset.S strcmp.S strlen.S
|
|
+# memchr.S, strcat.S, strcpy.S, strncpy.S is broken
|
|
+SOBJS := $(patsubst %.S,%.o, $(SSRC))
|
|
+OBJS := $(SOBJS)
|
|
+
|
|
+OBJ_LIST:= ../../obj.string.$(TARGET_ARCH)
|
|
+
|
|
+all: $(OBJ_LIST)
|
|
+
|
|
+$(OBJ_LIST): $(OBJS)
|
|
+ echo $(addprefix string/$(TARGET_ARCH)/, $(OBJS)) > $@
|
|
+
|
|
+$(SOBJS): %.o: %.S
|
|
+ $(CC) $(ASFLAGS) -c $< -o $@
|
|
+ $(STRIPTOOL) -x -R .note -R .comment $@
|
|
+
|
|
+clean:
|
|
+ $(RM) *.[oa] *~ core
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/memchr.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/memchr.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,62 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+#define str r12
|
|
+#define chr r11
|
|
+#define len r10
|
|
+
|
|
+ .text
|
|
+ .global memchr
|
|
+ .type memchr, @function
|
|
+memchr:
|
|
+ or chr, chr, chr << 8
|
|
+ or chr, chr, chr << 16
|
|
+
|
|
+ mov r9, str
|
|
+ andl r9, 3, COH
|
|
+ brne .Lunaligned_str
|
|
+
|
|
+1: sub len, 4
|
|
+ brlt 2f
|
|
+ ld.w r8, str++
|
|
+ psub.b r9, r8, r11
|
|
+ tnbz r9
|
|
+ brne 1b
|
|
+
|
|
+ sub str, 4
|
|
+ bfextu r9, r8, 24, 8
|
|
+ cp.b r9, r11
|
|
+ reteq str
|
|
+ sub str, -1
|
|
+ bfextu r9, r8, 16, 8
|
|
+ cp.b r9, r11
|
|
+ reteq str
|
|
+ sub str, -1
|
|
+ bfextu r9, r8, 8, 8
|
|
+ cp.b r9, r11
|
|
+ reteq str
|
|
+ sub str, -1
|
|
+ retal str
|
|
+
|
|
+2: sub len, -4
|
|
+ reteq 0
|
|
+
|
|
+3: ld.ub r8, str++
|
|
+ cp.w r8, 0
|
|
+ reteq str
|
|
+ sub len, 1
|
|
+ brne 3b
|
|
+
|
|
+ retal 0
|
|
+
|
|
+.Lunaligned_str:
|
|
+1: sub len, 1
|
|
+ retlt 0
|
|
+ ld.ub r8, str++
|
|
+ cp.b r8, r11
|
|
+ reteq str
|
|
+ sub r9, 1
|
|
+ brge 1b
|
|
+
|
|
+ rjmp .Laligned_search
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/memcmp.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/memcmp.S 2006-10-20 10:42:09.000000000 +0200
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway.
|
|
+ */
|
|
+
|
|
+#define s1 r12
|
|
+#define s2 r11
|
|
+#define len r10
|
|
+
|
|
+ .text
|
|
+ .global memcmp
|
|
+ .type memcmp, @function
|
|
+ .align 1
|
|
+memcmp:
|
|
+ sub len, 4
|
|
+ brlt .Lless_than_4
|
|
+
|
|
+1: ld.w r8, s1++
|
|
+ ld.w r9, s2++
|
|
+ cp.w r8, r9
|
|
+ brne .Lfound_word
|
|
+ sub len, 4
|
|
+ brge 1b
|
|
+
|
|
+.Lless_than_4:
|
|
+ sub len, -4
|
|
+ reteq 0
|
|
+
|
|
+1: ld.ub r8, s1++
|
|
+ ld.ub r9, s2++
|
|
+ sub r8, r9
|
|
+ retne r8
|
|
+ sub len, 1
|
|
+ brgt 1b
|
|
+
|
|
+ retal 0
|
|
+
|
|
+.Lfound_word:
|
|
+ psub.b r9, r8, r9
|
|
+ bfextu r8, r9, 24, 8
|
|
+ retne r8
|
|
+ bfextu r8, r9, 16, 8
|
|
+ retne r8
|
|
+ bfextu r8, r9, 8, 8
|
|
+ retne r8
|
|
+ retal r9
|
|
+
|
|
+ .size memcmp, . - memcmp
|
|
+
|
|
+ .weak bcmp
|
|
+ bcmp = memcmp
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/memcpy.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/memcpy.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,110 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+/* Don't use r12 as dst since we must return it unmodified */
|
|
+#define dst r9
|
|
+#define src r11
|
|
+#define len r10
|
|
+
|
|
+ .text
|
|
+ .global memcpy
|
|
+ .type memcpy, @function
|
|
+
|
|
+ .global __memcpy
|
|
+ .hidden __memcpy
|
|
+ .type __memcpy, @function
|
|
+memcpy:
|
|
+__memcpy:
|
|
+ pref src[0]
|
|
+ mov dst, r12
|
|
+
|
|
+ /* If we have less than 32 bytes, don't do anything fancy */
|
|
+ cp.w len, 32
|
|
+ brge .Lmore_than_31
|
|
+
|
|
+ sub len, 1
|
|
+ retlt r12
|
|
+1: ld.ub r8, src++
|
|
+ st.b dst++, r8
|
|
+ sub len, 1
|
|
+ brge 1b
|
|
+ retal r12
|
|
+
|
|
+.Lmore_than_31:
|
|
+ pushm r0-r7, lr
|
|
+
|
|
+ /* Check alignment */
|
|
+ mov r8, src
|
|
+ andl r8, 31, COH
|
|
+ brne .Lunaligned_src
|
|
+ mov r8, dst
|
|
+ andl r8, 3, COH
|
|
+ brne .Lunaligned_dst
|
|
+
|
|
+.Laligned_copy:
|
|
+ sub len, 32
|
|
+ brlt .Lless_than_32
|
|
+
|
|
+1: /* Copy 32 bytes at a time */
|
|
+ ldm src, r0-r7
|
|
+ sub src, -32
|
|
+ stm dst, r0-r7
|
|
+ sub dst, -32
|
|
+ sub len, 32
|
|
+ brge 1b
|
|
+
|
|
+.Lless_than_32:
|
|
+ /* Copy 16 more bytes if possible */
|
|
+ sub len, -16
|
|
+ brlt .Lless_than_16
|
|
+ ldm src, r0-r3
|
|
+ sub src, -16
|
|
+ sub len, 16
|
|
+ stm dst, r0-r3
|
|
+ sub dst, -16
|
|
+
|
|
+.Lless_than_16:
|
|
+ /* Do the remaining as byte copies */
|
|
+ neg len
|
|
+ add pc, pc, len << 2
|
|
+ .rept 15
|
|
+ ld.ub r0, src++
|
|
+ st.b dst++, r0
|
|
+ .endr
|
|
+
|
|
+ popm r0-r7, pc
|
|
+
|
|
+.Lunaligned_src:
|
|
+ /* Make src cacheline-aligned. r8 = (src & 31) */
|
|
+ rsub r8, r8, 32
|
|
+ sub len, r8
|
|
+1: ld.ub r0, src++
|
|
+ st.b dst++, r0
|
|
+ sub r8, 1
|
|
+ brne 1b
|
|
+
|
|
+ /* If dst is word-aligned, we're ready to go */
|
|
+ pref src[0]
|
|
+ mov r8, 3
|
|
+ tst dst, r8
|
|
+ breq .Laligned_copy
|
|
+
|
|
+.Lunaligned_dst:
|
|
+ /* src is aligned, but dst is not. Expect bad performance */
|
|
+ sub len, 4
|
|
+ brlt 2f
|
|
+1: ld.w r0, src++
|
|
+ st.w dst++, r0
|
|
+ sub len, 4
|
|
+ brge 1b
|
|
+
|
|
+2: neg len
|
|
+ add pc, pc, len << 2
|
|
+ .rept 3
|
|
+ ld.ub r0, src++
|
|
+ st.b dst++, r0
|
|
+ .endr
|
|
+
|
|
+ popm r0-r7, pc
|
|
+ .size memcpy, . - memcpy
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/memmove.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/memmove.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,114 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+#define dst r12
|
|
+#define src r11
|
|
+#define len r10
|
|
+
|
|
+ .text
|
|
+ .global memmove
|
|
+ .type memmove, @function
|
|
+
|
|
+ .global __memmove
|
|
+ .hidden __memmove
|
|
+ .type __memmove, @function
|
|
+memmove:
|
|
+__memmove:
|
|
+ cp.w src, dst
|
|
+ brge __memcpy
|
|
+
|
|
+ add dst, len
|
|
+ add src, len
|
|
+ pref src[-1]
|
|
+
|
|
+ /*
|
|
+ * The rest is basically the same as in memcpy.S except that
|
|
+ * the direction is reversed.
|
|
+ */
|
|
+ cp.w len, 32
|
|
+ brge .Lmore_than_31
|
|
+
|
|
+ sub len, 1
|
|
+ retlt r12
|
|
+1: ld.ub r8, --src
|
|
+ st.b --dst, r8
|
|
+ sub len, 1
|
|
+ brge 1b
|
|
+ retal r12
|
|
+
|
|
+.Lmore_than_31:
|
|
+ pushm r0-r7, lr
|
|
+
|
|
+ /* Check alignment */
|
|
+ mov r8, src
|
|
+ andl r8, 31, COH
|
|
+ brne .Lunaligned_src
|
|
+ mov r8, r12
|
|
+ andl r8, 3, COH
|
|
+ brne .Lunaligned_dst
|
|
+
|
|
+.Laligned_copy:
|
|
+ sub len, 32
|
|
+ brlt .Lless_than_32
|
|
+
|
|
+1: /* Copy 32 bytes at a time */
|
|
+ sub src, 32
|
|
+ ldm src, r0-r7
|
|
+ sub dst, 32
|
|
+ sub len, 32
|
|
+ stm dst, r0-r7
|
|
+ brge 1b
|
|
+
|
|
+.Lless_than_32:
|
|
+ /* Copy 16 more bytes if possible */
|
|
+ sub len, -16
|
|
+ brlt .Lless_than_16
|
|
+ sub src, 16
|
|
+ ldm src, r0-r3
|
|
+ sub dst, 16
|
|
+ sub len, 16
|
|
+ stm dst, r0-r3
|
|
+
|
|
+.Lless_than_16:
|
|
+ /* Do the remaining as byte copies */
|
|
+ sub len, -16
|
|
+ breq 2f
|
|
+1: ld.ub r0, --src
|
|
+ st.b --dst, r0
|
|
+ sub len, 1
|
|
+ brne 1b
|
|
+
|
|
+2: popm r0-r7, pc
|
|
+
|
|
+.Lunaligned_src:
|
|
+ /* Make src cacheline-aligned. r8 = (src & 31) */
|
|
+ sub len, r8
|
|
+1: ld.ub r0, --src
|
|
+ st.b --dst, r0
|
|
+ sub r8, 1
|
|
+ brne 1b
|
|
+
|
|
+ /* If dst is word-aligned, we're ready to go */
|
|
+ pref src[-4]
|
|
+ mov r8, 3
|
|
+ tst dst, r8
|
|
+ breq .Laligned_copy
|
|
+
|
|
+.Lunaligned_dst:
|
|
+ /* src is aligned, but dst is not. Expect bad performance */
|
|
+ sub len, 4
|
|
+ brlt 2f
|
|
+1: ld.w r0, --src
|
|
+ st.w --dst, r0
|
|
+ sub len, 4
|
|
+ brge 1b
|
|
+
|
|
+2: neg len
|
|
+ add pc, pc, len << 2
|
|
+ .rept 3
|
|
+ ld.ub r0, --src
|
|
+ st.b --dst, r0
|
|
+ .endr
|
|
+
|
|
+ popm r0-r7, pc
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/memset.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/memset.S 2006-10-20 10:42:15.000000000 +0200
|
|
@@ -0,0 +1,60 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway.
|
|
+ */
|
|
+
|
|
+#define s r12
|
|
+#define c r11
|
|
+#define n r10
|
|
+
|
|
+ .text
|
|
+ .global memset
|
|
+ .type memset, @function
|
|
+
|
|
+ .global __memset
|
|
+ .hidden __memset
|
|
+ .type __memset, @function
|
|
+
|
|
+ .align 1
|
|
+memset:
|
|
+__memset:
|
|
+ cp.w n, 32
|
|
+ mov r9, s
|
|
+ brge .Llarge_memset
|
|
+
|
|
+ sub n, 1
|
|
+ retlt s
|
|
+1: st.b s++, c
|
|
+ sub n, 1
|
|
+ brge 1b
|
|
+
|
|
+ retal r9
|
|
+
|
|
+.Llarge_memset:
|
|
+ mov r8, r11
|
|
+ mov r11, 3
|
|
+ bfins r8, r8, 8, 8
|
|
+ bfins r8, r8, 16, 16
|
|
+ tst s, r11
|
|
+ breq 2f
|
|
+
|
|
+1: st.b s++, r8
|
|
+ sub n, 1
|
|
+ tst s, r11
|
|
+ brne 1b
|
|
+
|
|
+2: mov r11, r9
|
|
+ mov r9, r8
|
|
+ sub n, 8
|
|
+
|
|
+3: st.d s++, r8
|
|
+ sub n, 8
|
|
+ brge 3b
|
|
+
|
|
+ /* If we are done, n == -8 and we'll skip all st.b insns below */
|
|
+ neg n
|
|
+ lsl n, 1
|
|
+ add pc, n
|
|
+ .rept 7
|
|
+ st.b s++, r8
|
|
+ .endr
|
|
+ retal r11
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/strcat.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/strcat.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,95 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+#define s1 r9
|
|
+#define s2 r11
|
|
+
|
|
+ .text
|
|
+ .global strcat
|
|
+ .type strcat, @function
|
|
+ .align 1
|
|
+strcat:
|
|
+ mov s1, r12
|
|
+
|
|
+ /* Make sure s1 is word-aligned */
|
|
+ mov r10, s1
|
|
+ andl r10, 3, COH
|
|
+ breq 2f
|
|
+
|
|
+ add pc, pc, r10 << 3
|
|
+ sub r0, r0, 0 /* 4-byte nop */
|
|
+ ld.ub r8, s1++
|
|
+ sub r8, r8, 0
|
|
+ breq 2f
|
|
+ ld.ub r8, s1++
|
|
+ sub r8, r8, 0
|
|
+ breq 3f
|
|
+ ld.ub r8, s1++
|
|
+ sub r8, r8, 0
|
|
+ breq 4f
|
|
+
|
|
+ /* Find the end of the first string */
|
|
+5: ld.w r8, s1++
|
|
+ tnbz r8
|
|
+ brne 5b
|
|
+
|
|
+ sub s1, 4
|
|
+
|
|
+ bfextu r10, r8, 24, 8
|
|
+ cp.w r10, 0
|
|
+ breq 1f
|
|
+ sub s1, -1
|
|
+ bfextu r10, r8, 16, 8
|
|
+ cp.w r10, 0
|
|
+ breq 2f
|
|
+ sub s1, -1
|
|
+ bfextu r10, r8, 8, 8
|
|
+ cp.w r10, 0
|
|
+ breq 3f
|
|
+ sub s1, -1
|
|
+ rjmp 4f
|
|
+
|
|
+ /* Now, append s2 */
|
|
+1: ld.ub r8, s2++
|
|
+ st.b s1++, r8
|
|
+ cp.w r8, 0
|
|
+ reteq r12
|
|
+2: ld.ub r8, s2++
|
|
+ st.b s1++, r8
|
|
+ cp.w r8, 0
|
|
+ reteq r12
|
|
+3: ld.ub r8, s2++
|
|
+ st.b s1++, r8
|
|
+ cp.w r8, 0
|
|
+ reteq r12
|
|
+4: ld.ub r8, s2++
|
|
+ st.b s1++, r8
|
|
+ cp.w r8, 0
|
|
+ reteq r12
|
|
+
|
|
+ /* Copy one word at a time */
|
|
+ ld.w r8, s2++
|
|
+ tnbz r8
|
|
+ breq 2f
|
|
+1: st.w r8, s2++
|
|
+ ld.w r8, s2++
|
|
+ tnbz r8
|
|
+ brne 1b
|
|
+
|
|
+ /* Copy the remaining bytes */
|
|
+ bfextu r10, r8, 24, 8
|
|
+ st.b s1++, r10
|
|
+ cp.w r10, 0
|
|
+ reteq r12
|
|
+ bfextu r10, r8, 16, 8
|
|
+ st.b s1++, r10
|
|
+ cp.w r10, 0
|
|
+ reteq r12
|
|
+ bfextu r10, r8, 8, 8
|
|
+ st.b s1++, r10
|
|
+ cp.w r10, 0
|
|
+ reteq r12
|
|
+ st.b s1++, r8
|
|
+ retal r12
|
|
+ .size strcat, . - strcat
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/strcmp.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/strcmp.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,80 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway.
|
|
+ */
|
|
+
|
|
+#define s1 r12
|
|
+#define s2 r11
|
|
+#define len r10
|
|
+
|
|
+ .text
|
|
+ .global strcmp
|
|
+ .type strcmp, @function
|
|
+ .align 1
|
|
+strcmp:
|
|
+ mov r8, 3
|
|
+ tst s1, r8
|
|
+ brne .Lunaligned_s1
|
|
+ tst s2, r8
|
|
+ brne .Lunaligned_s2
|
|
+
|
|
+1: ld.w r8, s1++
|
|
+ ld.w r9, s2++
|
|
+ cp.w r8, r9
|
|
+ brne 2f
|
|
+ tnbz r8
|
|
+ brne 1b
|
|
+ retal 0
|
|
+
|
|
+2: bfextu r12, r8, 24, 8
|
|
+ bfextu r11, r9, 24, 8
|
|
+ sub r12, r11
|
|
+ retne r12
|
|
+ cp.w r11, 0
|
|
+ reteq 0
|
|
+ bfextu r12, r8, 16, 8
|
|
+ bfextu r11, r9, 16, 8
|
|
+ sub r12, r11
|
|
+ retne r12
|
|
+ cp.w r11, 0
|
|
+ reteq 0
|
|
+ bfextu r12, r8, 8, 8
|
|
+ bfextu r11, r9, 8, 8
|
|
+ sub r12, r11
|
|
+ retne r12
|
|
+ cp.w r11, 0
|
|
+ reteq 0
|
|
+ bfextu r12, r8, 0, 8
|
|
+ bfextu r11, r9, 0, 8
|
|
+ sub r12, r11
|
|
+ retal r12
|
|
+
|
|
+.Lunaligned_s1:
|
|
+3: tst s1, r8
|
|
+ breq 4f
|
|
+ ld.ub r10, s1++
|
|
+ ld.ub r9, s2++
|
|
+ sub r10, r9
|
|
+ retne r10
|
|
+ cp.w r9, 0
|
|
+ brne 3b
|
|
+ retal r10
|
|
+
|
|
+4: tst s2, r8
|
|
+ breq 1b
|
|
+
|
|
+.Lunaligned_s2:
|
|
+ /*
|
|
+ * s1 and s2 can't both be aligned, and unaligned word loads
|
|
+ * can trigger spurious exceptions if we cross a page boundary.
|
|
+ * Do it the slow way...
|
|
+ */
|
|
+1: ld.ub r8, s1++
|
|
+ ld.ub r9, s2++
|
|
+ sub r8, r9
|
|
+ retne r8
|
|
+ cp.w r9, 0
|
|
+ brne 1b
|
|
+ retal 0
|
|
+
|
|
+ .weak strcoll
|
|
+ strcoll = strcmp
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/strcpy.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/strcpy.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,63 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ *
|
|
+ * To reduce the size, this one might simply call strncpy with len = -1.
|
|
+ */
|
|
+
|
|
+#define dst r9
|
|
+#define src r11
|
|
+
|
|
+ .text
|
|
+ .global strcpy
|
|
+ .type strcpy, @function
|
|
+strcpy:
|
|
+ mov dst, r12
|
|
+
|
|
+ pref src[0]
|
|
+
|
|
+ /*
|
|
+ * Check alignment. If src is aligned but dst isn't, we can't
|
|
+ * do much about it...
|
|
+ */
|
|
+ mov r8, src
|
|
+ andl r8, 3 COH
|
|
+ brne .Lunaligned_src
|
|
+
|
|
+.Laligned_copy:
|
|
+1: ld.w r8, src++
|
|
+ tnbz r8
|
|
+ breq 2f
|
|
+ st.w dst++, r8
|
|
+ rjmp 1b
|
|
+
|
|
+2: /*
|
|
+ * Ok, r8 now contains the terminating '\0'. Copy the
|
|
+ * remaining bytes individually.
|
|
+ */
|
|
+ bfextu r10, r8, 24, 8
|
|
+ st.b dst++, r10
|
|
+ cp.w r10, 0
|
|
+ reteq r12
|
|
+ bfextu r10, r8, 16, 8
|
|
+ st.b dst++, r10
|
|
+ cp.w r10, 0
|
|
+ reteq r12
|
|
+ bfextu r10, r8, 8, 8
|
|
+ st.b dst++, r10
|
|
+ cp.w r10, 0
|
|
+ reteq r12
|
|
+ st.b dst++, r8
|
|
+ retal r12
|
|
+
|
|
+.Lunaligned_src:
|
|
+ /* Copy bytes until we're aligned */
|
|
+ rsub r8, r8, 4
|
|
+ add pc, pc, r8 << 3
|
|
+ nop
|
|
+ nop
|
|
+ ld.ub r10, src++
|
|
+ st.b dst++, r10
|
|
+ cp.w r10, 0
|
|
+ reteq r12
|
|
+
|
|
+ rjmp .Laligned_copy
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/stringtest.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/stringtest.c 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,144 @@
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <time.h>
|
|
+#include <sys/mman.h>
|
|
+
|
|
+#define BUF_SIZE (8 * 1024)
|
|
+
|
|
+static char *buf1;
|
|
+static char *buf1_ref;
|
|
+static char *buf2;
|
|
+
|
|
+extern void *optimized_memcpy(void *dest, void *src, size_t len);
|
|
+extern void *optimized_memmove(void *dest, void *src, size_t len);
|
|
+extern char *optimized_strcpy(char *dest, char *src);
|
|
+extern char *optimized_strncpy(char *dest, char *src, size_t len);
|
|
+
|
|
+void dump_mismatch(char *buf, char *ref, size_t len)
|
|
+{
|
|
+ int i, j;
|
|
+
|
|
+ for (i = 0; i < len; i += 16) {
|
|
+ if (memcmp(buf + i, ref + i, 16) == 0)
|
|
+ continue;
|
|
+
|
|
+ printf("%4x buf:", i);
|
|
+ for (j = i; j < (i + 16); j++)
|
|
+ printf(" %02x", buf[j]);
|
|
+ printf("\n ref:");
|
|
+ for (j = i; j < (i + 16); j++)
|
|
+ printf(" %02x", ref[j]);
|
|
+ printf("\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+static void test_memcpy(int src_offset, int dst_offset, int len)
|
|
+{
|
|
+ clock_t start, old, new;
|
|
+ int i;
|
|
+
|
|
+ memset(buf1, 0x55, BUF_SIZE);
|
|
+ memset(buf1_ref, 0x55, BUF_SIZE);
|
|
+ memset(buf2, 0xaa, BUF_SIZE);
|
|
+
|
|
+ printf("Testing memcpy with offsets %d => %d and len %d...",
|
|
+ src_offset, dst_offset, len);
|
|
+
|
|
+ start = clock();
|
|
+ for (i = 0; i < 8192; i++)
|
|
+ optimized_memcpy(buf1 + dst_offset, buf2 + src_offset, len);
|
|
+ new = clock() - start;
|
|
+ start = clock();
|
|
+ for ( i = 0; i < 8192; i++)
|
|
+ memcpy(buf1_ref + dst_offset, buf2 + src_offset, len);
|
|
+ old = clock() - start;
|
|
+
|
|
+ if (memcmp(buf1, buf1_ref, BUF_SIZE) == 0)
|
|
+ printf("OK\n");
|
|
+ else {
|
|
+ printf("FAILED\n");
|
|
+ dump_mismatch(buf1, buf1_ref, BUF_SIZE);
|
|
+ }
|
|
+ printf("CPU time used: %d vs. %d\n", new, old);
|
|
+}
|
|
+
|
|
+static void test_memmove(int src_offset, int dst_offset, int len)
|
|
+{
|
|
+ clock_t start, old, new;
|
|
+
|
|
+ memset(buf1, 0x55, BUF_SIZE);
|
|
+ memset(buf1_ref, 0x55, BUF_SIZE);
|
|
+ memset(buf2, 0xaa, BUF_SIZE);
|
|
+
|
|
+ printf("Testing memmove with offsets %d => %d and len %d...",
|
|
+ src_offset, dst_offset, len);
|
|
+
|
|
+ start = clock();
|
|
+ optimized_memmove(buf1 + dst_offset, buf2 + src_offset, len);
|
|
+ new = clock() - start;
|
|
+ start = clock();
|
|
+ memmove(buf1_ref + dst_offset, buf2 + src_offset, len);
|
|
+ old = clock() - start;
|
|
+
|
|
+ if (memcmp(buf1, buf1_ref, BUF_SIZE) == 0)
|
|
+ printf("OK\n");
|
|
+ else {
|
|
+ printf("FAILED\n");
|
|
+ dump_mismatch(buf1, buf1_ref, BUF_SIZE);
|
|
+ }
|
|
+ printf("CPU time used: %d vs. %d\n", new, old);
|
|
+}
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ buf2 = mmap(NULL, BUF_SIZE, PROT_READ | PROT_WRITE,
|
|
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
|
+ if (buf2 == MAP_FAILED) {
|
|
+ perror("Failed to allocate memory for buf2");
|
|
+ return 1;
|
|
+ }
|
|
+ buf1 = mmap(NULL, BUF_SIZE, PROT_READ | PROT_WRITE,
|
|
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
|
+ if (buf1 == MAP_FAILED) {
|
|
+ perror("Failed to allocate memory for buf1");
|
|
+ return 1;
|
|
+ }
|
|
+ buf1_ref = mmap(NULL, BUF_SIZE, PROT_READ | PROT_WRITE,
|
|
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
|
+ if (buf1_ref == MAP_FAILED) {
|
|
+ perror("Failed to allocate memory for buf1_ref");
|
|
+ return 1;
|
|
+ }
|
|
+ printf("\n === MEMCPY ===\n\n");
|
|
+
|
|
+ test_memcpy(0, 0, BUF_SIZE - 32);
|
|
+ test_memcpy(0, 0, 1);
|
|
+ test_memcpy(0, 0, 31);
|
|
+ test_memcpy(0, 0, 32);
|
|
+ test_memcpy(0, 0, 127);
|
|
+ test_memcpy(0, 0, 128);
|
|
+ test_memcpy(4, 4, BUF_SIZE - 32 - 4);
|
|
+ test_memcpy(1, 1, BUF_SIZE - 32 - 1);
|
|
+ test_memcpy(1, 1, 126);
|
|
+ test_memcpy(0, 3, 128);
|
|
+ test_memcpy(1, 4, 128);
|
|
+ test_memcpy(0, 0, 0);
|
|
+
|
|
+ printf("\n === MEMMOVE ===\n\n");
|
|
+
|
|
+ test_memmove(0, 0, BUF_SIZE - 32);
|
|
+ test_memmove(0, 0, 1);
|
|
+ test_memmove(0, 0, 31);
|
|
+ test_memmove(0, 0, 32);
|
|
+ test_memmove(0, 0, BUF_SIZE - 33);
|
|
+ test_memmove(0, 0, 128);
|
|
+ test_memmove(4, 4, BUF_SIZE - 32 - 4);
|
|
+ test_memmove(1, 1, BUF_SIZE - 32 - 1);
|
|
+ test_memmove(1, 1, BUF_SIZE - 130);
|
|
+ test_memmove(0, 3, BUF_SIZE - 128);
|
|
+ test_memmove(1, 4, BUF_SIZE - 128);
|
|
+ test_memmove(0, 0, 0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/strlen.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/strlen.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,52 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+#define str r12
|
|
+
|
|
+ .text
|
|
+ .global strlen
|
|
+ .type strlen, @function
|
|
+strlen:
|
|
+ mov r11, r12
|
|
+
|
|
+ mov r9, str
|
|
+ andl r9, 3, COH
|
|
+ brne .Lunaligned_str
|
|
+
|
|
+1: ld.w r8, str++
|
|
+ tnbz r8
|
|
+ brne 1b
|
|
+
|
|
+ sub r12, r11
|
|
+ bfextu r9, r8, 24, 8
|
|
+ cp.w r9, 0
|
|
+ subeq r12, 4
|
|
+ reteq r12
|
|
+ bfextu r9, r8, 16, 8
|
|
+ cp.w r9, 0
|
|
+ subeq r12, 3
|
|
+ reteq r12
|
|
+ bfextu r9, r8, 8, 8
|
|
+ cp.w r9, 0
|
|
+ subeq r12, 2
|
|
+ reteq r12
|
|
+ sub r12, 1
|
|
+ retal r12
|
|
+
|
|
+.Lunaligned_str:
|
|
+ add pc, pc, r9 << 3
|
|
+ sub r0, r0, 0 /* 4-byte nop */
|
|
+ ld.ub r8, str++
|
|
+ sub r8, r8, 0
|
|
+ breq 1f
|
|
+ ld.ub r8, str++
|
|
+ sub r8, r8, 0
|
|
+ breq 1f
|
|
+ ld.ub r8, str++
|
|
+ sub r8, r8, 0
|
|
+ brne 1b
|
|
+
|
|
+1: sub r12, 1
|
|
+ sub r12, r11
|
|
+ retal r12
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/strncpy.S
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/strncpy.S 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,77 @@
|
|
+/*
|
|
+ * Copyright (C) 2004 Atmel Norway
|
|
+ */
|
|
+
|
|
+#define dst r9
|
|
+#define src r11
|
|
+
|
|
+ .text
|
|
+ .global strcpy
|
|
+ .type strncpy, @function
|
|
+strncpy:
|
|
+ mov dst, r12
|
|
+
|
|
+ pref src[0]
|
|
+ mov dst, r12
|
|
+
|
|
+ /*
|
|
+ * Check alignment. If src is aligned but dst isn't, we can't
|
|
+ * do much about it...
|
|
+ */
|
|
+ mov r8, src
|
|
+ andl r8, 3 COH
|
|
+ brne .Lunaligned_src
|
|
+
|
|
+.Laligned_copy:
|
|
+ sub r10, 4
|
|
+ brlt 3f
|
|
+1: ld.w r8, src++
|
|
+ tnbz r8
|
|
+ breq 2f
|
|
+ st.w dst++, r8
|
|
+ sub r10, 4
|
|
+ brne 1b
|
|
+
|
|
+3: sub r10, -4
|
|
+ reteq r12
|
|
+
|
|
+ /* This is safe as long as src is word-aligned and r10 > 0 */
|
|
+ ld.w r8, src++
|
|
+
|
|
+2: /*
|
|
+ * Ok, r8 now contains the terminating '\0'. Copy the
|
|
+ * remaining bytes individually.
|
|
+ */
|
|
+ bfextu r11, r8, 24, 8
|
|
+ st.b dst++, r11
|
|
+ cp.w r11, 0
|
|
+ reteq r12
|
|
+ sub r10, 1
|
|
+ reteq r12
|
|
+ bfextu r11, r8, 16, 8
|
|
+ st.b dst++, r11
|
|
+ cp.w r11, 0
|
|
+ reteq r12
|
|
+ sub r10, 1
|
|
+ reteq r12
|
|
+ bfextu r11, r8, 8, 8
|
|
+ st.b dst++, r11
|
|
+ cp.w r11, 0
|
|
+ reteq r12
|
|
+ sub r10, 1
|
|
+ reteq r12
|
|
+ st.b dst++, r8
|
|
+ retal r12
|
|
+
|
|
+.Lunaligned_src:
|
|
+ /* Copy bytes until we're aligned */
|
|
+ min r8, r8, r10
|
|
+ sub r10, r8
|
|
+ sub r8, 1
|
|
+ retlt r12
|
|
+1: ld.ub r10, src++
|
|
+ st.b dst++, r10
|
|
+ sub r8, 1
|
|
+ brge 1b
|
|
+
|
|
+ rjmp .Laligned_copy
|
|
Index: uClibc-0.9.28-avr32/libc/string/avr32/test_memcpy.c
|
|
===================================================================
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ uClibc-0.9.28-avr32/libc/string/avr32/test_memcpy.c 2006-10-19 15:05:52.000000000 +0200
|
|
@@ -0,0 +1,66 @@
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+#define BUF_SIZE 32768
|
|
+
|
|
+static char buf1[BUF_SIZE] __attribute__((aligned(32)));
|
|
+static char buf1_ref[BUF_SIZE] __attribute__((aligned(32)));
|
|
+static char buf2[BUF_SIZE] __attribute__((aligned(32)));
|
|
+
|
|
+extern void *new_memcpy(void *dest, void *src, size_t len);
|
|
+
|
|
+void dump_mismatch(char *buf, char *ref, size_t len)
|
|
+{
|
|
+ int i, j;
|
|
+
|
|
+ for (i = 0; i < len; i += 16) {
|
|
+ if (memcmp(buf + i, ref + i, 16) == 0)
|
|
+ continue;
|
|
+
|
|
+ printf("% 4x buf:", i);
|
|
+ for (j = i; j < (i + 16); j++)
|
|
+ printf(" %02x", buf[j]);
|
|
+ printf("\n ref:");
|
|
+ for (j = i; j < (i + 16); j++)
|
|
+ printf(" %02x", ref[j]);
|
|
+ printf("\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+void test(int src_offset, int dst_offset, int len)
|
|
+{
|
|
+ memset(buf1, 0x55, sizeof(buf1));
|
|
+ memset(buf1_ref, 0x55, sizeof(buf1_ref));
|
|
+ memset(buf2, 0xaa, sizeof(buf2));
|
|
+
|
|
+ printf("Testing with offsets %d => %d and len %d...",
|
|
+ src_offset, dst_offset, len);
|
|
+
|
|
+ new_memcpy(buf1 + dst_offset, buf2 + src_offset, len);
|
|
+ memcpy(buf1_ref + dst_offset, buf2 + src_offset, len);
|
|
+
|
|
+ if (memcmp(buf1, buf1_ref, sizeof(buf1)) == 0)
|
|
+ printf("OK\n");
|
|
+ else {
|
|
+ printf("FAILED\n");
|
|
+ dump_mismatch(buf1, buf1_ref, sizeof(buf1));
|
|
+ }
|
|
+}
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ test(0, 0, BUF_SIZE);
|
|
+ test(0, 0, 1);
|
|
+ test(0, 0, 31);
|
|
+ test(0, 0, 32);
|
|
+ test(0, 0, 127);
|
|
+ test(0, 0, 128);
|
|
+ test(4, 4, BUF_SIZE - 4);
|
|
+ test(1, 1, BUF_SIZE - 1);
|
|
+ test(1, 1, 126);
|
|
+ test(0, 3, 128);
|
|
+ test(1, 4, 128);
|
|
+
|
|
+ return 0;
|
|
+}
|