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/>. */
21 /* See strlen.s for comments on how this works. */
23 /* char * [r3] strchr (const char *s [r3] , int c [r4] ) */
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 */
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 */
44 insrdi rCHR, rCHR, 8, 48
46 insrdi rCHR, rCHR, 16, 32
47 rlwinm rIGN, rRTN, 3, 26, 28
48 insrdi rCHR, rCHR, 32, 0
52 addi rFEFE, rFEFE, -0x101
53 addi r7F7F, r7F7F, 0x7f7f
55 insrdi r7F7F, r7F7F, 32, 0
56 add rFEFE, rFEFE, rTMP1
57 /* Test the first (partial?) word. */
59 #ifdef __LITTLE_ENDIAN__
60 sld rMASK, rMASK, rIGN
62 srd rMASK, rMASK, rIGN
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
76 and. rTMP5, rTMP1, rTMP2
78 add rTMP1, rFEFE, rWORD /* x - 0x01010101. */
79 nor rTMP2, r7F7F, rWORD /* ~(x | 0x7f7f7f7f) == ~x & 0x80808080. */
81 and. rTMP4, rTMP1, rTMP2 /* (x - 0x01010101) & ~x & 0x80808080. */
82 /* Start test for the bytes we're looking for. */
83 xor rTMP3, rCHR, rWORD
85 add rTMP1, rFEFE, rTMP3
86 nor rTMP2, r7F7F, rTMP3
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
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
105 addi rTMP2, rTMP4, -1
106 andc rTMP2, rTMP2, rTMP4
109 subfic rCLZB, rCLZB, 64-7
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
127 add rRTN, rSTR, rCLZB
131 #ifdef __LITTLE_ENDIAN__
132 addi rTMP1, rTMP5, -1
133 andc rTMP1, rTMP1, rTMP5
135 subfic rCLZB, rCLZB, 64-7-64
136 sradi rCLZB, rCLZB, 3
138 and rTMP1, r7F7F, rTMP3
139 or rTMP4, r7F7F, rTMP3
140 add rTMP1, rTMP1, r7F7F
141 nor rTMP2, rTMP4, rTMP1
146 add rRTN, rSTR, rCLZB
150 weak_alias (strchr, index)
151 libc_hidden_builtin_def (strchr)