161 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 *  arch/xtensa/lib/memset.S
 | 
						|
 *
 | 
						|
 *  ANSI C standard library function memset
 | 
						|
 *  (Well, almost.  .fixup code might return zero.)
 | 
						|
 *
 | 
						|
 *  This file is subject to the terms and conditions of the GNU General
 | 
						|
 *  Public License.  See the file "COPYING" in the main directory of
 | 
						|
 *  this archive for more details.
 | 
						|
 *
 | 
						|
 *  Copyright (C) 2002 Tensilica Inc.
 | 
						|
 */
 | 
						|
 | 
						|
#include <variant/core.h>
 | 
						|
 | 
						|
/*
 | 
						|
 * void *memset(void *dst, int c, size_t length)
 | 
						|
 *
 | 
						|
 * The algorithm is as follows:
 | 
						|
 *   Create a word with c in all byte positions
 | 
						|
 *   If the destination is aligned,
 | 
						|
 *     do 16B chucks with a loop, and then finish up with
 | 
						|
 *     8B, 4B, 2B, and 1B stores conditional on the length.
 | 
						|
 *   If destination is unaligned, align it by conditionally
 | 
						|
 *     setting 1B and 2B and then go to aligned case.
 | 
						|
 *   This code tries to use fall-through branches for the common
 | 
						|
 *     case of an aligned destination (except for the branches to
 | 
						|
 *     the alignment labels).
 | 
						|
 */
 | 
						|
 | 
						|
/* Load or store instructions that may cause exceptions use the EX macro. */
 | 
						|
 | 
						|
#define EX(insn,reg1,reg2,offset,handler)	\
 | 
						|
9:	insn	reg1, reg2, offset;		\
 | 
						|
	.section __ex_table, "a";		\
 | 
						|
	.word	9b, handler;			\
 | 
						|
	.previous
 | 
						|
 | 
						|
 | 
						|
.text
 | 
						|
.align	4
 | 
						|
.global	memset
 | 
						|
.type	memset,@function
 | 
						|
memset:
 | 
						|
	entry	sp, 16		# minimal stack frame
 | 
						|
	# a2/ dst, a3/ c, a4/ length
 | 
						|
	extui	a3, a3, 0, 8	# mask to just 8 bits
 | 
						|
	slli	a7, a3, 8	# duplicate character in all bytes of word
 | 
						|
	or	a3, a3, a7	# ...
 | 
						|
	slli	a7, a3, 16	# ...
 | 
						|
	or	a3, a3, a7	# ...
 | 
						|
	mov	a5, a2		# copy dst so that a2 is return value
 | 
						|
	movi	a6, 3		# for alignment tests
 | 
						|
	bany	a2, a6, .Ldstunaligned # if dst is unaligned
 | 
						|
.L0:	# return here from .Ldstunaligned when dst is aligned
 | 
						|
	srli	a7, a4, 4	# number of loop iterations with 16B
 | 
						|
				# per iteration
 | 
						|
	bnez	a4, .Laligned
 | 
						|
	retw
 | 
						|
 | 
						|
/*
 | 
						|
 * Destination is word-aligned.
 | 
						|
 */
 | 
						|
	# set 16 bytes per iteration for word-aligned dst
 | 
						|
	.align	4		# 1 mod 4 alignment for LOOPNEZ
 | 
						|
	.byte	0		# (0 mod 4 alignment for LBEG)
 | 
						|
.Laligned:
 | 
						|
#if XCHAL_HAVE_LOOPS
 | 
						|
	loopnez	a7, .Loop1done
 | 
						|
#else /* !XCHAL_HAVE_LOOPS */
 | 
						|
	beqz	a7, .Loop1done
 | 
						|
	slli	a6, a7, 4
 | 
						|
	add	a6, a6, a5	# a6 = end of last 16B chunk
 | 
						|
#endif /* !XCHAL_HAVE_LOOPS */
 | 
						|
.Loop1:
 | 
						|
	EX(s32i, a3, a5,  0, memset_fixup)
 | 
						|
	EX(s32i, a3, a5,  4, memset_fixup)
 | 
						|
	EX(s32i, a3, a5,  8, memset_fixup)
 | 
						|
	EX(s32i, a3, a5, 12, memset_fixup)
 | 
						|
	addi	a5, a5, 16
 | 
						|
#if !XCHAL_HAVE_LOOPS
 | 
						|
	blt	a5, a6, .Loop1
 | 
						|
#endif /* !XCHAL_HAVE_LOOPS */
 | 
						|
.Loop1done:
 | 
						|
	bbci.l	a4, 3, .L2
 | 
						|
	# set 8 bytes
 | 
						|
	EX(s32i, a3, a5,  0, memset_fixup)
 | 
						|
	EX(s32i, a3, a5,  4, memset_fixup)
 | 
						|
	addi	a5, a5,  8
 | 
						|
.L2:
 | 
						|
	bbci.l	a4, 2, .L3
 | 
						|
	# set 4 bytes
 | 
						|
	EX(s32i, a3, a5,  0, memset_fixup)
 | 
						|
	addi	a5, a5,  4
 | 
						|
.L3:
 | 
						|
	bbci.l	a4, 1, .L4
 | 
						|
	# set 2 bytes
 | 
						|
	EX(s16i, a3, a5,  0, memset_fixup)
 | 
						|
	addi	a5, a5,  2
 | 
						|
.L4:
 | 
						|
	bbci.l	a4, 0, .L5
 | 
						|
	# set 1 byte
 | 
						|
	EX(s8i, a3, a5,  0, memset_fixup)
 | 
						|
.L5:
 | 
						|
.Lret1:
 | 
						|
	retw
 | 
						|
 | 
						|
/*
 | 
						|
 * Destination is unaligned
 | 
						|
 */
 | 
						|
 | 
						|
.Ldstunaligned:
 | 
						|
	bltui	a4, 8, .Lbyteset	# do short copies byte by byte
 | 
						|
	bbci.l	a5, 0, .L20		# branch if dst alignment half-aligned
 | 
						|
	# dst is only byte aligned
 | 
						|
	# set 1 byte
 | 
						|
	EX(s8i, a3, a5,  0, memset_fixup)
 | 
						|
	addi	a5, a5,  1
 | 
						|
	addi	a4, a4, -1
 | 
						|
	# now retest if dst aligned
 | 
						|
	bbci.l	a5, 1, .L0	# if now aligned, return to main algorithm
 | 
						|
.L20:
 | 
						|
	# dst half-aligned
 | 
						|
	# set 2 bytes
 | 
						|
	EX(s16i, a3, a5,  0, memset_fixup)
 | 
						|
	addi	a5, a5,  2
 | 
						|
	addi	a4, a4, -2
 | 
						|
	j	.L0		# dst is now aligned, return to main algorithm
 | 
						|
 | 
						|
/*
 | 
						|
 * Byte by byte set
 | 
						|
 */
 | 
						|
	.align	4
 | 
						|
	.byte	0		# 1 mod 4 alignment for LOOPNEZ
 | 
						|
				# (0 mod 4 alignment for LBEG)
 | 
						|
.Lbyteset:
 | 
						|
#if XCHAL_HAVE_LOOPS
 | 
						|
	loopnez	a4, .Lbytesetdone
 | 
						|
#else /* !XCHAL_HAVE_LOOPS */
 | 
						|
	beqz	a4, .Lbytesetdone
 | 
						|
	add	a6, a5, a4	# a6 = ending address
 | 
						|
#endif /* !XCHAL_HAVE_LOOPS */
 | 
						|
.Lbyteloop:
 | 
						|
	EX(s8i, a3, a5, 0, memset_fixup)
 | 
						|
	addi	a5, a5, 1
 | 
						|
#if !XCHAL_HAVE_LOOPS
 | 
						|
	blt	a5, a6, .Lbyteloop
 | 
						|
#endif /* !XCHAL_HAVE_LOOPS */
 | 
						|
.Lbytesetdone:
 | 
						|
	retw
 | 
						|
 | 
						|
 | 
						|
	.section .fixup, "ax"
 | 
						|
	.align	4
 | 
						|
 | 
						|
/* We return zero if a failure occurred. */
 | 
						|
 | 
						|
memset_fixup:
 | 
						|
	movi	a2, 0
 | 
						|
	retw
 |