summaryrefslogtreecommitdiff
path: root/libc/string/mips/memset.S
blob: 26b25985ddb78707a3d954f7f6e5039b03a3c6db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#include <features.h>
#include <sysdep.h>
#include <endian.h>

/* void *memset(void *s, int c, size_t n).  */

#ifdef __mips64

#include <sys/asm.h>

#if __BYTE_ORDER == __BIG_ENDIAN
# define SDHI	sdl		/* high part is left in big-endian	*/
#else
# define SDHI	sdr		/* high part is right in little-endian	*/
#endif

ENTRY (memset)
	.set	noreorder

	slti	ta1, a2, 16		# Less than 16?
	bne	ta1, zero, L(last16)
	move	v0, a0			# Setup exit value before too late

	beq	a1, zero, L(ueven)	# If zero pattern, no need to extend
	andi	a1, 0xff		# Avoid problems with bogus arguments
	dsll	ta0, a1, 8
	or	a1, ta0
	dsll	ta0, a1, 16
	or	a1, ta0			# a1 is now pattern in full word
	dsll	ta0, a1, 32
	or	a1, ta0			# a1 is now pattern in double word

L(ueven):
	PTR_SUBU ta0, zero, a0		# Unaligned address?
	andi	ta0, 0x7
	beq	ta0, zero, L(chkw)
	PTR_SUBU a2, ta0
	SDHI	a1, 0(a0)		# Yes, handle first unaligned part
	PTR_ADDU a0, ta0		# Now both a0 and a2 are updated

L(chkw):
	andi	ta0, a2, 0xf		# Enough left for one loop iteration?
	beq	ta0, a2, L(chkl)
	PTR_SUBU a3, a2, ta0
	PTR_ADDU a3, a0			# a3 is last loop address +1
	move	a2, ta0			# a2 is now # of bytes left after loop
L(loopw):
	PTR_ADDIU a0, 16		# Handle 2 dwords pr. iteration
	sd	a1, -16(a0)
	bne	a0, a3, L(loopw)
	sd	a1,  -8(a0)

L(chkl):
	andi	ta0, a2, 0x8		# Check if there is at least a double
	beq	ta0, zero, L(last16)	#  word remaining after the loop
	PTR_SUBU a2, ta0
	sd	a1, 0(a0)		# Yes...
	PTR_ADDIU a0, 8

L(last16):
	blez	a2, L(exit)		# Handle last 16 bytes (if cnt>0)
	PTR_ADDU a3, a2, a0		# a3 is last address +1
L(lst16l):
	PTR_ADDIU a0, 1
	bne	a0, a3, L(lst16l)
	sb	a1, -1(a0)
L(exit):
	j	ra			# Bye, bye
	nop

	.set	reorder
END (memset)

#else /* !__mips64 */

#if __BYTE_ORDER == __BIG_ENDIAN
# define SWHI	swl		/* high part is left in big-endian	*/
#else
# define SWHI	swr		/* high part is right in little-endian	*/
#endif

ENTRY (memset)
	.set	noreorder

	slti	t1, a2, 8		# Less than 8?
	bne	t1, zero, L(last8)
	move	v0, a0			# Setup exit value before too late

	beq	a1, zero, L(ueven)	# If zero pattern, no need to extend
	andi	a1, 0xff		# Avoid problems with bogus arguments
	sll	t0, a1, 8
	or	a1, t0
	sll	t0, a1, 16
	or	a1, t0			# a1 is now pattern in full word

L(ueven):	
	subu	t0, zero, a0		# Unaligned address?
	andi	t0, 0x3
	beq	t0, zero, L(chkw)
	subu	a2, t0
	SWHI	a1, 0(a0)		# Yes, handle first unaligned part
	addu	a0, t0			# Now both a0 and a2 are updated

L(chkw):	
	andi	t0, a2, 0x7		# Enough left for one loop iteration?
	beq	t0, a2, L(chkl)
	subu	a3, a2, t0
	addu	a3, a0			# a3 is last loop address +1
	move	a2, t0			# a2 is now # of bytes left after loop
L(loopw):	
	addiu	a0, 8			# Handle 2 words pr. iteration
	sw	a1, -8(a0)
	bne	a0, a3, L(loopw)
	sw	a1, -4(a0)

L(chkl):	
	andi	t0, a2, 0x4		# Check if there is at least a full
	beq	t0, zero, L(last8)	#  word remaining after the loop
	subu	a2, t0
	sw	a1, 0(a0)		# Yes...
	addiu	a0, 4

L(last8):	
	blez	a2, L(exit)		# Handle last 8 bytes (if cnt>0)
	addu	a3, a2, a0		# a3 is last address +1
L(lst8l):	
	addiu	a0, 1
	bne	a0, a3, L(lst8l)
	sb	a1, -1(a0)
L(exit):	
	j	ra			# Bye, bye
	nop

	.set	reorder
END (memset)

#endif /* !__mips64 */

libc_hidden_def(memset)