OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.17.0/] [newlib/] [libc/] [machine/] [mips/] [strncpy.c] - Rev 407

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * 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>
#include <stdint.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;
  /* Take care of any odd bytes in the source data because we
   * want to unroll where we read ahead 2 or 4 bytes at a time and then
   * check each byte for the null terminator.  This can result in
   * a segfault for the case where the source pointer is unaligned,
   * the null terminator is in valid memory, but reading 2 or 4 bytes at a
   * time blindly eventually goes outside of valid memory. */
  while (((uintptr_t) src & (UNROLL_FACTOR - 1)) != 0 && count > 0)
    {
      *dst++ = ch = *src++;
      --count;
      if (ch == '\0')
	{
          end = dst + count;
	  while (dst != end)
	    *dst++ = '\0';
 
	  return dst0;
	}
    }
 
  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
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.