]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/powerpc/powerpc32/power7/memrchr.S
2eb6fb5f4d7f232dcec0f324e33b6bb76e88a141
[thirdparty/glibc.git] / sysdeps / powerpc / powerpc32 / power7 / memrchr.S
1 /* Optimized memrchr implementation for PowerPC32/POWER7 using cmpb insn.
2 Copyright (C) 2010-2019 Free Software Foundation, Inc.
3 Contributed by Luis Machado <luisgpm@br.ibm.com>.
4 This file is part of the GNU C Library.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
19
20 #include <sysdep.h>
21
22 /* int [r3] memrchr (char *s [r3], int byte [r4], int size [r5]) */
23 .machine power7
24 ENTRY (__memrchr)
25 CALL_MCOUNT
26 add r7,r3,r5 /* Calculate the last acceptable address. */
27 neg r0,r7
28 addi r7,r7,-1
29 mr r10,r3
30 clrrwi r6,r7,7
31 li r9,3<<5
32 dcbt r9,r6,16 /* Stream hint, decreasing addresses. */
33
34 /* Replicate BYTE to word. */
35 insrwi r4,r4,8,16
36 insrwi r4,r4,16,0
37 li r6,-4
38 li r9,-1
39 rlwinm r0,r0,3,27,28 /* Calculate padding. */
40 clrrwi r8,r7,2
41 srw r9,r9,r0
42 cmplwi r5,16
43 clrrwi r0,r10,2
44 ble L(small_range)
45
46 #ifdef __LITTLE_ENDIAN__
47 lwzx r12,0,r8
48 #else
49 lwbrx r12,0,r8 /* Load reversed word from memory. */
50 #endif
51 cmpb r3,r12,r4 /* Check for BYTE in WORD1. */
52 and r3,r3,r9
53 cmplwi cr7,r3,0 /* If r3 == 0, no BYTEs have been found. */
54 bne cr7,L(done)
55
56 mtcrf 0x01,r8
57 /* Are we now aligned to a doubleword boundary? If so, skip to
58 the main loop. Otherwise, go through the alignment code. */
59 bf 29,L(loop_setup)
60
61 /* Handle WORD2 of pair. */
62 #ifdef __LITTLE_ENDIAN__
63 lwzx r12,r8,r6
64 #else
65 lwbrx r12,r8,r6
66 #endif
67 addi r8,r8,-4
68 cmpb r3,r12,r4
69 cmplwi cr7,r3,0
70 bne cr7,L(done)
71
72 L(loop_setup):
73 /* The last word we want to read in the loop below is the one
74 containing the first byte of the string, ie. the word at
75 s & ~3, or r0. The first word read is at r8 - 4, we
76 read 2 * cnt words, so the last word read will be at
77 r8 - 4 - 8 * cnt + 4. Solving for cnt gives
78 cnt = (r8 - r0) / 8 */
79 sub r5,r8,r0
80 addi r8,r8,-4
81 srwi r9,r5,3 /* Number of loop iterations. */
82 mtctr r9 /* Setup the counter. */
83
84 /* Main loop to look for BYTE backwards in the string.
85 FIXME: Investigate whether 32 byte align helps with this
86 9 instruction loop. */
87 .align 5
88 L(loop):
89 /* Load two words, compare and merge in a
90 single register for speed. This is an attempt
91 to speed up the byte-checking process for bigger strings. */
92
93 #ifdef __LITTLE_ENDIAN__
94 lwzx r12,0,r8
95 lwzx r11,r8,r6
96 #else
97 lwbrx r12,0,r8
98 lwbrx r11,r8,r6
99 #endif
100 cmpb r3,r12,r4
101 cmpb r9,r11,r4
102 or r5,r9,r3 /* Merge everything in one word. */
103 cmplwi cr7,r5,0
104 bne cr7,L(found)
105 addi r8,r8,-8
106 bdnz L(loop)
107
108 /* We may have one more word to read. */
109 cmplw r8,r0
110 bnelr
111
112 #ifdef __LITTLE_ENDIAN__
113 lwzx r12,0,r8
114 #else
115 lwbrx r12,0,r8
116 #endif
117 cmpb r3,r12,r4
118 cmplwi cr7,r3,0
119 bne cr7,L(done)
120 blr
121
122 .align 4
123 L(found):
124 /* OK, one (or both) of the words contains BYTE. Check
125 the first word. */
126 cmplwi cr6,r3,0
127 bne cr6,L(done)
128
129 /* BYTE must be in the second word. Adjust the address
130 again and move the result of cmpb to r3 so we can calculate the
131 pointer. */
132
133 mr r3,r9
134 addi r8,r8,-4
135
136 /* r3 has the output of the cmpb instruction, that is, it contains
137 0xff in the same position as BYTE in the original
138 word from the string. Use that to calculate the pointer.
139 We need to make sure BYTE is *before* the end of the
140 range. */
141 L(done):
142 cntlzw r9,r3 /* Count leading zeros before the match. */
143 cmplw r8,r0 /* Are we on the last word? */
144 srwi r6,r9,3 /* Convert leading zeros to bytes. */
145 addi r0,r6,-3
146 sub r3,r8,r0
147 cmplw cr7,r3,r10
148 bnelr
149 bgelr cr7
150 li r3,0
151 blr
152
153 .align 4
154 L(null):
155 li r3,0
156 blr
157
158 /* Deals with size <= 16. */
159 .align 4
160 L(small_range):
161 cmplwi r5,0
162 beq L(null)
163
164 #ifdef __LITTLE_ENDIAN__
165 lwzx r12,0,r8
166 #else
167 lwbrx r12,0,r8 /* Load reversed word from memory. */
168 #endif
169 cmpb r3,r12,r4 /* Check for BYTE in WORD1. */
170 and r3,r3,r9
171 cmplwi cr7,r3,0
172 bne cr7,L(done)
173
174 /* Are we done already? */
175 cmplw r8,r0
176 addi r8,r8,-4
177 beqlr
178
179 .align 5
180 L(loop_small):
181 #ifdef __LITTLE_ENDIAN__
182 lwzx r12,0,r8
183 #else
184 lwbrx r12,0,r8
185 #endif
186 cmpb r3,r12,r4
187 cmplw r8,r0
188 cmplwi cr7,r3,0
189 bne cr7,L(done)
190 addi r8,r8,-4
191 bne L(loop_small)
192 blr
193
194 END (__memrchr)
195 weak_alias (__memrchr, memrchr)
196 libc_hidden_builtin_def (memrchr)