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
6#include <features.h>
7
8	.text
9	.global	_strchr
10	.type	_strchr, function
11! D1Ar1 src
12! D0Ar2 c
13_strchr:
14	AND     D0Ar2,D0Ar2,#0xff                           ! Drop all but 8 bits of c
15	MOV 	D1Ar5, D1Ar1                                ! Copy src to D1Ar5
16	AND 	D1Ar5, D1Ar5, #7                            ! Check 64 bit alignment
17	CMP 	D1Ar5, #0
18	BZ 	$Laligned64bit                              ! Jump to 64 bit aligned strchr
19$Lalign64bit:
20	GETB 	D0Re0, [D1Ar1++]                            ! Get the next character
21	ADD 	D1Ar5, D1Ar5, #1                            ! Increment alignment counter
22	CMP 	D0Re0, D0Ar2                                ! Is the char c
23	BZ 	$Lcharatprevious                            ! If so exit returning position
24	CMP 	D0Re0, #0                                   ! End of string?
25	BZ 	$Lnotfound                                  ! If so exit
26	CMP 	D1Ar5, #8                                   ! Are we aligned 64bit yet?
27	BNZ 	$Lalign64bit                                ! If not keep aligning
28$Laligned64bit:                                             ! src is 64bit aligned
29	MOV 	D0Ar4, D0Ar2                                ! put c into D0Ar4
30	LSL 	D0Ar4, D0Ar4, #8                            ! Shift it up
31	ADD 	D0Ar4, D0Ar4, D0Ar2                         ! another c
32	LSL 	D0Ar4, D0Ar4, #8                            ! shift
33	ADD 	D0Ar4, D0Ar4, D0Ar2                         ! another c
34	LSL 	D0Ar4, D0Ar4, #8                            ! shift
35	ADD 	D0Ar4, D0Ar4, D0Ar2                         ! 4 copies of c
36$Lcheck8bytes:
37	GETL 	D0Re0, D1Re0, [D1Ar1++]                     ! grab 16 bytes
38	MOV 	A0.3, D0Re0                                 ! save for later use
39							    ! first word
40							    ! check for \0
41	MOV 	D0Ar2, D0Re0                                ! D0Ar2 is a scratch now
42	ADDT 	D0Re0, D0Re0, #HI(0xfefefeff)               ! Do 4 1-byte compares
43	ADD 	D0Re0, D0Re0, #LO(0xfefefeff)
44	XOR 	D0Ar2, D0Ar2, #-1
45	AND 	D0Re0, D0Re0, D0Ar2
46	ANDMT 	D0Re0, D0Re0, #HI(0x80808080)
47	ANDMB 	D0Re0, D0Re0, #LO(0x80808080)
48	CMP 	D0Re0, #0
49	BNZ 	$Lnullinword1                               ! found \0 (or c if c==\0)
50
51							    ! Check for c
52	MOV 	D0Re0, A0.3                                 ! restore the first word
53	XOR 	D0Re0, D0Re0, D0Ar4
54	MOV 	D0Ar2, D0Re0                                ! DO 4 1-byte compares
55	ADDT 	D0Re0, D0Re0, #HI(0xfefefeff)
56	ADD 	D0Re0, D0Re0, #LO(0xfefefeff)
57	XOR 	D0Ar2, D0Ar2, #-1
58	AND 	D0Re0, D0Re0, D0Ar2
59	ANDMT 	D0Re0, D0Re0, #HI(0x80808080)
60	ANDMB 	D0Re0, D0Re0, #LO(0x80808080)
61	CMP 	D0Re0, #0
62	BNZ 	$Lcharinword1                               ! found c
63
64							    ! second word
65							    ! check for \0
66	MOV 	A0.3, D1Re0                                 ! save for later use
67	MOV 	D1Ar3, D1Re0
68	ADDT 	D1Re0, D1Re0, #HI(0xfefefeff)               ! Do 4 1-byte compares
69	ADD 	D1Re0, D1Re0, #LO(0xfefefeff)
70	XOR 	D1Ar3, D1Ar3, #-1
71	AND 	D1Re0, D1Re0, D1Ar3
72	ANDMT 	D1Re0, D1Re0, #HI(0x80808080)
73	ANDMB 	D1Re0, D1Re0, #LO(0x80808080)
74	CMP 	D1Re0, #0
75	BNZ 	$Lnullinword2                               ! Found \0 (or c if c==\0)
76
77	MOV 	D0.4, A0.3                                  ! restore the second word
78	XOR 	D1Re0, D0.4, D0Ar4                          ! test c
79
80	MOV 	D1Ar3, D1Re0
81	ADDT 	D1Re0, D1Re0, #HI(0xfefefeff)               ! Do 4 1-byte compares
82	ADD 	D1Re0, D1Re0, #LO(0xfefefeff)
83	XOR 	D1Ar3, D1Ar3, #-1
84	AND 	D1Re0, D1Re0, D1Ar3
85	ANDMT 	D1Re0, D1Re0, #HI(0x80808080)
86	ANDMB 	D1Re0, D1Re0, #LO(0x80808080)
87	CMP 	D1Re0, #0
88	BNZ 	$Lcharinword2                               ! found c
89
90	B 	$Lcheck8bytes                               ! Keep checking
91
92$Lnullinword1:                                              ! found \0 somewhere, check for c too
93	SUB 	D1Ar1, D1Ar1, #4
94$Lnullinword2:
95	SUB 	D1Ar1, D1Ar1, #4
96	AND 	D0Ar2, D0Ar4, #0xff                         ! restore c
97	MOV 	D0Re0, A0.3                                 ! restore the word
98	MOV 	D0.4, D0Re0                                 ! for shifting later
99	AND 	D0Re0, D0Re0, #0xff                         ! take first byte of word
100	CMP 	D0Re0, D0Ar2
101	BZ 	$Lcharatcurrent                             ! found c
102	CMP 	D0Re0, #0!
103	BZ 	$Lnotfound                                  ! found \0
104
105	ADD 	D1Ar1, D1Ar1, #1
106	LSR 	D0.4, D0.4, #8
107	MOV 	D0Re0, D0.4
108	AND 	D0Re0, D0Re0, #0xff                         ! take second byte of word
109	CMP 	D0Re0, D0Ar2
110	BZ 	$Lcharatcurrent                             ! found c
111	CMP 	D0Re0, #0
112	BZ 	$Lnotfound                                  ! found \0
113
114	ADD 	D1Ar1, D1Ar1, #1
115	LSR 	D0.4, D0.4, #8
116	MOV 	D0Re0, D0.4
117	AND 	D0Re0, D0Re0, #0xff                         ! take third byte of word
118	CMP 	D0Re0, D0Ar2
119	BZ 	$Lcharatcurrent                             ! found c
120	CMP 	D0Re0, #0
121	BZ 	$Lnotfound                                  ! found \0
122
123	ADD 	D1Ar1, D1Ar1, #1                            ! move to 4th byte
124	CMP     D0Ar2, #0                                   ! If c was \0
125	BZ      $Lcharatcurrent                             ! c has been found!
126
127$Lnotfound:
128	MOV 	D0Re0,		#0                          ! End of string c not found
129	B 	$Lend
130
131$Lcharinword1: 						    ! found c in first word
132	MOV 	D1Re0, D0Re0
133	SUB 	D1Ar1, D1Ar1, #4
134$Lcharinword2:                                              ! found c in second word
135	SUB 	D1Ar1, D1Ar1, #4
136
137	AND 	D0Re0, D1Re0, #0xff                         ! First byte
138	CMP 	D0Re0, #0                                   ! Test c (zero indicates c due
139							    ! to the 4 1-byte compare code)
140	BNE 	$Lcharatcurrent
141	ADD 	D1Ar1, D1Ar1, #1
142
143	LSR 	D1Re0, D1Re0, #8
144	AND 	D0Re0, D1Re0, #0xff                         ! Second byte
145	CMP 	D0Re0, #0                                   ! Test c (indicated by zero)
146	BNE 	$Lcharatcurrent
147	ADD 	D1Ar1, D1Ar1, #1
148
149	LSR 	D1Re0, D1Re0, #8
150	AND 	D0Re0, D1Re0, #0xff                         ! Third byte
151	CMP 	D0Re0, #0                                   ! Test c (indicated by zero)
152	BNE 	$Lcharatcurrent
153	ADD 	D1Ar1, D1Ar1, #1                            ! Must be the fourth byte
154	B 	$Lcharatcurrent
155
156$Lcharatprevious:
157	SUB 	D1Ar1, D1Ar1, #1                            ! Fix-up pointer
158$Lcharatcurrent:
159	MOV 	D0Re0, D1Ar1                                ! Return the string pointer
160$Lend:
161	MOV 	PC, D1RtP
162	.size _strchr,.-_strchr
163
164libc_hidden_def(strchr)
165#ifdef __UCLIBC_SUSV3_LEGACY__
166strong_alias(strchr,index)
167#endif
168