This is the mail archive of the newlib@sources.redhat.com mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Mips optimized versions of strlen, strncpy, strcmp


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]