powerpc: Improve strcmp performance for shorter strings
[glibc.git] / sysdeps / powerpc / powerpc64 / power9 / strcmp.S
blob17ec8c24c3e7969dca4108216282d856628809cf
1 /* Optimized strcmp implementation for PowerPC64/POWER9.
2    Copyright (C) 2016-2017 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/>.  */
18 #ifdef __LITTLE_ENDIAN__
19 #include <sysdep.h>
21 /* Implements the function
23    int [r3] strcmp (const char *s1 [r3], const char *s2 [r4])
25    The implementation uses unaligned doubleword access for first 32 bytes
26    as in POWER8 patch and uses vectorised loops after that.  */
28 /* TODO: Change this to actual instructions when minimum binutils is upgraded
29    to 2.27. Macros are defined below for these newer instructions in order
30    to maintain compatibility.  */
31 # define VCTZLSBB(r,v) .long (0x10010602 | ((r)<<(32-11)) | ((v)<<(32-21)))
33 # define VEXTUBRX(t,a,b) .long (0x1000070d \
34                                 | ((t)<<(32-11))  \
35                                 | ((a)<<(32-16))  \
36                                 | ((b)<<(32-21)) )
38 # define VCMPNEZB(t,a,b) .long (0x10000507 \
39                                 | ((t)<<(32-11))  \
40                                 | ((a)<<(32-16))  \
41                                 | ((b)<<(32-21)) )
43 /* Get 16 bytes for unaligned case.
44    reg1: Vector to hold next 16 bytes.
45    reg2: Address to read from.
46    reg3: Permute control vector.  */
47 # define GET16BYTES(reg1, reg2, reg3) \
48         lvx     reg1, 0, reg2; \
49         vperm   v8, v2, reg1, reg3; \
50         vcmpequb.       v8, v0, v8; \
51         beq     cr6, 1f; \
52         vspltisb        v9, 0; \
53         b       2f; \
54         .align 4; \
55 1: \
56         addi    r6, reg2, 16; \
57         lvx     v9, 0, r6; \
58 2: \
59         vperm   reg1, v9, reg1, reg3;
61 /* TODO: change this to .machine power9 when the minimum required binutils
62    allows it.  */
64         .machine  power7
65 EALIGN (strcmp, 4, 0)
66         li      r0, 0
68         /* Check if [s1]+16 or [s2]+16 will cross a 4K page boundary using
69            the code:
71             (((size_t) s1) % PAGE_SIZE > (PAGE_SIZE - ITER_SIZE))
73            with PAGE_SIZE being 4096 and ITER_SIZE begin 16.  */
75         rldicl  r7, r3, 0, 52
76         rldicl  r9, r4, 0, 52
77         cmpldi  cr7, r7, 4096-16
78         bgt     cr7, L(pagecross_check)
79         cmpldi  cr5, r9, 4096-16
80         bgt     cr5, L(pagecross_check)
82         /* For short strings up to 16 bytes,  load both s1 and s2 using
83            unaligned dwords and compare.  */
84         ld      r8, 0(r3)
85         ld      r10, 0(r4)
86         cmpb    r12, r8, r0
87         cmpb    r11, r8, r10
88         orc.    r9, r12, r11
89         bne     cr0, L(different_nocmpb)
91         ld      r8, 8(r3)
92         ld      r10, 8(r4)
93         cmpb    r12, r8, r0
94         cmpb    r11, r8, r10
95         orc.    r9, r12, r11
96         bne     cr0, L(different_nocmpb)
98         addi    r7, r3, 16
99         addi    r4, r4, 16
101 L(align):
102         /* Now it has checked for first 16 bytes.  */
103         vspltisb        v0, 0
104         vspltisb        v2, -1
105         lvsr    v6, 0, r4   /* Compute mask.  */
106         or      r5, r4, r7
107         andi.   r5, r5, 0xF
108         beq     cr0, L(aligned)
109         andi.   r5, r7, 0xF
110         beq     cr0, L(s1_align)
111         lvsr    v10, 0, r7   /* Compute mask.  */
113         /* Both s1 and s2 are unaligned.  */
114         GET16BYTES(v4, r7, v10)
115         GET16BYTES(v5, r4, v6)
116         VCMPNEZB(v7, v5, v4)
117         beq     cr6, L(match)
118         b       L(different)
120         /* Align s1 to qw and adjust s2 address.  */
121         .align  4
122 L(match):
123         clrldi  r6, r7, 60
124         subfic  r5, r6, 16
125         add     r7, r7, r5
126         add     r4, r4, r5
127         andi.   r5, r4, 0xF
128         beq     cr0, L(aligned)
129         lvsr    v6, 0, r4
130         /* There are 2 loops depending on the input alignment.
131            Each loop gets 16 bytes from s1 and s2 and compares.
132            Loop until a mismatch or null occurs.  */
133 L(s1_align):
134         lvx     v4, r7, r0
135         GET16BYTES(v5, r4, v6)
136         VCMPNEZB(v7, v5, v4)
137         addi    r7, r7, 16
138         addi    r4, r4, 16
139         bne     cr6, L(different)
141         lvx     v4, r7, r0
142         GET16BYTES(v5, r4, v6)
143         VCMPNEZB(v7, v5, v4)
144         addi    r7, r7, 16
145         addi    r4, r4, 16
146         bne     cr6, L(different)
148         lvx     v4, r7, r0
149         GET16BYTES(v5, r4, v6)
150         VCMPNEZB(v7, v5, v4)
151         addi    r7, r7, 16
152         addi    r4, r4, 16
153         bne     cr6, L(different)
155         lvx     v4, r7, r0
156         GET16BYTES(v5, r4, v6)
157         VCMPNEZB(v7, v5, v4)
158         addi    r7, r7, 16
159         addi    r4, r4, 16
160         beq     cr6, L(s1_align)
161         b       L(different)
163         .align  4
164 L(aligned):
165         lvx     v4, 0, r7
166         lvx     v5, 0, r4
167         VCMPNEZB(v7, v5, v4)
168         addi    r7, r7, 16
169         addi    r4, r4, 16
170         bne     cr6, L(different)
172         lvx     v4, 0, r7
173         lvx     v5, 0, r4
174         VCMPNEZB(v7, v5, v4)
175         addi    r7, r7, 16
176         addi    r4, r4, 16
177         bne     cr6, L(different)
179         lvx     v4, 0, r7
180         lvx     v5, 0, r4
181         VCMPNEZB(v7, v5, v4)
182         addi    r7, r7, 16
183         addi    r4, r4, 16
184         bne     cr6, L(different)
186         lvx     v4, 0, r7
187         lvx     v5, 0, r4
188         VCMPNEZB(v7, v5, v4)
189         addi    r7, r7, 16
190         addi    r4, r4, 16
191         beq     cr6, L(aligned)
193         /* Calculate and return the difference.  */
194 L(different):
195         VCTZLSBB(r6, v7)
196         VEXTUBRX(r5, r6, v4)
197         VEXTUBRX(r4, r6, v5)
198         subf    r3, r4, r5
199         extsw   r3, r3
200         blr
202         .align  4
203 L(different_nocmpb):
204         neg     r3, r9
205         and     r9, r9, r3
206         cntlzd  r9, r9
207         subfic  r9, r9, 63
208         srd     r3, r8, r9
209         srd     r10, r10, r9
210         rldicl  r10, r10, 0, 56
211         rldicl  r3, r3, 0, 56
212         subf    r3, r10, r3
213         extsw   r3, r3
214         blr
216         .align  4
217 L(pagecross_check):
218         subfic  r9, r9, 4096
219         subfic  r7, r7, 4096
220         cmpld   cr7, r7, r9
221         bge     cr7, L(pagecross)
222         mr      r7, r9
224         /* If unaligned 16 bytes reads across a 4K page boundary, it uses
225            a simple byte a byte comparison until the page alignment for s1
226            is reached.  */
227 L(pagecross):
228         add     r7, r3, r7
229         subf    r9, r3, r7
230         mtctr   r9
232         .align  4
233 L(pagecross_loop):
234         /* Loads a byte from s1 and s2, compare if *s1 is equal to *s2
235            and if *s1 is '\0'.  */
236         lbz     r9, 0(r3)
237         lbz     r10, 0(r4)
238         addi    r3, r3, 1
239         addi    r4, r4, 1
240         cmplw   cr7, r9, r10
241         cmpdi   cr5, r9, r0
242         bne     cr7, L(pagecross_ne)
243         beq     cr5, L(pagecross_nullfound)
244         bdnz    L(pagecross_loop)
245         b       L(align)
247         .align  4
248 L(pagecross_ne):
249         extsw   r3, r9
250         mr      r9, r10
251 L(pagecross_retdiff):
252         subf    r9, r9, r3
253         extsw   r3, r9
254         blr
256         .align  4
257 L(pagecross_nullfound):
258         li      r3, 0
259         b       L(pagecross_retdiff)
260 END (strcmp)
261 libc_hidden_builtin_def (strcmp)
262 #else
263 #include <sysdeps/powerpc/powerpc64/power8/strcmp.S>
264 #endif