Update copyright notices with scripts/update-copyrights
[glibc.git] / ports / sysdeps / arm / armv6 / strchr.S
blobe4de0f332397b5d733cc59bb319448d7820a13a7
1 /* strchr -- find the first instance of C in a nul-terminated string.
2    Copyright (C) 2013-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library.  If not, see
17    <http://www.gnu.org/licenses/>.  */
19 #include <sysdep.h>
21         .syntax unified
22         .text
24 ENTRY (strchr)
25         @ r0 = start of string
26         @ r1 = character to match
27         @ returns NULL for no match, or a pointer to the match
28         sfi_breg r0, \
29         ldrb    r2, [\B]                @ load the first byte asap
30         uxtb    r1, r1
32         @ To cater to long strings, we want to search through a few
33         @ characters until we reach an aligned pointer.  To cater to
34         @ small strings, we don't want to start doing word operations
35         @ immediately.  The compromise is a maximum of 16 bytes less
36         @ whatever is required to end with an aligned pointer.
37         @ r3 = number of characters to search in alignment loop
38         and     r3, r0, #7
39         rsb     r3, r3, #15             @ 16 - 1 peeled loop iteration
40         cmp     r2, r1                  @ Found C?
41         it      ne
42         cmpne   r2, #0                  @ Found EOS?
43         beq     99f
45         @ Loop until we find ...
46 1:      sfi_breg r0, \
47         ldrb    r2, [\B, #1]!
48         subs    r3, r3, #1              @ ... the aligment point
49         it      ne
50         cmpne   r2, r1                  @ ... or the character
51         it      ne
52         cmpne   r2, #0                  @ ... or EOS
53         bne     1b
55         @ Disambiguate the exit possibilites above
56         cmp     r2, r1                  @ Found the character
57         it      ne
58         cmpne   r2, #0                  @ Found EOS
59         beq     99f
60         add     r0, r0, #1
62         @ So now we're aligned.  Now we actually need a stack frame.
63         push    { r4, r5, r6, r7 }
64         cfi_adjust_cfa_offset (16)
65         cfi_rel_offset (r4, 0)
66         cfi_rel_offset (r5, 4)
67         cfi_rel_offset (r6, 8)
68         cfi_rel_offset (r7, 12)
70         sfi_breg r0, \
71         ldrd    r2, r3, [\B], #8
72         orr     r1, r1, r1, lsl #8      @ Replicate C to all bytes
73 #ifdef ARCH_HAS_T2
74         movw    ip, #0x0101
75         sfi_pld r0, #64
76         movt    ip, #0x0101
77 #else
78         ldr     ip, =0x01010101
79         sfi_pld r0, #64
80 #endif
81         orr     r1, r1, r1, lsl #16
83         @ Loop searching for EOS or C, 8 bytes at a time.
85         @ Subtracting (unsigned saturating) from 1 means result of 1 for
86         @ any byte that was originally zero and 0 otherwise.  Therefore
87         @ we consider the lsb of each byte the "found" bit.
88         uqsub8  r4, ip, r2              @ Find EOS
89         eor     r6, r2, r1              @ Convert C bytes to 0
90         uqsub8  r5, ip, r3
91         eor     r7, r3, r1
92         uqsub8  r6, ip, r6              @ Find C
93         sfi_pld r0, #128                @ Prefetch 2 lines ahead
94         uqsub8  r7, ip, r7
95         orr     r4, r4, r6              @ Combine found for EOS and C
96         orr     r5, r5, r7
97         orrs    r6, r4, r5              @ Combine the two words
98         it      eq
99         sfi_breg r0, \
100         ldrdeq  r2, r3, [\B], #8
101         beq     2b
103         @ Found something.  Disambiguate between first and second words.
104         @ Adjust r0 to point to the word containing the match.
105         @ Adjust r2 to the contents of the word containing the match.
106         @ Adjust r4 to the found bits for the word containing the match.
107         cmp     r4, #0
108         sub     r0, r0, #4
109         itte    eq
110         moveq   r4, r5
111         moveq   r2, r3
112         subne   r0, r0, #4
114         @ Find the bit-offset of the match within the word.
115 #if defined(__ARMEL__)
116         @ For LE, swap the found word so clz searches from the little end.
117         rev     r4, r4
118 #else
119         @ For BE, byte swap the word to make it easier to extract the byte.
120         rev     r2, r2
121 #endif
122         @ We're counting 0x01 (not 0x80), so the bit offset is 7 too high.
123         clz     r3, r4
124         sub     r3, r3, #7
125         lsr     r2, r2, r3              @ Shift down found byte
126         uxtb    r1, r1                  @ Undo replication of C
127         uxtb    r2, r2                  @ Extract found byte
128         add     r0, r0, r3, lsr #3      @ Adjust the pointer to the found byte
130         pop     { r4, r5, r6, r7 }
131         cfi_adjust_cfa_offset (-16)
132         cfi_restore (r4)
133         cfi_restore (r5)
134         cfi_restore (r6)
135         cfi_restore (r7)
137         @ Disambiguate between EOS and C.
139         cmp     r2, r1
140         it      ne
141         movne   r0, #0                  @ Found EOS, return NULL
142         bx      lr
144 END (strchr)
146 weak_alias (strchr, index)
147 libc_hidden_builtin_def (strchr)