Drop main() prototype. Syncs with NetBSD-8
[minix.git] / common / lib / libc / arch / arm / string / strchr_arm.S
blob864ce61a8941f559a5468ef7efa147b6b2d3418d
1 /*-
2  * Copyright (c) 2013 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Matt Thomas of 3am Software Foundry.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
30 #include <machine/asm.h>
32 RCSID("$NetBSD: strchr_arm.S,v 1.8 2013/08/19 17:50:04 matt Exp $")
34 #if defined(__thumb__) && !defined(_ARM_ARCH_T2)
35 #error Only Thumb2 or ARM supported
36 #endif
38 #ifdef __ARMEL__
39 #define BYTE0   0x000000ff
40 #define BYTE1   0x0000ff00
41 #define BYTE2   0x00ff0000
42 #define BYTE3   0xff000000
43 #define lshi    lsl
44 #define lshis   lsls
45 #else
46 #define BYTE0   0xff000000
47 #define BYTE1   0x00ff0000
48 #define BYTE2   0x0000ff00
49 #define BYTE3   0x000000ff
50 #define lshi    lsr
51 #define lshis   lsrs
52 #endif
54         .text
55 ENTRY(strchr)
56         and     r2, r1, #0xff           /* restrict to byte value */
57 1:      tst     r0, #3                  /* test for word alignment */
58         beq     .Lpre_main_loop         /*   finally word aligned */
59         ldrb    r3, [r0], #1            /* load a byte */
60         cmp     r3, r2                  /* is it a match? */
61         beq     2f                      /*   yes, return current ptr - 1 */
62         cmp     r3, #0                  /* no, was it 0? */
63         bne     1b                      /*   no, try next byte */
64         movs    r0, #0                  /*   yes, set return value to NULL */
65         RET                             /* return */
66 2:      subs    r0, r0, #1              /* back up by one */
67         RET                             /* return */
68 .Lpre_main_loop:
69 #if defined(_ARM_ARCH_7)
70         movw    ip, #0xfefe             /* magic constant; 254 in each byte */
71         movt    ip, #0xfefe             /* magic constant; 254 in each byte */
72 #elif defined(_ARM_ARCH_6)
73         mov     ip, #0xfe               /* put 254 in low byte */
74         orr     ip, ip, ip, lsl #8      /* move to next byte */
75         orr     ip, ip, ip, lsl #16     /* move to next halfword */
76 #endif /* _ARM_ARCH_6 */
77         orr     r2, r2, r2, lsl #8      /* move to next byte */
78         orr     r2, r2, r2, lsl #16     /* move to next halfword */
79 .Lmain_loop:
80         ldr     r3, [r0], #4            /* load next word */
81 #if defined(_ARM_ARCH_6)
82         /*
83          * Add 254 to each byte using the UQADD8 (unsigned saturating add 8)
84          * instruction.  For every non-NUL byte, the result for that byte will
85          * become 255.  For NUL, it will be 254.  When we complement the
86          * result, if the result is non-0 then we must have encountered a NUL.
87          */
88         uqadd8  r1, r3, ip              /* NUL detection happens here */
89         eors    r3, r3, r2              /* xor to clear each lane */
90         uqadd8  r3, r3, ip              /* char detection happens here */
91         ands    r3, r3, r1              /* merge results */
92         mvns    r3, r3                  /* is the complement non-0? */
93         beq     .Lmain_loop             /*    no, then keep going */
95         /*
96          * We've encountered a NUL or a match but we don't know which happened
97          * first.
98          */
99 #if defined(__thumb__) && defined(_ARM_ARCH_T2)
100         cbz     r2, .Lfind_match        /* searching for NUL? yes, find it */
101 #else
102         cmp     r2, #0                  /* searching for NUL? */
103         beq     .Lfind_match            /*   yes, find the match */
104 #endif
105         mvns    r1, r1                  /* did we encounter a NUL? */
106         beq     .Lfind_match            /*   no, find the match */
107         bics    r3, r3, r1              /* clear match for the NUL(s) */
108         beq     .Lnomatch               /*   any left set? if not, no match */
109         lshis   r1, r1, #8              /* replicate NUL bit to other bytes */
110 #ifdef __thumb__
111         itt     ne
112 #endif
113         orrne   r1, r1, r1, lshi #8     /* replicate NUL bit to other bytes */
114         orrne   r1, r1, r1, lshi #8     /* replicate NUL bit to other bytes */
115         bics    r3, r3, r1              /* clear any match bits after the NUL */
116         beq     .Lnomatch               /*   any left set? if not, no match */
117 .Lfind_match:
118 #ifdef __ARMEL__
119         rev     r3, r3                  /* we want this in BE for the CLZ */
120 #endif
121         clz     r3, r3                  /* count how many leading zeros */
122         add     r0, r0, r3, lsr #3      /* divide that by 8 and add to count */
123         subs    r0, r0, #4              /* compensate for the post-inc */
124         RET
125 .Lnomatch:
126         movs    r0, #0
127         RET
128 #else
129         /*
130          * No fancy shortcuts so just test each byte lane for a NUL.
131          * (other tests for NULs in a word take more instructions/cycles).
132          */
133         eor     r1, r3, r2              /* xor .. */
134         tst     r3, #BYTE0              /* is this byte NUL? */
135         tstne   r1, #BYTE0              /*   no, does this byte match? */
136         tstne   r3, #BYTE1              /*   no, is this byte NUL? */
137         tstne   r1, #BYTE1              /*   no, does this byte match? */
138         tstne   r3, #BYTE2              /*   no, is this byte NUL? */
139         tstne   r1, #BYTE2              /*   no, does this byte match? */
140         tstne   r3, #BYTE3              /*   no, is this byte NUL? */
141         tstne   r1, #BYTE3              /*   no, does this byte match? */
142         bne     .Lmain_loop
144         sub     r2, r0, #4              /* un post-inc */
145         mov     r0, #0                  /* assume no match */
147         tst     r1, #BYTE0              /* does this byte match? */
148         moveq   r0, r2                  /*   yes, point to it */
149         RETc(eq)                        /*        and return */
150         tst     r3, #BYTE0              /* is this byte NUL? */
151         RETc(eq)                        /*   yes, return NULL */
153         tst     r1, #BYTE1              /* does this byte match? */
154         addeq   r0, r2, #1              /*   yes, point to it */
155         RETc(eq)                        /*        and return */
156         tst     r3, #BYTE1              /* is this byte NUL? */
157         RETc(eq)                        /*   yes, return NULL */
159         tst     r1, #BYTE2              /* does this byte match? */
160         addeq   r0, r2, #2              /*   yes, point to it */
161         RETc(eq)                        /*        and return */
162         tst     r3, #BYTE2              /* is this byte NUL? */
163         RETc(eq)                        /*   yes, return NULL */
165         tst     r1, #BYTE3              /* does this byte match? */
166         addeq   r0, r2, #3              /*   yes, point to it */
167         /*
168          * Since no NULs and no matches this must be the only case left.
169          */
170         RET                             /* return */
171 #endif /* _ARM_ARCH_6 */
172 END(strchr)