Update copyright notices with scripts/update-copyrights
[glibc.git] / sysdeps / powerpc / powerpc64 / strchr.S
blob3a16ee1c669b91d07cd0d69f4611a413c8dab181
1 /* Optimized strchr implementation for PowerPC64.
2    Copyright (C) 1997-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 /* See strlen.s for comments on how this works.  */
23 /* char * [r3] strchr (const char *s [r3] , int c [r4] )  */
25 ENTRY (strchr)
26         CALL_MCOUNT 2
28 #define rTMP1   r0
29 #define rRTN    r3      /* outgoing result */
30 #define rSTR    r8      /* current word pointer */
31 #define rCHR    r4      /* byte we're looking for, spread over the whole word */
32 #define rWORD   r5      /* the current word */
33 #define rCLZB   rCHR    /* leading zero byte count */
34 #define rFEFE   r6      /* constant 0xfefefefefefefeff (-0x0101010101010101) */
35 #define r7F7F   r7      /* constant 0x7f7f7f7f7f7f7f7f */
36 #define rTMP2   r9
37 #define rIGN    r10     /* number of bits we should ignore in the first word */
38 #define rMASK   r11     /* mask with the bits to ignore set to 0 */
39 #define rTMP3   r12
40 #define rTMP4   rIGN
41 #define rTMP5   rMASK
43         dcbt    0,rRTN
44         insrdi  rCHR, rCHR, 8, 48
45         li      rMASK, -1
46         insrdi  rCHR, rCHR, 16, 32
47         rlwinm  rIGN, rRTN, 3, 26, 28
48         insrdi  rCHR, rCHR, 32, 0
49         lis     rFEFE, -0x101
50         lis     r7F7F, 0x7f7f
51         clrrdi  rSTR, rRTN, 3
52         addi    rFEFE, rFEFE, -0x101
53         addi    r7F7F, r7F7F, 0x7f7f
54         sldi    rTMP1, rFEFE, 32
55         insrdi  r7F7F, r7F7F, 32, 0
56         add     rFEFE, rFEFE, rTMP1
57 /* Test the first (partial?) word.  */
58         ld      rWORD, 0(rSTR)
59 #ifdef __LITTLE_ENDIAN__
60         sld     rMASK, rMASK, rIGN
61 #else
62         srd     rMASK, rMASK, rIGN
63 #endif
64         orc     rWORD, rWORD, rMASK
65         add     rTMP1, rFEFE, rWORD
66         nor     rTMP2, r7F7F, rWORD
67         and.    rTMP4, rTMP1, rTMP2
68         xor     rTMP3, rCHR, rWORD
69         orc     rTMP3, rTMP3, rMASK
70         b       L(loopentry)
72 /* The loop.  */
74 L(loop):
75         ldu     rWORD, 8(rSTR)
76         and.    rTMP5, rTMP1, rTMP2
77 /* Test for 0.  */
78         add     rTMP1, rFEFE, rWORD /* x - 0x01010101.  */
79         nor     rTMP2, r7F7F, rWORD /* ~(x | 0x7f7f7f7f) == ~x & 0x80808080.  */
80         bne     L(foundit)
81         and.    rTMP4, rTMP1, rTMP2 /* (x - 0x01010101) & ~x & 0x80808080.  */
82 /* Start test for the bytes we're looking for.  */
83         xor     rTMP3, rCHR, rWORD
84 L(loopentry):
85         add     rTMP1, rFEFE, rTMP3
86         nor     rTMP2, r7F7F, rTMP3
87         beq     L(loop)
89 /* There is a zero byte in the word, but may also be a matching byte (either
90    before or after the zero byte).  In fact, we may be looking for a
91    zero byte, in which case we return a match.  */
92         and.    rTMP5, rTMP1, rTMP2
93         li      rRTN, 0
94         beqlr
95 /* At this point:
96    rTMP5 bytes are 0x80 for each match of c, 0 otherwise.
97    rTMP4 bytes are 0x80 for each match of 0, 0 otherwise.
98    But there may be false matches in the next most significant byte from
99    a true match due to carries.  This means we need to recalculate the
100    matches using a longer method for big-endian.  */
101 #ifdef __LITTLE_ENDIAN__
102         addi    rTMP1, rTMP5, -1
103         andc    rTMP1, rTMP1, rTMP5
104         cntlzd  rCLZB, rTMP1
105         addi    rTMP2, rTMP4, -1
106         andc    rTMP2, rTMP2, rTMP4
107         cmpld   rTMP1, rTMP2
108         bgtlr
109         subfic  rCLZB, rCLZB, 64-7
110 #else
111 /* I think we could reduce this by two instructions by keeping the "nor"
112    results from the loop for reuse here.  See strlen.S tail.  Similarly
113    one instruction could be pruned from L(foundit).  */
114         and     rFEFE, r7F7F, rWORD
115         or      rTMP5, r7F7F, rWORD
116         and     rTMP1, r7F7F, rTMP3
117         or      rTMP4, r7F7F, rTMP3
118         add     rFEFE, rFEFE, r7F7F
119         add     rTMP1, rTMP1, r7F7F
120         nor     rWORD, rTMP5, rFEFE
121         nor     rTMP2, rTMP4, rTMP1
122         cntlzd  rCLZB, rTMP2
123         cmpld   rWORD, rTMP2
124         bgtlr
125 #endif
126         srdi    rCLZB, rCLZB, 3
127         add     rRTN, rSTR, rCLZB
128         blr
130 L(foundit):
131 #ifdef __LITTLE_ENDIAN__
132         addi    rTMP1, rTMP5, -1
133         andc    rTMP1, rTMP1, rTMP5
134         cntlzd  rCLZB, rTMP1
135         subfic  rCLZB, rCLZB, 64-7-64
136         sradi   rCLZB, rCLZB, 3
137 #else
138         and     rTMP1, r7F7F, rTMP3
139         or      rTMP4, r7F7F, rTMP3
140         add     rTMP1, rTMP1, r7F7F
141         nor     rTMP2, rTMP4, rTMP1
142         cntlzd  rCLZB, rTMP2
143         subi    rSTR, rSTR, 8
144         srdi    rCLZB, rCLZB, 3
145 #endif
146         add     rRTN, rSTR, rCLZB
147         blr
148 END (strchr)
150 weak_alias (strchr, index)
151 libc_hidden_builtin_def (strchr)