]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/powerpc/powerpc32/strchr.S
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / powerpc / powerpc32 / strchr.S
CommitLineData
9a0a462c 1/* Optimized strchr implementation for PowerPC.
2b778ceb 2 Copyright (C) 1997-2021 Free Software Foundation, Inc.
9a0a462c
UD
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
41bdb6e2
AJ
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.
9a0a462c
UD
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
41bdb6e2 13 Lesser General Public License for more details.
9a0a462c 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
9a0a462c
UD
18
19#include <sysdep.h>
20
21/* See strlen.s for comments on how this works. */
22
1d280d9f 23/* char * [r3] strchr (const char *s [r3] , int c [r4] ) */
9a0a462c 24
b5510883 25ENTRY (strchr)
1d280d9f
GM
26
27#define rTMP1 r0
28#define rRTN r3 /* outgoing result */
b5510883
JM
29#define rSTR r8 /* current word pointer */
30#define rCHR r4 /* byte we're looking for, spread over the whole word */
31#define rWORD r5 /* the current word */
1d280d9f 32#define rCLZB rCHR /* leading zero byte count */
1d280d9f
GM
33#define rFEFE r6 /* constant 0xfefefeff (-0x01010101) */
34#define r7F7F r7 /* constant 0x7f7f7f7f */
1d280d9f
GM
35#define rTMP2 r9
36#define rIGN r10 /* number of bits we should ignore in the first word */
37#define rMASK r11 /* mask with the bits to ignore set to 0 */
38#define rTMP3 r12
664318c3
AM
39#define rTMP4 rIGN
40#define rTMP5 rMASK
1d280d9f 41
b1fc7a6a 42
1d280d9f
GM
43 rlwimi rCHR, rCHR, 8, 16, 23
44 li rMASK, -1
45 rlwimi rCHR, rCHR, 16, 0, 15
dfef32ef 46 rlwinm rIGN, rRTN, 3, 27, 28
1d280d9f
GM
47 lis rFEFE, -0x101
48 lis r7F7F, 0x7f7f
dfef32ef 49 clrrwi rSTR, rRTN, 2
1d280d9f 50 addi rFEFE, rFEFE, -0x101
b1fc7a6a 51 addi r7F7F, r7F7F, 0x7f7f
9a0a462c 52/* Test the first (partial?) word. */
1d280d9f 53 lwz rWORD, 0(rSTR)
664318c3
AM
54#ifdef __LITTLE_ENDIAN__
55 slw rMASK, rMASK, rIGN
56#else
1d280d9f 57 srw rMASK, rMASK, rIGN
664318c3 58#endif
1d280d9f
GM
59 orc rWORD, rWORD, rMASK
60 add rTMP1, rFEFE, rWORD
61 nor rTMP2, r7F7F, rWORD
664318c3 62 and. rTMP4, rTMP1, rTMP2
1d280d9f
GM
63 xor rTMP3, rCHR, rWORD
64 orc rTMP3, rTMP3, rMASK
65 b L(loopentry)
9a0a462c
UD
66
67/* The loop. */
68
664318c3
AM
69L(loop):
70 lwzu rWORD, 4(rSTR)
71 and. rTMP5, rTMP1, rTMP2
1d280d9f 72/* Test for 0. */
664318c3
AM
73 add rTMP1, rFEFE, rWORD /* x - 0x01010101. */
74 nor rTMP2, r7F7F, rWORD /* ~(x | 0x7f7f7f7f) == ~x & 0x80808080. */
1d280d9f 75 bne L(foundit)
664318c3 76 and. rTMP4, rTMP1, rTMP2 /* (x - 0x01010101) & ~x & 0x80808080. */
9a0a462c 77/* Start test for the bytes we're looking for. */
1d280d9f 78 xor rTMP3, rCHR, rWORD
9a0a462c 79L(loopentry):
1d280d9f
GM
80 add rTMP1, rFEFE, rTMP3
81 nor rTMP2, r7F7F, rTMP3
82 beq L(loop)
664318c3 83
9a0a462c
UD
84/* There is a zero byte in the word, but may also be a matching byte (either
85 before or after the zero byte). In fact, we may be looking for a
664318c3
AM
86 zero byte, in which case we return a match. */
87 and. rTMP5, rTMP1, rTMP2
dfef32ef 88 li rRTN, 0
9a0a462c 89 beqlr
664318c3
AM
90/* At this point:
91 rTMP5 bytes are 0x80 for each match of c, 0 otherwise.
92 rTMP4 bytes are 0x80 for each match of 0, 0 otherwise.
93 But there may be false matches in the next most significant byte from
94 a true match due to carries. This means we need to recalculate the
95 matches using a longer method for big-endian. */
96#ifdef __LITTLE_ENDIAN__
97 addi rTMP1, rTMP5, -1
98 andc rTMP1, rTMP1, rTMP5
99 cntlzw rCLZB, rTMP1
100 addi rTMP2, rTMP4, -1
101 andc rTMP2, rTMP2, rTMP4
102 cmplw rTMP1, rTMP2
103 bgtlr
104 subfic rCLZB, rCLZB, 32-7
105#else
106/* I think we could reduce this by two instructions by keeping the "nor"
107 results from the loop for reuse here. See strlen.S tail. Similarly
108 one instruction could be pruned from L(foundit). */
1d280d9f 109 and rFEFE, r7F7F, rWORD
664318c3 110 or rTMP5, r7F7F, rWORD
1d280d9f 111 and rTMP1, r7F7F, rTMP3
664318c3 112 or rTMP4, r7F7F, rTMP3
1d280d9f
GM
113 add rFEFE, rFEFE, r7F7F
114 add rTMP1, rTMP1, r7F7F
664318c3
AM
115 nor rWORD, rTMP5, rFEFE
116 nor rTMP2, rTMP4, rTMP1
117 cntlzw rCLZB, rTMP2
1d280d9f 118 cmplw rWORD, rTMP2
9a0a462c 119 bgtlr
664318c3 120#endif
1d280d9f 121 srwi rCLZB, rCLZB, 3
dfef32ef 122 add rRTN, rSTR, rCLZB
9a0a462c
UD
123 blr
124
125L(foundit):
664318c3
AM
126#ifdef __LITTLE_ENDIAN__
127 addi rTMP1, rTMP5, -1
128 andc rTMP1, rTMP1, rTMP5
129 cntlzw rCLZB, rTMP1
130 subfic rCLZB, rCLZB, 32-7-32
131 srawi rCLZB, rCLZB, 3
132#else
1d280d9f 133 and rTMP1, r7F7F, rTMP3
664318c3 134 or rTMP4, r7F7F, rTMP3
1d280d9f 135 add rTMP1, rTMP1, r7F7F
664318c3 136 nor rTMP2, rTMP4, rTMP1
1d280d9f
GM
137 cntlzw rCLZB, rTMP2
138 subi rSTR, rSTR, 4
139 srwi rCLZB, rCLZB, 3
664318c3 140#endif
dfef32ef 141 add rRTN, rSTR, rCLZB
9a0a462c 142 blr
b5510883 143END (strchr)
9a0a462c 144
b5510883 145weak_alias (strchr, index)
85dd1003 146libc_hidden_builtin_def (strchr)