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)
|