summaryrefslogtreecommitdiff
path: root/libc/string/metag/memchr.S
blob: 8b48d863cb844734a06f5201d02570b6a7d250d3 (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
!    Copyright (C) 2013 Imagination Technologies Ltd.
!
!    Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.

	.text
	.global	_memchr
	.type	_memchr,function
! D0Ar6 src
! D0Ar2 c
! D1Ar3 n
_memchr:
	CMP     D1Ar3, #0
	BEQ	$Lexit_fail
	!! convert c to unsigned char
	AND     D0Ar2,D0Ar2,#0xff
	MOV	D0Ar6, D1Ar1
	MOV	D1Ar5, D0Ar6
	!! test alignment
	AND	D1Ar5, D1Ar5, #7
	CMP	D1Ar5, #0
	BNZ	$Lunaligned_loop
	!! length must be greater than or equal to 8 for aligned loop
	CMP     D1Ar3, #8
	BGE     $Laligned_setup
$Lunaligned_loop:
	!! get 1 char from s
	GETB	D0Re0, [D0Ar6++]
	!! increase alignment counter
	ADD	D1Ar5, D1Ar5, #1
	!! decrement n
	SUB     D1Ar3, D1Ar3, #1
	!! exit if we have a match
	CMP	D0Re0, D0Ar2
	BZ	$Lexit_success1
	!! exit if we have hit the end of the string
	CMP	D1Ar3, #0
	BZ	$Lexit_fail
	!! fall through if the buffer is aligned now
	CMP	D1Ar5, #8
	BNE	$Lunaligned_loop
	!! fall through if there is more than 8 bytes left
	CMP	D1Ar3, #8
	BLT	$Lunaligned_loop
$Laligned_setup:
	!! fill the c into 4 bytes
	MOV	D0Ar4, D0Ar2
	LSL	D0Ar4, D0Ar4, #8
	ADD	D0Ar4, D0Ar4, D0Ar2
	LSL	D0Ar4, D0Ar4, #8
	ADD	D0Ar4, D0Ar4, D0Ar2
	LSL	D0Ar4, D0Ar4, #8
	ADD	D0Ar4, D0Ar4, D0Ar2
	!! divide n by 8
	MOV	D1Ar5, D1Ar3
	LSR	D1Ar5, D1Ar5, #3
$Laligned_loop:
	!! get 8 chars from s
	GETL	D0Re0, D1Re0, [D0Ar6++]
	!! decrement loop counter
	SUB	D1Ar5, D1Ar5, #1
	!! test first 4 chars
	XOR	D0Re0, D0Re0, D0Ar4
	!! test second 4 chars
	MOV	D0Ar2, D1Re0
	XOR	D1Re0, D0Ar2, D0Ar4
	!! check for matches in the first 4 chars
	MOV	D0Ar2, D0Re0
	ADDT	D0Re0, D0Re0, #HI(0xfefefeff)
	ADD	D0Re0, D0Re0, #LO(0xfefefeff)
	XOR	D0Ar2, D0Ar2, #-1
	AND	D0Re0, D0Re0, D0Ar2
	ANDMT	D0Re0, D0Re0, #HI(0x80808080)
	ANDMB	D0Re0, D0Re0, #LO(0x80808080)
	CMP	D0Re0, #0
	BNZ	$Lmatch_word1
	!! check for matches in the second 4 chars
	MOV	D1Ar1, D1Re0
	ADDT	D1Re0, D1Re0, #HI(0xfefefeff)
	ADD	D1Re0, D1Re0, #LO(0xfefefeff)
	XOR	D1Ar1, D1Ar1, #-1
	AND	D1Re0, D1Re0, D1Ar1
	ANDMT	D1Re0, D1Re0, #HI(0x80808080)
	ANDMB	D1Re0, D1Re0, #LO(0x80808080)
	CMP	D1Re0, #0
	BNZ	$Lmatch_word2
	!! check if we have reached the end of the buffer
	CMP	D1Ar5, #0
	BNE	$Laligned_loop
	!! exit if there are no chars left to check
	AND	D1Ar3, D1Ar3, #7
	CMP	D1Ar3, #0
	BZ	$Lexit_fail
	!! recover c
	AND	D0Ar2, D0Ar4, #0xff
$Lbyte_loop:
	!! get 1 char from s
	GETB	D0Re0, [D0Ar6++]
	!! decrement n
	SUB	D1Ar3, D1Ar3, #1
	!! exit if we have a match
	CMP	D0Re0, D0Ar2
	BZ	$Lexit_success1
	!! fall through if we have run out of chars
	CMP	D1Ar3, #0
	BNE	$Lbyte_loop

$Lexit_fail:
	MOV	D0Re0, #0
	B	$Lend

$Lmatch_word1:
	!! move the match word into D1Re0
	MOV	D1Re0, D0Re0
	!! roll back the buffer pointer by 4 chars
	SUB	D0Ar6, D0Ar6, #4
$Lmatch_word2:
	!! roll back the buffer pointer by 4 chars
	SUB	D0Ar6, D0Ar6, #4
	!! exit if lowest byte is 0
	MOV	D1Ar1, D1Re0
	AND	D1Ar1, D1Ar1, #0xff
	CMP	D1Ar1, #0
	BNE	$Lexit_success2
	!! advance buffer pointer to the next char
	ADD	D0Ar6, D0Ar6, #1
	!! shift in the next lowest byte
	LSR	D1Re0, D1Re0, #8
	!! exit if lowest byte is 0
	MOV	D1Ar1, D1Re0
	AND	D1Ar1, D1Ar1, #0xff
	CMP	D1Ar1, #0
	BNE	$Lexit_success2
	!! advance buffer pointer to the next char
	ADD	D0Ar6, D0Ar6, #1
	!! shift in the next lowest byte
	LSR	D1Re0, D1Re0, #8
	!! exit if lowest byte is 0
	MOV	D1Ar1, D1Re0
	AND	D1Ar1, D1Ar1, #0xff
	CMP	D1Ar1, #0
	BNE	$Lexit_success2
	!! the match must be in the last byte, exit
	ADD	D0Ar6, D0Ar6, #1
	B	$Lexit_success2

$Lexit_success1:
	SUB	D0Ar6, D0Ar6, #1
$Lexit_success2:
	!! return the buffer pointer
	MOV	D0Re0, D0Ar6
$Lend:
	MOV	PC, D1RtP

	.size _memchr,.-_memchr

libc_hidden_def(memchr)