neon for memset; higher minimums to enter loops
[glibc.git] / sysdeps / aarch64 / memset.S
blob2e15551006457e011eebe8aefca1e7d3609f360a
1 /* Copyright (C) 2012-2014 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/>.  */
19 /* Assumptions:
20  *
21  * ARMv8-a, AArch64
22  * Unaligned accesses
23  */
25 #include <sysdep.h>
27 #define dstin           x0
28 #define dstin_w         w0
29 #define valw            w1
30 #define count           x2
31 #define tmp1            x3
32 #define tmp1w           w3
33 #define tmp2            x4
34 #define tmp2w           w4
35 #define zva_len_x       x5
36 #define zva_len         w5
37 #define zva_mask_x      x6
38 #define zva_mask        w6
39 #define dst             x8
40 #define dst_w           w8
41 #define dstend          x9
43         .globl  memset
44         cfi_startproc
46 #if HAVE_IFUNC && !defined (IS_IN_rtld)
47 /* Rather than decode dczid_el0 every time, checking for zva disabled and
48    unpacking the line size, do this once in the indirect function and choose
49    an appropriate entry point which encodes these values as constants.  */
51         .type   memset, %gnu_indirect_function
52 memset:
53         mrs     x1, dczid_el0
54         adrp    x0, 1f
55         tst     x1, #16                         /* test for zva disabled */
56         and     x1, x1, #15
57         add     x0, x0, #:lo12:1f
58         csel    x1, xzr, x1, ne                 /* squash index to 0 if so */
59         ldrsw   x2, [x0, x1, lsl #2]
60         add     x0, x0, x2
61         RET
62         .size   memset, .-memset
64         .section .rodata
65 1:      .long   memset_nozva - 1b               // 0
66         .long   memset_nozva - 1b               // 1
67         .long   memset_nozva - 1b               // 2
68         .long   memset_nozva - 1b               // 3
69         .long   memset_zva_64 - 1b              // 4
70         .long   memset_zva_128 - 1b             // 5
71         .long   memset_zva_256 - 1b             // 6
72         .long   memset_zva_512 - 1b             // 7
73         .long   memset_zva_1024 - 1b    // 8
74         .long   memset_zva_2048 - 1b    // 9
75         .long   memset_zva_4096 - 1b    // 10
76         .long   memset_zva_8192 - 1b    // 11
77         .long   memset_zva_16384 - 1b   // 12
78         .long   memset_zva_32768 - 1b   // 13
79         .long   memset_zva_65536 - 1b   // 14
80         .long   memset_zva_131072 - 1b  // 15
81         .previous
83 /* The 64 byte zva size is too small, and needs unrolling for efficiency.  */
85         .p2align 6
86         .type   memset_zva_64, %function
87 memset_zva_64:
88         CALL_MCOUNT
89         tst     valw, #255
90         b.ne    L(nz_or_small)
92         cmp     count, #256
93         dup     v16.16b, valw
94         add     dstend, dstin, count
95         b.lo    L(le_255)
97         str     q16, [dstin]            /* first 16 aligned 1.  */
98         and     tmp2, dstin, #-16
99         and     dst, dstin, #-64
101         stp     q16, q16, [tmp2, #16]   /* first 64 aligned 16.  */
102         add     dst, dst, #64
104         stp     q16, q16, [tmp2, #48]
105         sub     count, dstend, dst      /* recompute for misalign */
106         add     tmp1, dst, #64
108         sub     count, count, #128      /* pre-bias */
110         .p2align 6,,24
111 0:      dc      zva, dst
112         subs    count, count, #128
113         dc      zva, tmp1
114         add     dst, dst, #128
115         add     tmp1, tmp1, #128
116         b.hs    0b
118         adds    count, count, #128      /* undo pre-bias */
119         b.ne    L(zva_tail)
120         RET
122         .size   memset_zva_64, . - memset_zva_64
124 /* For larger zva sizes, a simple loop ought to suffice.  */
125 /* ??? Needs performance testing, when such hardware becomes available.  */
127 .macro do_zvas len
128         .p2align 4
129         .type   memset_zva_\len, %function
130 memset_zva_\len:
131         CALL_MCOUNT
132         tst     valw, #255
133         b.ne    L(nz_or_small)
135         cmp     count, #256
136         dup     v16.16b, valw
137         add     dstend, dstin, count
138         b.lo    L(le_255)
140         mov     zva_len, #\len
141         b       memset_zva_n
143         .size   memset_zva_\len, . - memset_zva_\len
144 .endm
146 .macro do_zval len
147         .p2align 4
148         .type   memset_zva_\len, %function
149 memset_zva_\len:
150         CALL_MCOUNT
151         and     valw, valw, #255
152         cmp     count, #\len
153         ccmp    valw, #0, #0, hs        /* hs ? cmp val,0 : !z */
154         b.ne    L(nz_or_small)
156         add     dstend, dstin, count
157         mov     zva_len, #\len
158         b       memset_zva_n
160         .size   memset_zva_\len, . - memset_zva_\len
161 .endm
163         do_zvas 128     // 5
164         do_zvas 256     // 6
165         do_zval 512     // 7
166         do_zval 1024    // 8
167         do_zval 2048    // 9
168         do_zval 4096    // 10
169         do_zval 8192    // 11
170         do_zval 16384   // 12
171         do_zval 32768   // 13
172         do_zval 65536   // 14
173         do_zval 131072  // 15
175         .p2align 6
176 #else
177 /* Without IFUNC, we must load the zva data from the dczid register.  */
179         .p2align 6
180         .type   memset, %function
181 memset:
182         tst     valw, #255
183         b.ne    L(nz_or_small)
185         cmp     count, #256
186         dup     v16.16b, valw
187         add     dstend, dstin, count
188         b.lo    L(le_255)
190         mrs     tmp1, dczid_el0
191         mov     zva_len, #4
193         tst     tmp1w, #16              /* dc disabled? */
194         and     tmp1w, tmp1w, #15
196         ccmp    tmp1w, #4, #0, eq       /* eq ? cmp len,64 : !c */
197         lsl     zva_len, zva_len, tmp1w
199         ccmp    count, zva_len_x, #0, hs /* hs ? cmp count,len : !c */
201         b.lo    L(ge_256)               /* disabled || len<64 || count<len */
203         /* Fall through into memset_zva_n.  */
204         .size   memset, . - memset
205 #endif /* HAVE_IFUNC */
207 /* Main part of the zva path.  On arrival here, we've already checked for
208    minimum size and that VAL is zero.  Also, we've set up zva_len and mask. */
210         .type   memset_zva_n, %function
211 memset_zva_n:
212         stp     q16, q16, [dstin]       /* first 32 aligned 1.  */
213         neg     tmp1w, dstin_w
214         sub     zva_mask, zva_len, #1
215         sub     count, count, zva_len_x /* pre-bias */
216         mov     dst, dstin
217         ands    tmp1w, tmp1w, zva_mask
218         b.ne    3f
220         .p2align 6,,16
221 2:      dc      zva, dst
222         subs    count, count, zva_len_x
223         add     dst, dst, zva_len_x
224         b.hs    2b
226         adds    count, count, zva_len_x /* undo pre-bias */
227         b.ne    L(zva_tail)
228         RET
230         .p2align 4
231 3:      and     tmp2, dstin, #-32
232         sub     count, count, tmp1      /* account for misalign */
233         add     dst, dstin, tmp1
235         .p2align 6,,24
236 4:      stp     q16, q16, [tmp2, #32]
237         subs    tmp1w, tmp1w, #64
238         stp     q16, q16, [tmp2, #64]!
239         b.hi    4b
241         b       2b
243         .size   memset_zva_n, . - memset_zva_n
245 /* The non-zva path.  */
247         .p2align 6
248         .type   memset_nozva, %function
249 memset_nozva:
250         CALL_MCOUNT
251 L(nz_or_small):
252         dup     v16.16b, valw
253         cmp     count, #256
254         add     dstend, dstin, count
255         b.hs    L(ge_256)
257         /* Small data -- original count is less than 256 bytes.  */
258 L(le_255):
259         cmp     count, #32
260         b.lo    L(le_31)
262         stp     q16, q16, [dstin]
263         cmp     count, #64
264         b.lo    L(le_63)
266         stp     q16, q16, [dstin, #0x20]
267         tbz     count, #7, L(le_127)
269         stp     q16, q16, [dstin, #0x40]
270         stp     q16, q16, [dstin, #0x60]
271         stp     q16, q16, [dstend, #-0x80]
272         stp     q16, q16, [dstend, #-0x60]
273 L(le_127):
274         stp     q16, q16, [dstend, #-0x40]
275 L(le_63):
276         stp     q16, q16, [dstend, #-0x20]
277         RET
279         .p2align 6,,16
280 L(ge_256):
281         and     dst, dstin, #-32        /* align the pointer / pre-bias.  */
282         stp     q16, q16, [dstin]       /* first 32 align 1 */
283         sub     count, dstend, dst      /* begin misalign recompute */
284         sub     count, count, #32+128   /* finish recompute + pre-bias */
286         .p2align 6,,24
287 L(loop):
288         stp     q16, q16, [dst, #0x20]
289         stp     q16, q16, [dst, #0x40]
290         subs    count, count, #128
291         stp     q16, q16, [dst, #0x60]
292         stp     q16, q16, [dst, #0x80]!
293         b.hs    L(loop)
295         adds    count, count, #128      /* undo pre-bias */
296         b.ne    L(loop_tail)
297         RET
299         /* Tail of the zva loop.  Less than ZVA bytes, but possibly lots
300            more than 128.  Note that dst is aligned but unbiased.  */
301 L(zva_tail):
302         subs    count, count, #128      /* pre-bias */
303         sub     dst, dst, #32           /* pre-bias */
304         b.hi    L(loop)
306         /* Tail of the stp loop; less than 128 bytes left.
307            Note that dst is still aligned and biased by -32.  */
308 L(loop_tail):
309         stp     q16, q16, [dstend, #-0x80]
310         stp     q16, q16, [dstend, #-0x60]
311         stp     q16, q16, [dstend, #-0x40]
312         stp     q16, q16, [dstend, #-0x20]
313         RET
315 L(le_31):
316         tbz     count, #4, L(le_15)
317         str     q16, [dstin]
318         str     q16, [dstend, #-0x10]
319         RET
320 L(le_15):
321         tbz     count, #3, L(le_7)
322         str     d16, [dstin]
323         str     d16, [dstend, #-8]
324         RET
325 L(le_7):
326         tbz     count, #2, L(le_3)
327         str     s16, [dstin]
328         str     s16, [dstend, #-4]
329         RET
330 L(le_3):
331         tbz     count, #1, L(le_1)
332         str     h16, [dstend, #-2]
333 L(le_1):
334         tbz     count, #0, L(le_0)
335         str     b16, [dstin]
336 L(le_0):
337         RET
339         .size   memset_nozva, . - memset_nozva
340         cfi_endproc
342 strong_alias (memset, __memset)
343 libc_hidden_builtin_def (memset)