Update copyright notices with scripts/update-copyrights
[glibc.git] / sysdeps / powerpc / powerpc32 / power7 / memrchr.S
blobebfd540883cee85d94a01f7e390946776f2bc92c
1 /* Optimized memrchr implementation for PowerPC32/POWER7 using cmpb insn.
2    Copyright (C) 2010-2014 Free Software Foundation, Inc.
3    Contributed by Luis Machado <luisgpm@br.ibm.com>.
4    This file is part of the GNU C Library.
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.
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.
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/>.  */
20 #include <sysdep.h>
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.  */
34         /* Replicate BYTE to word.  */
35         rldimi  r4,r4,8,48
36         rldimi  r4,r4,16,32
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)
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)
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)
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)
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.  */
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.  */
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)
108         /* We may have one more word to read.  */
109         cmplw   r8,r0
110         bnelr
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
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)
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.  */
133         mr      r3,r9
134         addi    r8,r8,-4
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
153         .align  4
154 L(null):
155         li      r3,0
156         blr
158 /* Deals with size <= 16.  */
159         .align  4
160 L(small_range):
161         cmplwi  r5,0
162         beq     L(null)
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)
174         /* Are we done already?  */
175         cmplw   r8,r0
176         addi    r8,r8,-4
177         beqlr
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
194 END (__memrchr)
195 weak_alias (__memrchr, memrchr)
196 libc_hidden_builtin_def (memrchr)