[4/5] AArch64: Improve A64FX memset by removing unroll32
[glibc.git] / sysdeps / aarch64 / multiarch / memset_a64fx.S
blobef0315658a676a8692c3f18cc9f914bd6e145991
1 /* Optimized memset for Fujitsu A64FX processor.
2    Copyright (C) 2021 Free Software Foundation, Inc.
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    <https://www.gnu.org/licenses/>.  */
20 #include <sysdep.h>
21 #include <sysdeps/aarch64/memset-reg.h>
23 /* Assumptions:
24  *
25  * ARMv8.2-a, AArch64, unaligned accesses, sve
26  *
27  */
29 #define L1_SIZE         (64*1024)       // L1 64KB
30 #define L2_SIZE         (8*1024*1024)   // L2 8MB
31 #define CACHE_LINE_SIZE 256
32 #define PF_DIST_L1      (CACHE_LINE_SIZE * 16)  // Prefetch distance L1
33 #define rest            x2
34 #define vector_length   x9
36 #if HAVE_AARCH64_SVE_ASM
37 # if IS_IN (libc)
38 #  define MEMSET __memset_a64fx
40         .arch armv8.2-a+sve
42         .macro st1b_unroll first=0, last=7
43         st1b    z0.b, p0, [dst, \first, mul vl]
44         .if \last-\first
45         st1b_unroll "(\first+1)", \last
46         .endif
47         .endm
50 #undef BTI_C
51 #define BTI_C
53 ENTRY (MEMSET)
54         PTR_ARG (0)
55         SIZE_ARG (2)
57         cntb    vector_length
58         dup     z0.b, valw
59         whilelo p0.b, vector_length, count
60         b.last  1f
61         whilelo p1.b, xzr, count
62         st1b    z0.b, p1, [dstin, 0, mul vl]
63         st1b    z0.b, p0, [dstin, 1, mul vl]
64         ret
66         // count >= vector_length * 2
67 1:      cmp     count, vector_length, lsl 2
68         add     dstend, dstin, count
69         b.hi    1f
70         st1b    z0.b, p0, [dstin, 0, mul vl]
71         st1b    z0.b, p0, [dstin, 1, mul vl]
72         st1b    z0.b, p0, [dstend, -2, mul vl]
73         st1b    z0.b, p0, [dstend, -1, mul vl]
74         ret
76         // count > vector_length * 4
77 1:      lsl     tmp1, vector_length, 3
78         cmp     count, tmp1
79         b.hi    L(vl_agnostic)
80         st1b    z0.b, p0, [dstin, 0, mul vl]
81         st1b    z0.b, p0, [dstin, 1, mul vl]
82         st1b    z0.b, p0, [dstin, 2, mul vl]
83         st1b    z0.b, p0, [dstin, 3, mul vl]
84         st1b    z0.b, p0, [dstend, -4, mul vl]
85         st1b    z0.b, p0, [dstend, -3, mul vl]
86         st1b    z0.b, p0, [dstend, -2, mul vl]
87         st1b    z0.b, p0, [dstend, -1, mul vl]
88         ret
90         .p2align 4
91 L(vl_agnostic): // VL Agnostic
92         mov     rest, count
93         mov     dst, dstin
94         add     dstend, dstin, count
95         // if rest >= L2_SIZE && vector_length == 64 then L(L2)
96         mov     tmp1, 64
97         cmp     rest, L2_SIZE
98         ccmp    vector_length, tmp1, 0, cs
99         b.eq    L(L2)
100         // if rest >= L1_SIZE && vector_length == 64 then L(L1_prefetch)
101         cmp     rest, L1_SIZE
102         ccmp    vector_length, tmp1, 0, cs
103         b.eq    L(L1_prefetch)
106 L(unroll8):
107         lsl     tmp1, vector_length, 3
108         .p2align 3
109 1:      cmp     rest, tmp1
110         b.cc    L(last)
111         st1b_unroll
112         add     dst, dst, tmp1
113         sub     rest, rest, tmp1
114         b       1b
116 L(last):
117         cmp     count, vector_length, lsl 1
118         b.ls    2f
119         add     tmp2, vector_length, vector_length, lsl 2
120         cmp     count, tmp2
121         b.ls    5f
122         st1b    z0.b, p0, [dstend, -8, mul vl]
123         st1b    z0.b, p0, [dstend, -7, mul vl]
124         st1b    z0.b, p0, [dstend, -6, mul vl]
125 5:      st1b    z0.b, p0, [dstend, -5, mul vl]
126         st1b    z0.b, p0, [dstend, -4, mul vl]
127         st1b    z0.b, p0, [dstend, -3, mul vl]
128 2:      st1b    z0.b, p0, [dstend, -2, mul vl]
129         st1b    z0.b, p0, [dstend, -1, mul vl]
130         ret
132 L(L1_prefetch): // if rest >= L1_SIZE
133         .p2align 3
134 1:      st1b_unroll 0, 3
135         prfm    pstl1keep, [dst, PF_DIST_L1]
136         st1b_unroll 4, 7
137         prfm    pstl1keep, [dst, PF_DIST_L1 + CACHE_LINE_SIZE]
138         add     dst, dst, CACHE_LINE_SIZE * 2
139         sub     rest, rest, CACHE_LINE_SIZE * 2
140         cmp     rest, L1_SIZE
141         b.ge    1b
142         cbnz    rest, L(unroll8)
143         ret
145         // count >= L2_SIZE
146         .p2align 3
147 L(L2):
148         tst     valw, 255
149         b.ne    L(unroll8)
150         // align dst to CACHE_LINE_SIZE byte boundary
151         and     tmp2, dst, CACHE_LINE_SIZE - 1
152         st1b    z0.b, p0, [dst, 0, mul vl]
153         st1b    z0.b, p0, [dst, 1, mul vl]
154         st1b    z0.b, p0, [dst, 2, mul vl]
155         st1b    z0.b, p0, [dst, 3, mul vl]
156         sub     dst, dst, tmp2
157         add     count, count, tmp2
159         // clear cachelines using DC ZVA
160         sub     count, count, CACHE_LINE_SIZE * 2
161         .p2align 4
162 1:      add     dst, dst, CACHE_LINE_SIZE
163         dc      zva, dst
164         subs    count, count, CACHE_LINE_SIZE
165         b.hi    1b
166         add     count, count, CACHE_LINE_SIZE
167         b       L(last)
169 END (MEMSET)
170 libc_hidden_builtin_def (MEMSET)
172 #endif /* IS_IN (libc) */
173 #endif /* HAVE_AARCH64_SVE_ASM */