Blame sysdeps/mips/memset.S

Packit 6c4009
/* Copyright (C) 2013-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library.  If not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifdef ANDROID_CHANGES
Packit 6c4009
# include "machine/asm.h"
Packit 6c4009
# include "machine/regdef.h"
Packit 6c4009
# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
Packit 6c4009
#elif _LIBC
Packit 6c4009
# include <sysdep.h>
Packit 6c4009
# include <regdef.h>
Packit 6c4009
# include <sys/asm.h>
Packit 6c4009
# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
Packit 6c4009
#elif defined _COMPILING_NEWLIB
Packit 6c4009
# include "machine/asm.h"
Packit 6c4009
# include "machine/regdef.h"
Packit 6c4009
# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
Packit 6c4009
#else
Packit 6c4009
# include <regdef.h>
Packit 6c4009
# include <sys/asm.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Check to see if the MIPS architecture we are compiling for supports
Packit 6c4009
   prefetching.  */
Packit 6c4009
Packit 6c4009
#if (__mips == 4) || (__mips == 5) || (__mips == 32) || (__mips == 64)
Packit 6c4009
# ifndef DISABLE_PREFETCH
Packit 6c4009
#  define USE_PREFETCH
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32))
Packit 6c4009
# ifndef DISABLE_DOUBLE
Packit 6c4009
#  define USE_DOUBLE
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef USE_DOUBLE
Packit 6c4009
# ifndef DISABLE_DOUBLE_ALIGN
Packit 6c4009
#  define DOUBLE_ALIGN
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Some asm.h files do not have the L macro definition.  */
Packit 6c4009
#ifndef L
Packit 6c4009
# if _MIPS_SIM == _ABIO32
Packit 6c4009
#  define L(label) $L ## label
Packit 6c4009
# else
Packit 6c4009
#  define L(label) .L ## label
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Some asm.h files do not have the PTR_ADDIU macro definition.  */
Packit 6c4009
#ifndef PTR_ADDIU
Packit 6c4009
# ifdef USE_DOUBLE
Packit 6c4009
#  define PTR_ADDIU	daddiu
Packit 6c4009
# else
Packit 6c4009
#  define PTR_ADDIU	addiu
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* New R6 instructions that may not be in asm.h.  */
Packit 6c4009
#ifndef PTR_LSA
Packit 6c4009
# if _MIPS_SIM == _ABI64
Packit 6c4009
#  define PTR_LSA        dlsa
Packit 6c4009
# else
Packit 6c4009
#  define PTR_LSA        lsa
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE
Packit 6c4009
   or PREFETCH_STORE_STREAMED offers a large performance advantage
Packit 6c4009
   but PREPAREFORSTORE has some special restrictions to consider.
Packit 6c4009
Packit 6c4009
   Prefetch with the 'prepare for store' hint does not copy a memory
Packit 6c4009
   location into the cache, it just allocates a cache line and zeros
Packit 6c4009
   it out.  This means that if you do not write to the entire cache
Packit 6c4009
   line before writing it out to memory some data will get zero'ed out
Packit 6c4009
   when the cache line is written back to memory and data will be lost.
Packit 6c4009
Packit 6c4009
   There are ifdef'ed sections of this memcpy to make sure that it does not
Packit 6c4009
   do prefetches on cache lines that are not going to be completely written.
Packit 6c4009
   This code is only needed and only used when PREFETCH_STORE_HINT is set to
Packit 6c4009
   PREFETCH_HINT_PREPAREFORSTORE.  This code assumes that cache lines are
Packit 6c4009
   less than MAX_PREFETCH_SIZE bytes and if the cache line is larger it will
Packit 6c4009
   not work correctly.  */
Packit 6c4009
Packit 6c4009
#ifdef USE_PREFETCH
Packit 6c4009
# define PREFETCH_HINT_STORE		1
Packit 6c4009
# define PREFETCH_HINT_STORE_STREAMED	5
Packit 6c4009
# define PREFETCH_HINT_STORE_RETAINED	7
Packit 6c4009
# define PREFETCH_HINT_PREPAREFORSTORE	30
Packit 6c4009
Packit 6c4009
/* If we have not picked out what hints to use at this point use the
Packit 6c4009
   standard load and store prefetch hints.  */
Packit 6c4009
# ifndef PREFETCH_STORE_HINT
Packit 6c4009
#  define PREFETCH_STORE_HINT PREFETCH_HINT_STORE
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* We double everything when USE_DOUBLE is true so we do 2 prefetches to
Packit 6c4009
   get 64 bytes in that case.  The assumption is that each individual
Packit 6c4009
   prefetch brings in 32 bytes.  */
Packit 6c4009
# ifdef USE_DOUBLE
Packit 6c4009
#  define PREFETCH_CHUNK 64
Packit 6c4009
#  define PREFETCH_FOR_STORE(chunk, reg) \
Packit 6c4009
    pref PREFETCH_STORE_HINT, (chunk)*64(reg); \
Packit 6c4009
    pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg)
Packit 6c4009
# else
Packit 6c4009
#  define PREFETCH_CHUNK 32
Packit 6c4009
#  define PREFETCH_FOR_STORE(chunk, reg) \
Packit 6c4009
    pref PREFETCH_STORE_HINT, (chunk)*32(reg)
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less
Packit 6c4009
   than PREFETCH_CHUNK, the assumed size of each prefetch.  If the real size
Packit 6c4009
   of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE
Packit 6c4009
   hint is used, the code will not work correctly.  If PREPAREFORSTORE is not
Packit 6c4009
   used than MAX_PREFETCH_SIZE does not matter.  */
Packit 6c4009
# define MAX_PREFETCH_SIZE 128
Packit 6c4009
/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater
Packit 6c4009
   than 5 on a STORE prefetch and that a single prefetch can never be larger
Packit 6c4009
   than MAX_PREFETCH_SIZE.  We add the extra 32 when USE_DOUBLE is set because
Packit 6c4009
   we actually do two prefetches in that case, one 32 bytes after the other.  */
Packit 6c4009
# ifdef USE_DOUBLE
Packit 6c4009
#  define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE
Packit 6c4009
# else
Packit 6c4009
#  define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \
Packit 6c4009
    && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE)
Packit 6c4009
/* We cannot handle this because the initial prefetches may fetch bytes that
Packit 6c4009
   are before the buffer being copied.  We start copies with an offset
Packit 6c4009
   of 4 so avoid this situation when using PREPAREFORSTORE.  */
Packit 6c4009
#  error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small."
Packit 6c4009
# endif
Packit 6c4009
#else /* USE_PREFETCH not defined */
Packit 6c4009
# define PREFETCH_FOR_STORE(offset, reg)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if __mips_isa_rev > 5
Packit 6c4009
# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
Packit 6c4009
#  undef PREFETCH_STORE_HINT
Packit 6c4009
#  define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED
Packit 6c4009
# endif
Packit 6c4009
# define R6_CODE
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Allow the routine to be named something else if desired.  */
Packit 6c4009
#ifndef MEMSET_NAME
Packit 6c4009
# define MEMSET_NAME memset
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* We load/store 64 bits at a time when USE_DOUBLE is true.
Packit 6c4009
   The C_ prefix stands for CHUNK and is used to avoid macro name
Packit 6c4009
   conflicts with system header files.  */
Packit 6c4009
Packit 6c4009
#ifdef USE_DOUBLE
Packit 6c4009
# define C_ST	sd
Packit 6c4009
# ifdef __MIPSEB
Packit 6c4009
#  define C_STHI	sdl	/* high part is left in big-endian	*/
Packit 6c4009
# else
Packit 6c4009
#  define C_STHI	sdr	/* high part is right in little-endian	*/
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
# define C_ST	sw
Packit 6c4009
# ifdef __MIPSEB
Packit 6c4009
#  define C_STHI	swl	/* high part is left in big-endian	*/
Packit 6c4009
# else
Packit 6c4009
#  define C_STHI	swr	/* high part is right in little-endian	*/
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Bookkeeping values for 32 vs. 64 bit mode.  */
Packit 6c4009
#ifdef USE_DOUBLE
Packit 6c4009
# define NSIZE 8
Packit 6c4009
# define NSIZEMASK 0x3f
Packit 6c4009
# define NSIZEDMASK 0x7f
Packit 6c4009
#else
Packit 6c4009
# define NSIZE 4
Packit 6c4009
# define NSIZEMASK 0x1f
Packit 6c4009
# define NSIZEDMASK 0x3f
Packit 6c4009
#endif
Packit 6c4009
#define UNIT(unit) ((unit)*NSIZE)
Packit 6c4009
#define UNITM1(unit) (((unit)*NSIZE)-1)
Packit 6c4009
Packit 6c4009
#ifdef ANDROID_CHANGES
Packit 6c4009
LEAF(MEMSET_NAME,0)
Packit 6c4009
#else
Packit 6c4009
LEAF(MEMSET_NAME)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	.set	nomips16
Packit 6c4009
	.set	noreorder
Packit 6c4009
/* If the size is less than 2*NSIZE (8 or 16), go to L(lastb).  Regardless of
Packit 6c4009
   size, copy dst pointer to v0 for the return value.  */
Packit 6c4009
	slti	t2,a2,(2 * NSIZE)
Packit 6c4009
	bne	t2,zero,L(lastb)
Packit 6c4009
	move	v0,a0
Packit 6c4009
Packit 6c4009
/* If memset value is not zero, we copy it to all the bytes in a 32 or 64
Packit 6c4009
   bit word.  */
Packit 6c4009
	beq	a1,zero,L(set0)		/* If memset value is zero no smear  */
Packit 6c4009
	PTR_SUBU a3,zero,a0
Packit 6c4009
	nop
Packit 6c4009
Packit 6c4009
	/* smear byte into 32 or 64 bit word */
Packit 6c4009
#if ((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2)
Packit 6c4009
# ifdef USE_DOUBLE
Packit 6c4009
	dins	a1, a1, 8, 8        /* Replicate fill byte into half-word.  */
Packit 6c4009
	dins	a1, a1, 16, 16      /* Replicate fill byte into word.       */
Packit 6c4009
	dins	a1, a1, 32, 32      /* Replicate fill byte into dbl word.   */
Packit 6c4009
# else
Packit 6c4009
	ins	a1, a1, 8, 8        /* Replicate fill byte into half-word.  */
Packit 6c4009
	ins	a1, a1, 16, 16      /* Replicate fill byte into word.       */
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
# ifdef USE_DOUBLE
Packit 6c4009
        and     a1,0xff
Packit 6c4009
	dsll	t2,a1,8
Packit 6c4009
	or	a1,t2
Packit 6c4009
	dsll	t2,a1,16
Packit 6c4009
	or	a1,t2
Packit 6c4009
	dsll	t2,a1,32
Packit 6c4009
	or	a1,t2
Packit 6c4009
# else
Packit 6c4009
        and     a1,0xff
Packit 6c4009
	sll	t2,a1,8
Packit 6c4009
	or	a1,t2
Packit 6c4009
	sll	t2,a1,16
Packit 6c4009
	or	a1,t2
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* If the destination address is not aligned do a partial store to get it
Packit 6c4009
   aligned.  If it is already aligned just jump to L(aligned).  */
Packit 6c4009
L(set0):
Packit 6c4009
#ifndef R6_CODE
Packit 6c4009
	andi	t2,a3,(NSIZE-1)		/* word-unaligned address?          */
Packit 6c4009
	beq	t2,zero,L(aligned)	/* t2 is the unalignment count      */
Packit 6c4009
	PTR_SUBU a2,a2,t2
Packit 6c4009
	C_STHI	a1,0(a0)
Packit 6c4009
	PTR_ADDU a0,a0,t2
Packit 6c4009
#else /* R6_CODE */
Packit 6c4009
	andi	t2,a0,(NSIZE-1)
Packit 6c4009
	lapc	t9,L(atable)
Packit 6c4009
	PTR_LSA	t9,t2,t9,2
Packit 6c4009
	jrc	t9
Packit 6c4009
L(atable):
Packit 6c4009
	bc	L(aligned)
Packit 6c4009
# ifdef USE_DOUBLE
Packit 6c4009
	bc	L(lb7)
Packit 6c4009
	bc	L(lb6)
Packit 6c4009
	bc	L(lb5)
Packit 6c4009
	bc	L(lb4)
Packit 6c4009
# endif
Packit 6c4009
	bc	L(lb3)
Packit 6c4009
	bc	L(lb2)
Packit 6c4009
	bc	L(lb1)
Packit 6c4009
L(lb7):
Packit 6c4009
	sb	a1,6(a0)
Packit 6c4009
L(lb6):
Packit 6c4009
	sb	a1,5(a0)
Packit 6c4009
L(lb5):
Packit 6c4009
	sb	a1,4(a0)
Packit 6c4009
L(lb4):
Packit 6c4009
	sb	a1,3(a0)
Packit 6c4009
L(lb3):
Packit 6c4009
	sb	a1,2(a0)
Packit 6c4009
L(lb2):
Packit 6c4009
	sb	a1,1(a0)
Packit 6c4009
L(lb1):
Packit 6c4009
	sb	a1,0(a0)
Packit 6c4009
Packit 6c4009
	li	t9,NSIZE
Packit 6c4009
	subu	t2,t9,t2
Packit 6c4009
	PTR_SUBU a2,a2,t2
Packit 6c4009
	PTR_ADDU a0,a0,t2
Packit 6c4009
#endif /* R6_CODE */
Packit 6c4009
Packit 6c4009
L(aligned):
Packit 6c4009
/* If USE_DOUBLE is not set we may still want to align the data on a 16
Packit 6c4009
   byte boundry instead of an 8 byte boundry to maximize the opportunity
Packit 6c4009
   of proAptiv chips to do memory bonding (combining two sequential 4
Packit 6c4009
   byte stores into one 8 byte store).  We know there are at least 4 bytes
Packit 6c4009
   left to store or we would have jumped to L(lastb) earlier in the code.  */
Packit 6c4009
#ifdef DOUBLE_ALIGN
Packit 6c4009
	andi	t2,a3,4
Packit 6c4009
	beq	t2,zero,L(double_aligned)
Packit 6c4009
	PTR_SUBU a2,a2,t2
Packit 6c4009
	sw	a1,0(a0)
Packit 6c4009
	PTR_ADDU a0,a0,t2
Packit 6c4009
L(double_aligned):
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Now the destination is aligned to (word or double word) aligned address
Packit 6c4009
   Set a2 to count how many bytes we have to copy after all the 64/128 byte
Packit 6c4009
   chunks are copied and a3 to the dest pointer after all the 64/128 byte
Packit 6c4009
   chunks have been copied.  We will loop, incrementing a0 until it equals
Packit 6c4009
   a3.  */
Packit 6c4009
	andi	t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
Packit 6c4009
	beq	a2,t8,L(chkw)	 /* if a2==t8, no 64-byte/128-byte chunks */
Packit 6c4009
	PTR_SUBU a3,a2,t8	 /* subtract from a2 the reminder */
Packit 6c4009
	PTR_ADDU a3,a0,a3	 /* Now a3 is the final dst after loop */
Packit 6c4009
Packit 6c4009
/* When in the loop we may prefetch with the 'prepare to store' hint,
Packit 6c4009
   in this case the a0+x should not be past the "t0-32" address.  This
Packit 6c4009
   means: for x=128 the last "safe" a0 address is "t0-160".  Alternatively,
Packit 6c4009
   for x=64 the last "safe" a0 address is "t0-96" In the current version we
Packit 6c4009
   will use "prefetch hint,128(a0)", so "t0-160" is the limit.  */
Packit 6c4009
#if defined(USE_PREFETCH) \
Packit 6c4009
    && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
Packit 6c4009
	PTR_ADDU t0,a0,a2		/* t0 is the "past the end" address */
Packit 6c4009
	PTR_SUBU t9,t0,PREFETCH_LIMIT	/* t9 is the "last safe pref" address */
Packit 6c4009
#endif
Packit 6c4009
#if defined(USE_PREFETCH) \
Packit 6c4009
    && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
Packit 6c4009
	PREFETCH_FOR_STORE (1, a0)
Packit 6c4009
	PREFETCH_FOR_STORE (2, a0)
Packit 6c4009
	PREFETCH_FOR_STORE (3, a0)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
L(loop16w):
Packit 6c4009
#if defined(USE_PREFETCH) \
Packit 6c4009
    && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
Packit 6c4009
	sltu	v1,t9,a0		/* If a0 > t9 don't use next prefetch */
Packit 6c4009
	bgtz	v1,L(skip_pref)
Packit 6c4009
	nop
Packit 6c4009
#endif
Packit 6c4009
#ifdef R6_CODE
Packit 6c4009
	PREFETCH_FOR_STORE (2, a0)
Packit 6c4009
#else
Packit 6c4009
	PREFETCH_FOR_STORE (4, a0)
Packit 6c4009
	PREFETCH_FOR_STORE (5, a0)
Packit 6c4009
#endif
Packit 6c4009
L(skip_pref):
Packit 6c4009
	C_ST	a1,UNIT(0)(a0)
Packit 6c4009
	C_ST	a1,UNIT(1)(a0)
Packit 6c4009
	C_ST	a1,UNIT(2)(a0)
Packit 6c4009
	C_ST	a1,UNIT(3)(a0)
Packit 6c4009
	C_ST	a1,UNIT(4)(a0)
Packit 6c4009
	C_ST	a1,UNIT(5)(a0)
Packit 6c4009
	C_ST	a1,UNIT(6)(a0)
Packit 6c4009
	C_ST	a1,UNIT(7)(a0)
Packit 6c4009
	C_ST	a1,UNIT(8)(a0)
Packit 6c4009
	C_ST	a1,UNIT(9)(a0)
Packit 6c4009
	C_ST	a1,UNIT(10)(a0)
Packit 6c4009
	C_ST	a1,UNIT(11)(a0)
Packit 6c4009
	C_ST	a1,UNIT(12)(a0)
Packit 6c4009
	C_ST	a1,UNIT(13)(a0)
Packit 6c4009
	C_ST	a1,UNIT(14)(a0)
Packit 6c4009
	C_ST	a1,UNIT(15)(a0)
Packit 6c4009
	PTR_ADDIU a0,a0,UNIT(16)	/* adding 64/128 to dest */
Packit 6c4009
	bne	a0,a3,L(loop16w)
Packit 6c4009
	nop
Packit 6c4009
	move	a2,t8
Packit 6c4009
Packit 6c4009
/* Here we have dest word-aligned but less than 64-bytes or 128 bytes to go.
Packit 6c4009
   Check for a 32(64) byte chunk and copy if there is one.  Otherwise
Packit 6c4009
   jump down to L(chk1w) to handle the tail end of the copy.  */
Packit 6c4009
L(chkw):
Packit 6c4009
	andi	t8,a2,NSIZEMASK	/* is there a 32-byte/64-byte chunk.  */
Packit 6c4009
				/* the t8 is the reminder count past 32-bytes */
Packit 6c4009
	beq	a2,t8,L(chk1w)/* when a2==t8, no 32-byte chunk */
Packit 6c4009
	nop
Packit 6c4009
	C_ST	a1,UNIT(0)(a0)
Packit 6c4009
	C_ST	a1,UNIT(1)(a0)
Packit 6c4009
	C_ST	a1,UNIT(2)(a0)
Packit 6c4009
	C_ST	a1,UNIT(3)(a0)
Packit 6c4009
	C_ST	a1,UNIT(4)(a0)
Packit 6c4009
	C_ST	a1,UNIT(5)(a0)
Packit 6c4009
	C_ST	a1,UNIT(6)(a0)
Packit 6c4009
	C_ST	a1,UNIT(7)(a0)
Packit 6c4009
	PTR_ADDIU a0,a0,UNIT(8)
Packit 6c4009
Packit 6c4009
/* Here we have less than 32(64) bytes to set.  Set up for a loop to
Packit 6c4009
   copy one word (or double word) at a time.  Set a2 to count how many
Packit 6c4009
   bytes we have to copy after all the word (or double word) chunks are
Packit 6c4009
   copied and a3 to the dest pointer after all the (d)word chunks have
Packit 6c4009
   been copied.  We will loop, incrementing a0 until a0 equals a3.  */
Packit 6c4009
L(chk1w):
Packit 6c4009
	andi	a2,t8,(NSIZE-1)	/* a2 is the reminder past one (d)word chunks */
Packit 6c4009
	beq	a2,t8,L(lastb)
Packit 6c4009
	PTR_SUBU a3,t8,a2	/* a3 is count of bytes in one (d)word chunks */
Packit 6c4009
	PTR_ADDU a3,a0,a3	/* a3 is the dst address after loop */
Packit 6c4009
Packit 6c4009
/* copying in words (4-byte or 8 byte chunks) */
Packit 6c4009
L(wordCopy_loop):
Packit 6c4009
	PTR_ADDIU a0,a0,UNIT(1)
Packit 6c4009
	bne	a0,a3,L(wordCopy_loop)
Packit 6c4009
	C_ST	a1,UNIT(-1)(a0)
Packit 6c4009
Packit 6c4009
/* Copy the last 8 (or 16) bytes */
Packit 6c4009
L(lastb):
Packit 6c4009
	blez	a2,L(leave)
Packit 6c4009
	PTR_ADDU a3,a0,a2       /* a3 is the last dst address */
Packit 6c4009
L(lastbloop):
Packit 6c4009
	PTR_ADDIU a0,a0,1
Packit 6c4009
	bne	a0,a3,L(lastbloop)
Packit 6c4009
	sb	a1,-1(a0)
Packit 6c4009
L(leave):
Packit 6c4009
	j	ra
Packit 6c4009
	nop
Packit 6c4009
Packit 6c4009
	.set	at
Packit 6c4009
	.set	reorder
Packit 6c4009
END(MEMSET_NAME)
Packit 6c4009
#ifndef ANDROID_CHANGES
Packit 6c4009
# ifdef _LIBC
Packit 6c4009
libc_hidden_builtin_def (MEMSET_NAME)
Packit 6c4009
# endif
Packit 6c4009
#endif