1!    Copyright (C) 2013 Imagination Technologies Ltd.
2!
3!    Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
4
5	.text
6	.global	_memchr
7	.type	_memchr,function
8! D0Ar6 src
9! D0Ar2 c
10! D1Ar3 n
11_memchr:
12	CMP     D1Ar3, #0
13	BEQ	$Lexit_fail
14	!! convert c to unsigned char
15	AND     D0Ar2,D0Ar2,#0xff
16	MOV	D0Ar6, D1Ar1
17	MOV	D1Ar5, D0Ar6
18	!! test alignment
19	AND	D1Ar5, D1Ar5, #7
20	CMP	D1Ar5, #0
21	BNZ	$Lunaligned_loop
22	!! length must be greater than or equal to 8 for aligned loop
23	CMP     D1Ar3, #8
24	BGE     $Laligned_setup
25$Lunaligned_loop:
26	!! get 1 char from s
27	GETB	D0Re0, [D0Ar6++]
28	!! increase alignment counter
29	ADD	D1Ar5, D1Ar5, #1
30	!! decrement n
31	SUB     D1Ar3, D1Ar3, #1
32	!! exit if we have a match
33	CMP	D0Re0, D0Ar2
34	BZ	$Lexit_success1
35	!! exit if we have hit the end of the string
36	CMP	D1Ar3, #0
37	BZ	$Lexit_fail
38	!! fall through if the buffer is aligned now
39	CMP	D1Ar5, #8
40	BNE	$Lunaligned_loop
41	!! fall through if there is more than 8 bytes left
42	CMP	D1Ar3, #8
43	BLT	$Lunaligned_loop
44$Laligned_setup:
45	!! fill the c into 4 bytes
46	MOV	D0Ar4, D0Ar2
47	LSL	D0Ar4, D0Ar4, #8
48	ADD	D0Ar4, D0Ar4, D0Ar2
49	LSL	D0Ar4, D0Ar4, #8
50	ADD	D0Ar4, D0Ar4, D0Ar2
51	LSL	D0Ar4, D0Ar4, #8
52	ADD	D0Ar4, D0Ar4, D0Ar2
53	!! divide n by 8
54	MOV	D1Ar5, D1Ar3
55	LSR	D1Ar5, D1Ar5, #3
56$Laligned_loop:
57	!! get 8 chars from s
58	GETL	D0Re0, D1Re0, [D0Ar6++]
59	!! decrement loop counter
60	SUB	D1Ar5, D1Ar5, #1
61	!! test first 4 chars
62	XOR	D0Re0, D0Re0, D0Ar4
63	!! test second 4 chars
64	MOV	D0Ar2, D1Re0
65	XOR	D1Re0, D0Ar2, D0Ar4
66	!! check for matches in the first 4 chars
67	MOV	D0Ar2, D0Re0
68	ADDT	D0Re0, D0Re0, #HI(0xfefefeff)
69	ADD	D0Re0, D0Re0, #LO(0xfefefeff)
70	XOR	D0Ar2, D0Ar2, #-1
71	AND	D0Re0, D0Re0, D0Ar2
72	ANDMT	D0Re0, D0Re0, #HI(0x80808080)
73	ANDMB	D0Re0, D0Re0, #LO(0x80808080)
74	CMP	D0Re0, #0
75	BNZ	$Lmatch_word1
76	!! check for matches in the second 4 chars
77	MOV	D1Ar1, D1Re0
78	ADDT	D1Re0, D1Re0, #HI(0xfefefeff)
79	ADD	D1Re0, D1Re0, #LO(0xfefefeff)
80	XOR	D1Ar1, D1Ar1, #-1
81	AND	D1Re0, D1Re0, D1Ar1
82	ANDMT	D1Re0, D1Re0, #HI(0x80808080)
83	ANDMB	D1Re0, D1Re0, #LO(0x80808080)
84	CMP	D1Re0, #0
85	BNZ	$Lmatch_word2
86	!! check if we have reached the end of the buffer
87	CMP	D1Ar5, #0
88	BNE	$Laligned_loop
89	!! exit if there are no chars left to check
90	AND	D1Ar3, D1Ar3, #7
91	CMP	D1Ar3, #0
92	BZ	$Lexit_fail
93	!! recover c
94	AND	D0Ar2, D0Ar4, #0xff
95$Lbyte_loop:
96	!! get 1 char from s
97	GETB	D0Re0, [D0Ar6++]
98	!! decrement n
99	SUB	D1Ar3, D1Ar3, #1
100	!! exit if we have a match
101	CMP	D0Re0, D0Ar2
102	BZ	$Lexit_success1
103	!! fall through if we have run out of chars
104	CMP	D1Ar3, #0
105	BNE	$Lbyte_loop
106
107$Lexit_fail:
108	MOV	D0Re0, #0
109	B	$Lend
110
111$Lmatch_word1:
112	!! move the match word into D1Re0
113	MOV	D1Re0, D0Re0
114	!! roll back the buffer pointer by 4 chars
115	SUB	D0Ar6, D0Ar6, #4
116$Lmatch_word2:
117	!! roll back the buffer pointer by 4 chars
118	SUB	D0Ar6, D0Ar6, #4
119	!! exit if lowest byte is 0
120	MOV	D1Ar1, D1Re0
121	AND	D1Ar1, D1Ar1, #0xff
122	CMP	D1Ar1, #0
123	BNE	$Lexit_success2
124	!! advance buffer pointer to the next char
125	ADD	D0Ar6, D0Ar6, #1
126	!! shift in the next lowest byte
127	LSR	D1Re0, D1Re0, #8
128	!! exit if lowest byte is 0
129	MOV	D1Ar1, D1Re0
130	AND	D1Ar1, D1Ar1, #0xff
131	CMP	D1Ar1, #0
132	BNE	$Lexit_success2
133	!! advance buffer pointer to the next char
134	ADD	D0Ar6, D0Ar6, #1
135	!! shift in the next lowest byte
136	LSR	D1Re0, D1Re0, #8
137	!! exit if lowest byte is 0
138	MOV	D1Ar1, D1Re0
139	AND	D1Ar1, D1Ar1, #0xff
140	CMP	D1Ar1, #0
141	BNE	$Lexit_success2
142	!! the match must be in the last byte, exit
143	ADD	D0Ar6, D0Ar6, #1
144	B	$Lexit_success2
145
146$Lexit_success1:
147	SUB	D0Ar6, D0Ar6, #1
148$Lexit_success2:
149	!! return the buffer pointer
150	MOV	D0Re0, D0Ar6
151$Lend:
152	MOV	PC, D1RtP
153
154	.size _memchr,.-_memchr
155
156libc_hidden_def(memchr)
157