summaryrefslogtreecommitdiff
path: root/libc/string/metag/strchr.S
blob: 6b0f2ea435548c1591bc2e5e13a5c513c6d1a2b9 (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
158
159
160
161
162
163
164
165
166
167
!    Copyright (C) 2013 Imagination Technologies Ltd.

!    Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.


#include <features.h>

	.text
	.global	_strchr
	.type	_strchr, function
! D1Ar1 src
! D0Ar2 c
_strchr:
	AND     D0Ar2,D0Ar2,#0xff                           ! Drop all but 8 bits of c
	MOV 	D1Ar5, D1Ar1                                ! Copy src to D1Ar5
	AND 	D1Ar5, D1Ar5, #7                            ! Check 64 bit alignment
	CMP 	D1Ar5, #0
	BZ 	$Laligned64bit                              ! Jump to 64 bit aligned strchr
$Lalign64bit:
	GETB 	D0Re0, [D1Ar1++]                            ! Get the next character
	ADD 	D1Ar5, D1Ar5, #1                            ! Increment alignment counter
	CMP 	D0Re0, D0Ar2                                ! Is the char c
	BZ 	$Lcharatprevious                            ! If so exit returning position
	CMP 	D0Re0, #0                                   ! End of string?
	BZ 	$Lnotfound                                  ! If so exit
	CMP 	D1Ar5, #8                                   ! Are we aligned 64bit yet?
	BNZ 	$Lalign64bit                                ! If not keep aligning
$Laligned64bit:                                             ! src is 64bit aligned
	MOV 	D0Ar4, D0Ar2                                ! put c into D0Ar4
	LSL 	D0Ar4, D0Ar4, #8                            ! Shift it up
	ADD 	D0Ar4, D0Ar4, D0Ar2                         ! another c
	LSL 	D0Ar4, D0Ar4, #8                            ! shift
	ADD 	D0Ar4, D0Ar4, D0Ar2                         ! another c
	LSL 	D0Ar4, D0Ar4, #8                            ! shift
	ADD 	D0Ar4, D0Ar4, D0Ar2                         ! 4 copies of c
$Lcheck8bytes:
	GETL 	D0Re0, D1Re0, [D1Ar1++]                     ! grab 16 bytes
	MOV 	A0.3, D0Re0                                 ! save for later use
							    ! first word
							    ! check for \0
	MOV 	D0Ar2, D0Re0                                ! D0Ar2 is a scratch now
	ADDT 	D0Re0, D0Re0, #HI(0xfefefeff)               ! Do 4 1-byte compares
	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 	$Lnullinword1                               ! found \0 (or c if c==\0)

							    ! Check for c
	MOV 	D0Re0, A0.3                                 ! restore the first word
	XOR 	D0Re0, D0Re0, D0Ar4
	MOV 	D0Ar2, D0Re0                                ! DO 4 1-byte compares
	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 	$Lcharinword1                               ! found c

							    ! second word
							    ! check for \0
	MOV 	A0.3, D1Re0                                 ! save for later use
	MOV 	D1Ar3, D1Re0
	ADDT 	D1Re0, D1Re0, #HI(0xfefefeff)               ! Do 4 1-byte compares
	ADD 	D1Re0, D1Re0, #LO(0xfefefeff)
	XOR 	D1Ar3, D1Ar3, #-1
	AND 	D1Re0, D1Re0, D1Ar3
	ANDMT 	D1Re0, D1Re0, #HI(0x80808080)
	ANDMB 	D1Re0, D1Re0, #LO(0x80808080)
	CMP 	D1Re0, #0
	BNZ 	$Lnullinword2                               ! Found \0 (or c if c==\0)

	MOV 	D0.4, A0.3                                  ! restore the second word
	XOR 	D1Re0, D0.4, D0Ar4                          ! test c

	MOV 	D1Ar3, D1Re0
	ADDT 	D1Re0, D1Re0, #HI(0xfefefeff)               ! Do 4 1-byte compares
	ADD 	D1Re0, D1Re0, #LO(0xfefefeff)
	XOR 	D1Ar3, D1Ar3, #-1
	AND 	D1Re0, D1Re0, D1Ar3
	ANDMT 	D1Re0, D1Re0, #HI(0x80808080)
	ANDMB 	D1Re0, D1Re0, #LO(0x80808080)
	CMP 	D1Re0, #0
	BNZ 	$Lcharinword2                               ! found c

	B 	$Lcheck8bytes                               ! Keep checking

$Lnullinword1:                                              ! found \0 somewhere, check for c too
	SUB 	D1Ar1, D1Ar1, #4
$Lnullinword2:
	SUB 	D1Ar1, D1Ar1, #4
	AND 	D0Ar2, D0Ar4, #0xff                         ! restore c
	MOV 	D0Re0, A0.3                                 ! restore the word
	MOV 	D0.4, D0Re0                                 ! for shifting later
	AND 	D0Re0, D0Re0, #0xff                         ! take first byte of word
	CMP 	D0Re0, D0Ar2
	BZ 	$Lcharatcurrent                             ! found c
	CMP 	D0Re0, #0!
	BZ 	$Lnotfound                                  ! found \0

	ADD 	D1Ar1, D1Ar1, #1
	LSR 	D0.4, D0.4, #8
	MOV 	D0Re0, D0.4
	AND 	D0Re0, D0Re0, #0xff                         ! take second byte of word
	CMP 	D0Re0, D0Ar2
	BZ 	$Lcharatcurrent                             ! found c
	CMP 	D0Re0, #0
	BZ 	$Lnotfound                                  ! found \0

	ADD 	D1Ar1, D1Ar1, #1
	LSR 	D0.4, D0.4, #8
	MOV 	D0Re0, D0.4
	AND 	D0Re0, D0Re0, #0xff                         ! take third byte of word
	CMP 	D0Re0, D0Ar2
	BZ 	$Lcharatcurrent                             ! found c
	CMP 	D0Re0, #0
	BZ 	$Lnotfound                                  ! found \0

	ADD 	D1Ar1, D1Ar1, #1                            ! move to 4th byte
	CMP     D0Ar2, #0                                   ! If c was \0
	BZ      $Lcharatcurrent                             ! c has been found!

$Lnotfound:
	MOV 	D0Re0,		#0                          ! End of string c not found
	B 	$Lend

$Lcharinword1: 						    ! found c in first word
	MOV 	D1Re0, D0Re0
	SUB 	D1Ar1, D1Ar1, #4
$Lcharinword2:                                              ! found c in second word
	SUB 	D1Ar1, D1Ar1, #4

	AND 	D0Re0, D1Re0, #0xff                         ! First byte
	CMP 	D0Re0, #0                                   ! Test c (zero indicates c due
							    ! to the 4 1-byte compare code)
	BNE 	$Lcharatcurrent
	ADD 	D1Ar1, D1Ar1, #1

	LSR 	D1Re0, D1Re0, #8
	AND 	D0Re0, D1Re0, #0xff                         ! Second byte
	CMP 	D0Re0, #0                                   ! Test c (indicated by zero)
	BNE 	$Lcharatcurrent
	ADD 	D1Ar1, D1Ar1, #1

	LSR 	D1Re0, D1Re0, #8
	AND 	D0Re0, D1Re0, #0xff                         ! Third byte
	CMP 	D0Re0, #0                                   ! Test c (indicated by zero)
	BNE 	$Lcharatcurrent
	ADD 	D1Ar1, D1Ar1, #1                            ! Must be the fourth byte
	B 	$Lcharatcurrent

$Lcharatprevious:
	SUB 	D1Ar1, D1Ar1, #1                            ! Fix-up pointer
$Lcharatcurrent:
	MOV 	D0Re0, D1Ar1                                ! Return the string pointer
$Lend:
	MOV 	PC, D1RtP
	.size _strchr,.-_strchr

libc_hidden_def(strchr)
#ifdef __UCLIBC_SUSV3_LEGACY__
strong_alias(strchr,index)
#endif