arm: Implement armv6 optimized string routines
[glibc.git] / ports / sysdeps / arm / armv6 / strrchr.S
blobddd4f7fc061996d32ea3a0bcffc2d0a9488675b5
1 /* strrchr -- find the last occurence of C in a nul-terminated string
2    Copyright (C) 2013 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 (strrchr)
25         @ r0 = start of string
26         @ r1 = character to match
27         @ returns NULL for no match, or a pointer to the match
29         mov     r3, r0
30         mov     r0, #0
31         uxtb    r1, r1
33         @ Loop a few times until we're aligned.
34         tst     r3, #7
35         beq     2f
36 1:      ldrb    r2, [r3], #1
37         cmp     r2, r1                  @ Find the character
38         it      eq
39         subeq   r0, r3, #1
40         cmp     r2, #0                  @ Find EOS
41         it      eq
42         bxeq    lr
43         tst     r3, #7                  @ Find the aligment point
44         bne     1b
46         @ So now we're aligned.  Now we actually need a stack frame.
47 2:      push    { r4, r5, r6, r7 }
48         cfi_adjust_cfa_offset (16)
49         cfi_rel_offset (r4, 0)
50         cfi_rel_offset (r5, 4)
51         cfi_rel_offset (r6, 8)
52         cfi_rel_offset (r7, 12)
54         orr     r1, r1, r1, lsl #8      @ Replicate C to all bytes
55 #ifdef ARCH_HAS_T2
56         movw    ip, #0x0101
57         movt    ip, #0x0101
58 #else
59         ldr     ip, =0x01010101
60 #endif
61         orr     r1, r1, r1, lsl #16
62         mov     r2, #0                  @ No found bits yet
64         @ Loop searching for EOS and C, 8 bytes at a time.
65         @ Any time we find a match in a word, we copy the address of
66         @ the word to r0, and the found bits to r2.
67 3:      ldrd    r4, r5, [r3], #8
68         @ Subtracting (unsigned saturating) from 1 means result of 1 for
69         @ any byte that was originally zero and 0 otherwise.  Therefore
70         @ we consider the lsb of each byte the "found" bit.
71         uqsub8  r6, ip, r4              @ Find EOS
72         uqsub8  r7, ip, r5
73         eor     r4, r4, r1              @ Convert C bytes to 0
74         eor     r5, r5, r1
75         uqsub8  r4, ip, r4              @ Find C
76         uqsub8  r5, ip, r5
77         cmp     r6, #0                  @ Found EOS, first word
78         bne     4f
79         cmp     r4, #0                  @ Handle C, first word
80         itt     ne
81         subne   r0, r3, #8
82         movne   r2, r4
83         cmp     r7, #0                  @ Found EOS, second word
84         bne     5f
85         cmp     r5, #0                  @ Handle C, second word
86         itt     ne
87         subne   r0, r3, #4
88         movne   r2, r5
89         b       3b
91         @ Found EOS in second word; fold to first word.
92 5:      add     r3, r3, #4              @ Dec pointer to 2nd word, with below
93         mov     r4, r5                  @ Overwrite first word C found
94         mov     r6, r7                  @ Overwrite first word EOS found
96         @ Found EOS.  Zap found C after EOS.
97 4:      sub     r3, r3, #8              @ Decrement pointer to first word
98 #ifdef __ARMEB__
99         @ Byte swap to be congruent with LE, which is easier from here on.
100         rev     r6, r6                  @ Byte swap found EOS,
101         rev     r4, r4                  @ ... this found C
102         rev     r2, r2                  @ ... prev found C
103 #endif
104         sub     r7, r6, #1              @ Toggle EOS lsb and below
105         eor     r6, r6, r7              @ All bits below and including lsb
106         ands    r4, r4, r6              @ Zap C above EOS
107         itt     ne
108         movne   r2, r4                  @ Copy to result, if still non-zero
109         movne   r0, r3
111         pop     { r4, r5, r6, r7 }
112         cfi_adjust_cfa_offset (-16)
113         cfi_restore (r4)
114         cfi_restore (r5)
115         cfi_restore (r6)
116         cfi_restore (r7)
118         @ Adjust the result pointer if we found a word containing C.
119         cmp     r2, #0
120         clz     r2, r2                  @ Find the bit offset of the last C
121         itt     ne
122         rsbne   r2, r2, #32             @ Convert to a count from the right
123         addne   r0, r0, r2, lsr #3      @ Convert to byte offset and add.
124         bx      lr
126 END (strrchr)
128 weak_alias (strrchr, rindex)
129 libc_hidden_builtin_def (strrchr)