This is the mail archive of the
newlib@sources.redhat.com
mailing list for the newlib project.
Mips optimized versions of strlen, strncpy, strcmp
- To: newlib at sources dot redhat dot com
- Subject: Mips optimized versions of strlen, strncpy, strcmp
- From: Michael Meissner <meissner at redhat dot com>
- Date: Tue, 13 Nov 2001 15:44:06 -0500
I was doing some benchmarking of the MIPS compiler, and noticed that
one of the benchmarks could be improved by writing faster versions of
some of the string routines, which are tuned towards the MIPS
architecture (ok, ok, one is written in assembler). In general, I
feel that the str* (& to some extent the mem*) functions in newlib
could be better tuned for different machines (I suspect you may wind
up with 3-4 versions, depending on whether a machine has pre or post
incrementation, how deep the pipeline is to/from memory, etc.). Is
this ok to apply?
2001-11-13 Michael Meissner <meissner@redhat.com>
* libc/machine/mips/Makefile.am (lib_a_SOURCES): Add strlen.c,
strcmp.c, and strncpy.c.
* libc/machine/mips/Makefile.in: Regenerate.
* libc/machine/mips/strlen.c: New implementation tuned for MIPS.
* libc/machine/mips/strcmp.c: New implementation tuned for MIPS.
* libc/machine/mips/strncpy.c: New implementation tuned for MIPS.
*** newlib/libc/machine/mips/Makefile.am.~1~ Tue Nov 13 15:31:49 2001
--- newlib/libc/machine/mips/Makefile.am Wed Oct 24 19:15:50 2001
*************** INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLA
*** 6,12 ****
noinst_LIBRARIES = lib.a
! lib_a_SOURCES = setjmp.S
ACLOCAL_AMFLAGS = -I ../../..
CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
--- 6,12 ----
noinst_LIBRARIES = lib.a
! lib_a_SOURCES = setjmp.S strlen.c strcmp.c strncpy.c
ACLOCAL_AMFLAGS = -I ../../..
CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
*** newlib/libc/machine/mips/Makefile.in.~1~ Tue Nov 13 15:31:49 2001
--- newlib/libc/machine/mips/Makefile.in Tue Nov 13 15:32:52 2001
***************
*** 1,6 ****
! # Makefile.in generated automatically by automake 1.3 from Makefile.am
! # Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
--- 1,6 ----
! # Makefile.in generated automatically by automake 1.4 from Makefile.am
! # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
*************** mandir = @mandir@
*** 32,38 ****
includedir = @includedir@
oldincludedir = /usr/include
! DISTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
--- 32,38 ----
includedir = @includedir@
oldincludedir = /usr/include
! DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
*************** AUTOMAKE = @AUTOMAKE@
*** 46,52 ****
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
! INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
--- 46,52 ----
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
! INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
*************** INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLA
*** 80,86 ****
noinst_LIBRARIES = lib.a
! lib_a_SOURCES = setjmp.S
ACLOCAL_AMFLAGS = -I ../../..
CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
--- 80,86 ----
noinst_LIBRARIES = lib.a
! lib_a_SOURCES = setjmp.S strlen.c strcmp.c strncpy.c
ACLOCAL_AMFLAGS = -I ../../..
CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
*************** CPPFLAGS = @CPPFLAGS@
*** 95,132 ****
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
lib_a_LIBADD =
! lib_a_OBJECTS = setjmp.o
CFLAGS = @CFLAGS@
! COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
! LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@
DIST_COMMON = Makefile.am Makefile.in aclocal.m4 configure configure.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
! TAR = tar
! GZIP = --best
SOURCES = $(lib_a_SOURCES)
OBJECTS = $(lib_a_OBJECTS)
! all: Makefile $(LIBRARIES)
!
.SUFFIXES:
.SUFFIXES: .S .c .o .s
! $(srcdir)/Makefile.in: @MAINT@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --cygnus Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
! $(ACLOCAL_M4): @MAINT@ configure.in ../../../acinclude.m4 \
! ../../../aclocal.m4
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
! $(srcdir)/configure: @MAINT@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
cd $(srcdir) && $(AUTOCONF)
mostlyclean-noinstLIBRARIES:
--- 95,132 ----
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
lib_a_LIBADD =
! lib_a_OBJECTS = setjmp.o strlen.o strcmp.o strncpy.o
CFLAGS = @CFLAGS@
! COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
! CCLD = $(CC)
! LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
DIST_COMMON = Makefile.am Makefile.in aclocal.m4 configure configure.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
! TAR = gtar
! GZIP_ENV = --best
SOURCES = $(lib_a_SOURCES)
OBJECTS = $(lib_a_OBJECTS)
! all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .o .s
! $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --cygnus Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
! $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in \
! ../../../acinclude.m4 ../../../aclocal.m4
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
! $(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
cd $(srcdir) && $(AUTOCONF)
mostlyclean-noinstLIBRARIES:
*************** lib.a: $(lib_a_OBJECTS) $(lib_a_DEPENDEN
*** 165,172 ****
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
here=`pwd` && cd $(srcdir) \
! && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
--- 165,176 ----
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
! && mkid -f$$here/ID $$unique $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
*************** top_distdir = $(distdir)
*** 195,201 ****
# tarfile.
distcheck: dist
-rm -rf $(distdir)
! GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz
mkdir $(distdir)/=build
mkdir $(distdir)/=inst
dc_install_base=`cd $(distdir)/=inst && pwd`; \
--- 199,205 ----
# tarfile.
distcheck: dist
-rm -rf $(distdir)
! GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
mkdir $(distdir)/=build
mkdir $(distdir)/=inst
dc_install_base=`cd $(distdir)/=inst && pwd`; \
*************** distcheck: dist
*** 208,223 ****
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) dist
-rm -rf $(distdir)
! @echo "========================"; \
! echo "$(distdir).tar.gz is ready for distribution"; \
! echo "========================"
dist: distdir
-chmod -R a+r $(distdir)
! GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
-rm -rf $(distdir)
dist-all: distdir
-chmod -R a+r $(distdir)
! GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
-rm -rf $(distdir)
distdir: $(DISTFILES)
-rm -rf $(distdir)
--- 212,229 ----
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) dist
-rm -rf $(distdir)
! @banner="$(distdir).tar.gz is ready for distribution"; \
! dashes=`echo "$$banner" | sed s/./=/g`; \
! echo "$$dashes"; \
! echo "$$banner"; \
! echo "$$dashes"
dist: distdir
-chmod -R a+r $(distdir)
! GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
-rm -rf $(distdir)
dist-all: distdir
-chmod -R a+r $(distdir)
! GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
-rm -rf $(distdir)
distdir: $(DISTFILES)
-rm -rf $(distdir)
*************** distdir: $(DISTFILES)
*** 225,294 ****
-chmod 777 $(distdir)
@for file in $(DISTFILES); do \
if test -f $$file; then d=.; else d=$(srcdir); fi; \
! test -f $(distdir)/$$file \
! || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
! || cp -p $$d/$$file $(distdir)/$$file; \
done
! info:
! dvi:
! check:
! $(MAKE) $(AM_MAKEFLAGS)
! installcheck:
! install-info:
! install-exec:
! @$(NORMAL_INSTALL)
!
! install-data:
! @$(NORMAL_INSTALL)
!
! install: install-exec install-data all
! @:
!
! uninstall:
!
install-strip:
! $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
installdirs:
mostlyclean-generic:
- -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
- -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
! -rm -f Makefile $(DISTCLEANFILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
! -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
! -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
! mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
! clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
! mostlyclean
! distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
! distclean-generic clean
-rm -f config.status
! maintainer-clean: maintainer-clean-noinstLIBRARIES \
maintainer-clean-compile maintainer-clean-tags \
! maintainer-clean-generic distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
-rm -f config.status
.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
! clean-tags maintainer-clean-tags distdir info dvi installcheck \
! install-info install-exec install-data install uninstall all \
! installdirs mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
--- 231,315 ----
-chmod 777 $(distdir)
@for file in $(DISTFILES); do \
if test -f $$file; then d=.; else d=$(srcdir); fi; \
! if test -d $$d/$$file; then \
! cp -pr $$d/$$file $(distdir)/$$file; \
! else \
! test -f $(distdir)/$$file \
! || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
! || cp -p $$d/$$file $(distdir)/$$file || :; \
! fi; \
done
! info-am:
! info: info-am
! dvi-am:
! dvi: dvi-am
! check-am:
! check: check-am
! installcheck-am:
! installcheck: installcheck-am
! install-info-am:
! install-info: install-info-am
! install-exec-am:
! install-exec: install-exec-am
!
! install-data-am:
! install-data: install-data-am
!
! install-am: all-am
! @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
! install: install-am
! uninstall-am:
! uninstall: uninstall-am
! all-am: Makefile $(LIBRARIES)
! all-redirect: all-am
install-strip:
! $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
mostlyclean-generic:
clean-generic:
distclean-generic:
! -rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
! mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
! mostlyclean: mostlyclean-am
!
! clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
! mostlyclean-am
! clean: clean-am
!
! distclean-am: distclean-noinstLIBRARIES distclean-compile \
! distclean-tags distclean-generic clean-am
!
! distclean: distclean-am
-rm -f config.status
! maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
maintainer-clean-compile maintainer-clean-tags \
! maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
+
+ maintainer-clean: maintainer-clean-am
-rm -f config.status
.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
! clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
! check-am installcheck-am installcheck install-info-am install-info \
! install-exec-am install-exec install-data-am install-data install-am \
! install uninstall-am uninstall all-redirect all-am all installdirs \
! mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
*** newlib/libc/machine/mips/strcmp.c.~1~ Wed Oct 24 19:15:07 2001
--- newlib/libc/machine/mips/strcmp.c Wed Oct 24 19:14:41 2001
***************
*** 0 ****
--- 1,71 ----
+ /*
+ * strcmp.c -- strcmp function. On at least some MIPS chips, a strcmp that is
+ * unrolled twice is faster than the 'optimized' C version in newlib.
+ *
+ * Copyright (c) 2001 Red Hat, Inc.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply. */
+
+ #include <stddef.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ int
+ strcmp (const char *s1, const char *s2)
+ {
+ unsigned const char *us1 = (unsigned const char *)s1;
+ unsigned const char *us2 = (unsigned const char *)s2;
+ int c1a, c1b;
+ int c2a, c2b;
+
+ /* If the pointers aren't both aligned to a 16-byte boundary, do the
+ comparison byte by byte, so that we don't get an invalid page fault if we
+ are comparing a string whose null byte is at the last byte on the last
+ valid page. */
+ if (((((long)us1) | ((long)us2)) & 1) == 0)
+ {
+ c1a = *us1;
+ for (;;)
+ {
+ c1b = *us2;
+ us1 += 2;
+ if (c1a == '\0')
+ goto ret1;
+
+ c2a = us1[-1];
+ if (c1a != c1b)
+ goto ret1;
+
+ c2b = us2[1];
+ us2 += 2;
+ if (c2a == '\0')
+ break;
+
+ c1a = *us1;
+ if (c2a != c2b)
+ break;
+ }
+
+ return c2a - c2b;
+ }
+ else
+ {
+ do
+ {
+ c1a = *us1++;
+ c1b = *us2++;
+ }
+ while (c1a != '\0' && c1a == c1b);
+ }
+
+ ret1:
+ return c1a - c1b;
+ }
*** newlib/libc/machine/mips/strlen.c.~1~ Wed Oct 24 19:15:07 2001
--- newlib/libc/machine/mips/strlen.c Wed Oct 24 19:14:41 2001
***************
*** 0 ****
--- 1,70 ----
+ /*
+ * strlen.c -- strlen function. On at least some MIPS chips, a simple
+ * strlen is faster than the 'optimized' C version.
+ *
+ * Copyright (c) 2001 Red Hat, Inc.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+
+ #include <stddef.h>
+ #include <string.h>
+
+ #if defined(__mips64)
+ __asm__("" /* 64-bit MIPS targets */
+ " .set noreorder\n"
+ " .set nomacro\n"
+ " .globl strlen\n"
+ " .ent strlen\n"
+ "strlen:\n"
+ " daddiu $2,$4,1\n"
+ "\n"
+ "1: lbu $3,0($4)\n"
+ " bnez $3,1b\n"
+ " daddiu $4,$4,1\n"
+ "\n"
+ " jr $31\n"
+ " dsubu $2,$4,$2\n"
+ " .end strlen\n"
+ " .set macro\n"
+ " .set reorder\n");
+
+ #elif !defined(__mips16)
+ __asm__("" /* 32-bit MIPS targets */
+ " .set noreorder\n"
+ " .set nomacro\n"
+ " .globl strlen\n"
+ " .ent strlen\n"
+ "strlen:\n"
+ " addiu $2,$4,1\n"
+ "\n"
+ "1: lbu $3,0($4)\n"
+ " bnez $3,1b\n"
+ " addiu $4,$4,1\n"
+ "\n"
+ " jr $31\n"
+ " subu $2,$4,$2\n"
+ " .end strlen\n"
+ " .set macro\n"
+ " .set reorder\n");
+
+ #else /* MIPS16 targets */
+ size_t
+ strlen (const char *str)
+ {
+ const char *start = str;
+
+ while (*str++ != '\0')
+ ;
+
+ return str - start + 1;
+ }
+ #endif
*** newlib/libc/machine/mips/strncpy.c.~1~ Wed Oct 24 19:15:07 2001
--- newlib/libc/machine/mips/strncpy.c Wed Oct 24 19:14:41 2001
***************
*** 0 ****
--- 1,229 ----
+ /*
+ * strncpy.S -- strncmp function. On at least some MIPS chips, you get better
+ * code by hand unrolling the loops, and by using store words to zero the
+ * remainder of the buffer than the default newlib C version.
+ *
+ * Copyright (c) 2001 Red Hat, Inc.
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply. */
+
+ #include <string.h>
+ #include <stddef.h>
+ #include <stdlib.h>
+
+ #if !defined(__GNUC__) || (__GNUC__ < 3)
+ #define __builtin_expect(a,b) a
+
+ #else
+ #ifdef __mips64
+ /* Don't use limits test for the size of long, in order to allow the use of
+ 64-bit stores on MIPS3 machines, even if -mlong32 was used. */
+ typedef unsigned word_type __attribute__ ((mode (DI)));
+ #else
+ typedef unsigned word_type __attribute__ ((mode (SI)));
+ #endif
+
+ typedef unsigned si_type __attribute__ ((mode (SI)));
+ typedef unsigned hi_type __attribute__ ((mode (HI)));
+
+ #ifndef UNROLL_FACTOR
+ #define UNROLL_FACTOR 4
+
+ #elif (UNROLL_FACTOR != 2) && (UNROLL_FACTOR != 4)
+ #error "UNROLL_FACTOR must be 2 or 4"
+ #endif
+ #endif
+
+ char *
+ strncpy (char *dst0, const char *src0, size_t count)
+ {
+ #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || defined(__mips16) || !defined(__GNUC__) || (__GNUC__ < 3)
+ char *dst, *end;
+ const char *src;
+ int ch;
+
+ dst = dst0;
+ src = src0;
+ end = dst + count;
+ while (dst != end)
+ {
+ *dst++ = ch = *src++;
+ if (__builtin_expect (ch == '\0', 0))
+ {
+ while (dst != end)
+ *dst++ = '\0';
+
+ break;
+ }
+ }
+
+ return dst0;
+
+ #else
+ unsigned char *dst;
+ unsigned char *dst_end;
+ unsigned char *end;
+ const unsigned char *src;
+ int ch0, ch1;
+ #if UNROLL_FACTOR > 2
+ int ch2, ch3;
+ #endif
+ int ch;
+ int odd_bytes;
+ size_t long_count;
+
+ dst = (unsigned char *)dst0;
+ src = (unsigned const char *)src0;
+ if (__builtin_expect (count >= 4, 1))
+ {
+ odd_bytes = (count & (UNROLL_FACTOR - 1));
+ count -= odd_bytes;
+
+ do
+ {
+ ch0 = src[0];
+ ch1 = src[1];
+ #if UNROLL_FACTOR > 2
+ ch2 = src[2];
+ ch3 = src[3];
+ #endif
+ src += UNROLL_FACTOR;
+ count -= UNROLL_FACTOR;
+
+ dst[0] = ch0;
+ if (ch0 == '\0')
+ goto found_null0;
+
+ dst[1] = ch1;
+ if (ch1 == '\0')
+ goto found_null1;
+
+ #if UNROLL_FACTOR > 2
+ dst[2] = ch2;
+ if (ch2 == '\0')
+ goto found_null2;
+
+ dst[3] = ch3;
+ if (ch3 == '\0')
+ goto found_null3;
+ #endif
+
+ dst += UNROLL_FACTOR;
+ }
+ while (count);
+
+ /* fall through, count == 0, no null found, deal with last bytes */
+ count = odd_bytes;
+ }
+
+ end = dst + count;
+ while (dst != end)
+ {
+ *dst++ = ch = *src++;
+ if (ch == '\0')
+ {
+ while (dst != end)
+ *dst++ = '\0';
+
+ break;
+ }
+ }
+
+ return dst0;
+
+ /* Found null byte in first byte, count has been decremented by 4, null has
+ been stored in dst[0]. */
+ found_null0:
+ count++; /* add 1 to cover remaining byte */
+ dst -= 1; /* adjust dst += 4 gets correct ptr */
+ /* fall through */
+
+ /* Found null byte in second byte, count has been decremented by 4, null has
+ been stored in dst[1]. */
+ found_null1:
+ #if UNROLL_FACTOR > 2
+ count++; /* add 1 to cover remaining byte */
+ dst -= 1; /* adjust dst += 4 gets correct ptr */
+ /* fall through */
+
+ /* Found null byte in third byte, count has been decremented by 4, null has
+ been stored in dst[2]. */
+ found_null2:
+ count++; /* add 1 to cover remaining byte */
+ dst -= 1; /* adjust dst += 4 gets correct ptr */
+ /* fall through */
+
+ /* Found null byte in fourth byte, count is accurate, dst has not been
+ updated yet. */
+ found_null3:
+ #endif
+ count += odd_bytes; /* restore odd byte count */
+ dst += UNROLL_FACTOR;
+
+ /* Zero fill remainder of the array. Unroll the loop, and use word/dword
+ stores where we can. */
+ while (count && (((long)dst) & (sizeof (word_type) - 1)) != 0)
+ {
+ count--;
+ *dst++ = 0;
+ }
+
+ while (count >= UNROLL_FACTOR*sizeof (word_type))
+ {
+ count -= UNROLL_FACTOR*sizeof (word_type);
+ dst += UNROLL_FACTOR*sizeof (word_type);
+ #if UNROLL_FACTOR > 2
+ ((word_type *)(void *)dst)[-4] = 0;
+ ((word_type *)(void *)dst)[-3] = 0;
+ #endif
+ ((word_type *)(void *)dst)[-2] = 0;
+ ((word_type *)(void *)dst)[-1] = 0;
+ }
+
+ #if UNROLL_FACTOR > 2
+ if (count >= 2*sizeof (word_type))
+ {
+ count -= 2*sizeof (word_type);
+ ((word_type *)(void *)dst)[0] = 0;
+ ((word_type *)(void *)dst)[1] = 0;
+ dst += 2*sizeof (word_type);
+ }
+ #endif
+
+ if (count >= sizeof (word_type))
+ {
+ count -= sizeof (word_type);
+ ((word_type *)(void *)dst)[0] = 0;
+ dst += sizeof (word_type);
+ }
+
+ #ifdef __mips64
+ if (count >= sizeof (si_type))
+ {
+ count -= sizeof (si_type);
+ ((si_type *)(void *)dst)[0] = 0;
+ dst += sizeof (si_type);
+ }
+ #endif
+
+ if (count >= sizeof (hi_type))
+ {
+ count -= sizeof (hi_type);
+ ((hi_type *)(void *)dst)[0] = 0;
+ dst += sizeof (hi_type);
+ }
+
+ if (count)
+ *dst = '\0';
+
+ return dst0;
+ #endif
+ }
--
Michael Meissner, Red Hat, Inc. (GCC group)
PMB 198, 174 Littleton Road #3, Westford, Massachusetts 01886, USA
Work: meissner@redhat.com phone: +1 978-486-9304
Non-work: meissner@spectacle-pond.org fax: +1 978-692-4482