[aarch64] Add an ASIMD variant of strlen for falkor
[glibc.git] / sysdeps / powerpc / powerpc64 / power9 / strncmp.S
blob40be98ff45c9f48586a89e5c1b6b38c8d06f8270
1 /* Optimized strncmp implementation for PowerPC64/POWER9.
2    Copyright (C) 2016-2018 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] strncmp (const char *s1 [r3], const char *s2 [r4], size_t [r5] n)
25    The implementation uses unaligned doubleword access to avoid specialized
26    code paths depending of data alignment for first 32 bytes and uses
27    vectorised loops after that.  */
29 #ifndef STRNCMP
30 # define STRNCMP strncmp
31 #endif
33 /* TODO: Change this to actual instructions when minimum binutils is upgraded
34    to 2.27. Macros are defined below for these newer instructions in order
35    to maintain compatibility.  */
36 # define VCTZLSBB(r,v) .long (0x10010602 | ((r)<<(32-11)) | ((v)<<(32-21)))
38 # define VEXTUBRX(t,a,b) .long (0x1000070d \
39                                 | ((t)<<(32-11))  \
40                                 | ((a)<<(32-16))  \
41                                 | ((b)<<(32-21)) )
43 # define VCMPNEZB(t,a,b) .long (0x10000507 \
44                                 | ((t)<<(32-11))  \
45                                 | ((a)<<(32-16))  \
46                                 | ((b)<<(32-21)) )
48 /* Get 16 bytes for unaligned case.
49    reg1: Vector to hold next 16 bytes.
50    reg2: Address to read from.
51    reg3: Permute control vector.  */
52 # define GET16BYTES(reg1, reg2, reg3) \
53         lvx     reg1, 0, reg2; \
54         vperm   v8, v2, reg1, reg3; \
55         vcmpequb.       v8, v0, v8; \
56         beq     cr6, 1f; \
57         vspltisb        v9, 0; \
58         b       2f; \
59         .align 4; \
60 1: \
61         cmplw   cr6, r5, r11; \
62         ble     cr6, 2f; \
63         addi    r6, reg2, 16; \
64         lvx     v9, 0, r6; \
65 2: \
66         vperm   reg1, v9, reg1, reg3;
68 /* TODO: change this to .machine power9 when minimum binutils
69    is upgraded to 2.27.  */
70         .machine  power7
71 ENTRY_TOCLESS (STRNCMP, 4)
72         /* Check if size is 0.  */
73         cmpdi   cr0, r5, 0
74         beq     cr0, L(ret0)
75         li      r0, 0
77         /* Check if [s1]+32 or [s2]+32 will cross a 4K page boundary using
78            the code:
80             (((size_t) s1) % PAGE_SIZE > (PAGE_SIZE - ITER_SIZE))
82            with PAGE_SIZE being 4096 and ITER_SIZE begin 32.  */
83         rldicl  r8, r3, 0, 52
84         cmpldi  cr7, r8, 4096-32
85         bgt     cr7, L(pagecross)
86         rldicl  r9, r4, 0, 52
87         cmpldi  cr7, r9, 4096-32
88         bgt     cr7, L(pagecross)
90         /* For short strings up to 32 bytes, load both s1 and s2 using
91            unaligned dwords and compare.  */
93         ld      r7, 0(r3)
94         ld      r9, 0(r4)
95         li      r8, 0
96         cmpb    r8, r7, r8
97         cmpb    r6, r7, r9
98         orc.    r8, r8, r6
99         bne     cr0, L(different1)
101         /* If the strings compared are equal, but size is less or equal
102            to 8, return 0.  */
103         cmpldi  cr7, r5, 8
104         li      r9, 0
105         ble     cr7, L(ret1)
106         addi    r5, r5, -8
108         ld      r7, 8(r3)
109         ld      r9, 8(r4)
110         cmpb    r8, r7, r8
111         cmpb    r6, r7, r9
112         orc.    r8, r8, r6
113         bne     cr0, L(different1)
114         cmpldi  cr7, r5, 8
115         mr      r9, r8
116         ble     cr7, L(ret1)
117         /* Update pointers and size.  */
118         addi    r5, r5, -8
119         addi    r3, r3, 16
120         addi    r4, r4, 16
122         ld      r7, 0(r3)
123         ld      r9, 0(r4)
124         li      r8, 0
125         cmpb    r8, r7, r8
126         cmpb    r6, r7, r9
127         orc.    r8, r8, r6
128         bne     cr0, L(different1)
129         cmpldi  cr7, r5, 8
130         li      r9, 0
131         ble     cr7, L(ret1)
132         addi    r5, r5, -8
134         ld      r7, 8(r3)
135         ld      r9, 8(r4)
136         cmpb    r8, r7, r8
137         cmpb    r6, r7, r9
138         orc.    r8, r8, r6
139         bne     cr0, L(different1)
140         cmpldi  cr7, r5, 8
141         mr      r9, r8
142         ble     cr7, L(ret1)
144         /* Update pointers and size.  */
145         addi    r5, r5, -8
146         addi    r3, r3, 16
147         addi    r4, r4, 16
148 L(align):
149         /* Now it has checked for first 32 bytes, align source1 to doubleword
150            and adjust source2 address.  */
151         vspltisb        v0, 0
152         vspltisb        v2, -1
153         or      r6, r4, r3
154         andi.   r6, r6, 0xF
155         beq     cr0, L(aligned)
156         lvsr    v6, 0, r4   /* Compute mask.  */
157         clrldi  r6, r4, 60
158         subfic  r11, r6, 16
159         andi.   r6, r3, 0xF
160         beq     cr0, L(s1_align)
161         /* Both s1 and s2 are unaligned.  */
162         GET16BYTES(v5, r4, v6)
163         lvsr    v10, 0, r3   /* Compute mask.  */
164         clrldi  r6, r3, 60
165         subfic  r11, r6, 16
166         GET16BYTES(v4, r3, v10)
167         VCMPNEZB(v7, v5, v4)
168         beq     cr6, L(match)
169         b       L(different)
171         /* Align s1 to qw and adjust s2 address.  */
172         .align  4
173 L(match):
174         cmpldi  cr7, r5, 16
175         ble     cr7, L(ret0)
176         subf    r5, r11, r5
177         add     r3, r3, r11
178         add     r4, r4, r11
179         andi.   r11, r4, 0xF
180         beq     cr0, L(aligned)
181         lvsr    v6, 0, r4
182         clrldi  r6, r4, 60
183         subfic  r11, r6, 16
184         /* There are 2 loops depending on the input alignment.
185            Each loop gets 16 bytes from s1 and s2, checks for null
186            and compares them. Loops until a mismatch or  null occurs.  */
187 L(s1_align):
188         lvx     v4, 0, r3
189         GET16BYTES(v5, r4, v6)
190         VCMPNEZB(v7, v5, v4)
191         bne     cr6, L(different)
192         cmpldi  cr7, r5, 16
193         ble     cr7, L(ret0)
194         addi    r5, r5, -16
195         addi    r3, r3, 16
196         addi    r4, r4, 16
198         lvx     v4, 0, r3
199         GET16BYTES(v5, r4, v6)
200         VCMPNEZB(v7, v5, v4)
201         bne     cr6, L(different)
202         cmpldi  cr7, r5, 16
203         ble     cr7, L(ret0)
204         addi    r5, r5, -16
205         addi    r3, r3, 16
206         addi    r4, r4, 16
208         lvx     v4, 0, r3
209         GET16BYTES(v5, r4, v6)
210         VCMPNEZB(v7, v5, v4)
211         bne     cr6, L(different)
212         cmpldi  cr7, r5, 16
213         ble     cr7, L(ret0)
214         addi    r5, r5, -16
215         addi    r3, r3, 16
216         addi    r4, r4, 16
218         lvx     v4, 0, r3
219         GET16BYTES(v5, r4, v6)
220         VCMPNEZB(v7, v5, v4)
221         bne     cr6, L(different)
222         cmpldi  cr7, r5, 16
223         ble     cr7, L(ret0)
224         addi    r5, r5, -16
225         addi    r3, r3, 16
226         addi    r4, r4, 16
227         b       L(s1_align)
228         .align  4
229 L(aligned):
230         lvx     v4, 0, r3
231         lvx     v5, 0, r4
232         VCMPNEZB(v7, v5, v4)
233         bne     cr6, L(different)
234         cmpldi  cr7, r5, 16
235         ble     cr7, L(ret0)
236         addi    r5, r5, -16
237         addi    r3, r3, 16
238         addi    r4, r4, 16
240         lvx     v4, 0, r3
241         lvx     v5, 0, r4
242         VCMPNEZB(v7, v5, v4)
243         bne     cr6, L(different)
244         cmpldi  cr7, r5, 16
245         ble     cr7, L(ret0)
246         addi    r5, r5, -16
247         addi    r3, r3, 16
248         addi    r4, r4, 16
250         lvx     v4, 0, r3
251         lvx     v5, 0, r4
252         VCMPNEZB(v7, v5, v4)
253         bne     cr6, L(different)
254         cmpldi  cr7, r5, 16
255         ble     cr7, L(ret0)
256         addi    r5, r5, -16
257         addi    r3, r3, 16
258         addi    r4, r4, 16
260         lvx     v4, 0, r3
261         lvx     v5, 0, r4
262         VCMPNEZB(v7, v5, v4)
263         bne     cr6, L(different)
264         cmpldi  cr7, r5, 16
265         ble     cr7, L(ret0)
266         addi    r5, r5, -16
267         addi    r3, r3, 16
268         addi    r4, r4, 16
269         b       L(aligned)
270         /* Calculate and return the difference.  */
271 L(different):
272         VCTZLSBB(r6, v7)
273         cmplw   cr7, r5, r6
274         ble     cr7, L(ret0)
275         VEXTUBRX(r5, r6, v4)
276         VEXTUBRX(r4, r6, v5)
277         subf    r3, r4, r5
278         extsw   r3, r3
279         blr
281         .align 4
282 L(ret0):
283         li      r9, 0
284 L(ret1):
285         mr      r3, r9
286         blr
288         /* The code now checks if r8 and r5 are different by issuing a
289            cmpb and shifts the result based on its output:
291           leadzero = (__builtin_ffsl (z1) - 1);
292           leadzero = leadzero > (n-1)*8 ? (n-1)*8 : leadzero;
293           r1 = (r1 >> leadzero) & 0xFFUL;
294           r2 = (r2 >> leadzero) & 0xFFUL;
295           return r1 - r2;  */
297         .align 4
298 L(different1):
299         neg     r11, r8
300         sldi    r5, r5, 3
301         and     r8, r11, r8
302         addi    r5, r5, -8
303         cntlzd  r8, r8
304         subfic  r8, r8, 63
305         extsw   r8, r8
306         cmpld   cr7, r8, r5
307         ble     cr7, L(different2)
308         mr      r8, r5
309 L(different2):
310         extsw   r8, r8
311         srd     r7, r7, r8
312         srd     r9, r9, r8
313         rldicl  r3, r7, 0, 56
314         rldicl  r9, r9, 0, 56
315         subf    r9, r9, 3
316         extsw   r9, r9
317         mr      r3, r9
318         blr
320         /* If unaligned 16 bytes reads across a 4K page boundary, it uses
321            a simple byte a byte comparison until the page alignment for s1
322            is reached.  */
323         .align 4
324 L(pagecross):
325         lbz     r7, 0(r3)
326         lbz     r9, 0(r4)
327         subfic  r8, r8,4095
328         cmplw   cr7, r9, r7
329         bne     cr7, L(byte_ne_3)
330         cmpdi   cr7, r9, 0
331         beq     cr7, L(byte_ne_0)
332         addi    r5, r5, -1
333         subf    r7, r8, r5
334         subf    r9, r7, r5
335         addi    r9, r9, 1
336         mtctr   r9
337         b       L(pagecross_loop1)
339         .align 4
340 L(pagecross_loop0):
341         beq     cr7, L(ret0)
342         lbz     r9, 0(r3)
343         lbz     r8, 0(r4)
344         addi    r5, r5, -1
345         cmplw   cr7, r9, r8
346         cmpdi   cr5, r9, 0
347         bne     cr7, L(byte_ne_2)
348         beq     cr5, L(byte_ne_0)
349 L(pagecross_loop1):
350         cmpdi   cr7, r5, 0
351         addi    r3, r3, 1
352         addi    r4, r4, 1
353         bdnz    L(pagecross_loop0)
354         cmpdi   cr7, r7, 0
355         li      r9, 0
356         bne+    cr7, L(align)
357         b       L(ret1)
359         .align 4
360 L(byte_ne_0):
361         li      r7, 0
362 L(byte_ne_1):
363         subf    r9, r9, r7
364         extsw   r9, r9
365         b       L(ret1)
367         .align 4
368 L(byte_ne_2):
369         extsw   r7, r9
370         mr      r9, r8
371         b       L(byte_ne_1)
372 L(byte_ne_3):
373         extsw   r7, r7
374         b       L(byte_ne_1)
375 END(STRNCMP)
376 libc_hidden_builtin_def(strncmp)
377 #else
378 #include <sysdeps/powerpc/powerpc64/power8/strncmp.S>
379 #endif