~linaro-toolchain-dev/cortex-strings/trunk

« back to all changes in this revision

Viewing changes to reference/glibc/strchr.S

  • Committer: Will Newton
  • Date: 2013-11-29 18:10:00 UTC
  • Revision ID: will.newton@linaro.org-20131129181000-i4qers0vxwao2a5g
Add glibc strchr reference implementation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* strchr -- find the first instance 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.
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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/>.  */
 
18
 
 
19
#define ARCH_HAS_T2
 
20
 
 
21
        .syntax unified
 
22
        .text
 
23
        .global strchr
 
24
        .type strchr,%function
 
25
        .align 4
 
26
 
 
27
strchr:
 
28
        @ r0 = start of string
 
29
        @ r1 = character to match
 
30
        @ returns NULL for no match, or a pointer to the match
 
31
        ldrb    r2, [r0]                @ load the first byte asap
 
32
        uxtb    r1, r1
 
33
 
 
34
        @ To cater to long strings, we want to search through a few
 
35
        @ characters until we reach an aligned pointer.  To cater to
 
36
        @ small strings, we don't want to start doing word operations
 
37
        @ immediately.  The compromise is a maximum of 16 bytes less
 
38
        @ whatever is required to end with an aligned pointer.
 
39
        @ r3 = number of characters to search in alignment loop
 
40
        and     r3, r0, #7
 
41
        rsb     r3, r3, #15             @ 16 - 1 peeled loop iteration
 
42
        cmp     r2, r1                  @ Found C?
 
43
        it      ne
 
44
        cmpne   r2, #0                  @ Found EOS?
 
45
        beq     99f
 
46
 
 
47
        @ Loop until we find ...
 
48
1:      ldrb    r2, [r0, #1]!
 
49
        subs    r3, r3, #1              @ ... the aligment point
 
50
        it      ne
 
51
        cmpne   r2, r1                  @ ... or the character
 
52
        it      ne
 
53
        cmpne   r2, #0                  @ ... or EOS
 
54
        bne     1b
 
55
 
 
56
        @ Disambiguate the exit possibilites above
 
57
        cmp     r2, r1                  @ Found the character
 
58
        it      ne
 
59
        cmpne   r2, #0                  @ Found EOS
 
60
        beq     99f
 
61
        add     r0, r0, #1
 
62
 
 
63
        @ So now we're aligned.  Now we actually need a stack frame.
 
64
        push    { r4, r5, r6, r7 }
 
65
 
 
66
        ldrd    r2, r3, [r0], #8
 
67
        orr     r1, r1, r1, lsl #8      @ Replicate C to all bytes
 
68
#ifdef ARCH_HAS_T2
 
69
        movw    ip, #0x0101
 
70
        pld     [r0, #64]
 
71
        movt    ip, #0x0101
 
72
#else
 
73
        ldr     ip, =0x01010101
 
74
        pld     [r0, #64]
 
75
#endif
 
76
        orr     r1, r1, r1, lsl #16
 
77
 
 
78
        @ Loop searching for EOS or C, 8 bytes at a time.
 
79
2:
 
80
        @ Subtracting (unsigned saturating) from 1 means result of 1 for
 
81
        @ any byte that was originally zero and 0 otherwise.  Therefore
 
82
        @ we consider the lsb of each byte the "found" bit.
 
83
        uqsub8  r4, ip, r2              @ Find EOS
 
84
        eor     r6, r2, r1              @ Convert C bytes to 0
 
85
        uqsub8  r5, ip, r3
 
86
        eor     r7, r3, r1
 
87
        uqsub8  r6, ip, r6              @ Find C
 
88
        pld     [r0, #128]              @ Prefetch 2 lines ahead
 
89
        uqsub8  r7, ip, r7
 
90
        orr     r4, r4, r6              @ Combine found for EOS and C
 
91
        orr     r5, r5, r7
 
92
        orrs    r6, r4, r5              @ Combine the two words
 
93
        it      eq
 
94
        ldrdeq  r2, r3, [r0], #8
 
95
        beq     2b
 
96
 
 
97
        @ Found something.  Disambiguate between first and second words.
 
98
        @ Adjust r0 to point to the word containing the match.
 
99
        @ Adjust r2 to the contents of the word containing the match.
 
100
        @ Adjust r4 to the found bits for the word containing the match.
 
101
        cmp     r4, #0
 
102
        sub     r0, r0, #4
 
103
        itte    eq
 
104
        moveq   r4, r5
 
105
        moveq   r2, r3
 
106
        subne   r0, r0, #4
 
107
 
 
108
        @ Find the bit-offset of the match within the word.
 
109
#if defined(__ARMEL__)
 
110
        @ For LE, swap the found word so clz searches from the little end.
 
111
        rev     r4, r4
 
112
#else
 
113
        @ For BE, byte swap the word to make it easier to extract the byte.
 
114
        rev     r2, r2
 
115
#endif
 
116
        @ We're counting 0x01 (not 0x80), so the bit offset is 7 too high.
 
117
        clz     r3, r4
 
118
        sub     r3, r3, #7
 
119
        lsr     r2, r2, r3              @ Shift down found byte
 
120
        uxtb    r1, r1                  @ Undo replication of C
 
121
        uxtb    r2, r2                  @ Extract found byte
 
122
        add     r0, r0, r3, lsr #3      @ Adjust the pointer to the found byte
 
123
 
 
124
        pop     { r4, r5, r6, r7 }
 
125
 
 
126
        @ Disambiguate between EOS and C.
 
127
99:
 
128
        cmp     r2, r1
 
129
        it      ne
 
130
        movne   r0, #0                  @ Found EOS, return NULL
 
131
        bx      lr
 
132
        .size strchr,.-strchr