1 /*
2  *  arch/xtensa/lib/memset.S
3  *
4  *  ANSI C standard library function memset
5  *  (Well, almost.  .fixup code might return zero.)
6  *
7  *  This file is subject to the terms and conditions of the GNU General
8  *  Public License.  See the file "COPYING" in the main directory of
9  *  this archive for more details.
10  *
11  *  Copyright (C) 2002 Tensilica Inc.
12  */
13 
14 #include <linux/linkage.h>
15 #include <asm/asmmacro.h>
16 #include <asm/core.h>
17 
18 /*
19  * void *memset(void *dst, int c, size_t length)
20  *
21  * The algorithm is as follows:
22  *   Create a word with c in all byte positions
23  *   If the destination is aligned,
24  *     do 16B chucks with a loop, and then finish up with
25  *     8B, 4B, 2B, and 1B stores conditional on the length.
26  *   If destination is unaligned, align it by conditionally
27  *     setting 1B and 2B and then go to aligned case.
28  *   This code tries to use fall-through branches for the common
29  *     case of an aligned destination (except for the branches to
30  *     the alignment labels).
31  */
32 
33 .text
34 ENTRY(__memset)
35 WEAK(memset)
36 
37 	abi_entry_default
38 	# a2/ dst, a3/ c, a4/ length
39 	extui	a3, a3, 0, 8	# mask to just 8 bits
40 	slli	a7, a3, 8	# duplicate character in all bytes of word
41 	or	a3, a3, a7	# ...
42 	slli	a7, a3, 16	# ...
43 	or	a3, a3, a7	# ...
44 	mov	a5, a2		# copy dst so that a2 is return value
45 	movi	a6, 3		# for alignment tests
46 	bany	a2, a6, .Ldstunaligned # if dst is unaligned
47 .L0:	# return here from .Ldstunaligned when dst is aligned
48 	srli	a7, a4, 4	# number of loop iterations with 16B
49 				# per iteration
50 	bnez	a4, .Laligned
51 	abi_ret_default
52 
53 /*
54  * Destination is word-aligned.
55  */
56 	# set 16 bytes per iteration for word-aligned dst
57 	.align	4		# 1 mod 4 alignment for LOOPNEZ
58 	.byte	0		# (0 mod 4 alignment for LBEG)
59 .Laligned:
60 #if XCHAL_HAVE_LOOPS
61 	loopnez	a7, .Loop1done
62 #else /* !XCHAL_HAVE_LOOPS */
63 	beqz	a7, .Loop1done
64 	slli	a6, a7, 4
65 	add	a6, a6, a5	# a6 = end of last 16B chunk
66 #endif /* !XCHAL_HAVE_LOOPS */
67 .Loop1:
68 EX(10f) s32i	a3, a5,  0
69 EX(10f) s32i	a3, a5,  4
70 EX(10f) s32i	a3, a5,  8
71 EX(10f) s32i	a3, a5, 12
72 	addi	a5, a5, 16
73 #if !XCHAL_HAVE_LOOPS
74 	blt	a5, a6, .Loop1
75 #endif /* !XCHAL_HAVE_LOOPS */
76 .Loop1done:
77 	bbci.l	a4, 3, .L2
78 	# set 8 bytes
79 EX(10f) s32i	a3, a5,  0
80 EX(10f) s32i	a3, a5,  4
81 	addi	a5, a5,  8
82 .L2:
83 	bbci.l	a4, 2, .L3
84 	# set 4 bytes
85 EX(10f) s32i	a3, a5,  0
86 	addi	a5, a5,  4
87 .L3:
88 	bbci.l	a4, 1, .L4
89 	# set 2 bytes
90 EX(10f) s16i	a3, a5,  0
91 	addi	a5, a5,  2
92 .L4:
93 	bbci.l	a4, 0, .L5
94 	# set 1 byte
95 EX(10f) s8i	a3, a5,  0
96 .L5:
97 .Lret1:
98 	abi_ret_default
99 
100 /*
101  * Destination is unaligned
102  */
103 
104 .Ldstunaligned:
105 	bltui	a4, 8, .Lbyteset	# do short copies byte by byte
106 	bbci.l	a5, 0, .L20		# branch if dst alignment half-aligned
107 	# dst is only byte aligned
108 	# set 1 byte
109 EX(10f) s8i	a3, a5,  0
110 	addi	a5, a5,  1
111 	addi	a4, a4, -1
112 	# now retest if dst aligned
113 	bbci.l	a5, 1, .L0	# if now aligned, return to main algorithm
114 .L20:
115 	# dst half-aligned
116 	# set 2 bytes
117 EX(10f) s16i	a3, a5,  0
118 	addi	a5, a5,  2
119 	addi	a4, a4, -2
120 	j	.L0		# dst is now aligned, return to main algorithm
121 
122 /*
123  * Byte by byte set
124  */
125 	.align	4
126 	.byte	0		# 1 mod 4 alignment for LOOPNEZ
127 				# (0 mod 4 alignment for LBEG)
128 .Lbyteset:
129 #if XCHAL_HAVE_LOOPS
130 	loopnez	a4, .Lbytesetdone
131 #else /* !XCHAL_HAVE_LOOPS */
132 	beqz	a4, .Lbytesetdone
133 	add	a6, a5, a4	# a6 = ending address
134 #endif /* !XCHAL_HAVE_LOOPS */
135 .Lbyteloop:
136 EX(10f) s8i	a3, a5, 0
137 	addi	a5, a5, 1
138 #if !XCHAL_HAVE_LOOPS
139 	blt	a5, a6, .Lbyteloop
140 #endif /* !XCHAL_HAVE_LOOPS */
141 .Lbytesetdone:
142 	abi_ret_default
143 
144 ENDPROC(__memset)
145 
146 	.section .fixup, "ax"
147 	.align	4
148 
149 /* We return zero if a failure occurred. */
150 
151 10:
152 	movi	a2, 0
153 	abi_ret_default
154