]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cortex-strings/src/aarch64/memcpy.S
MFV r328253: 8835 Speculative prefetch in ZFS not working for misaligned reads
[FreeBSD/FreeBSD.git] / contrib / cortex-strings / src / aarch64 / memcpy.S
1 /* Copyright (c) 2012, Linaro Limited
2    All rights reserved.
3
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions are met:
6        * Redistributions of source code must retain the above copyright
7          notice, this list of conditions and the following disclaimer.
8        * Redistributions in binary form must reproduce the above copyright
9          notice, this list of conditions and the following disclaimer in the
10          documentation and/or other materials provided with the distribution.
11        * Neither the name of the Linaro nor the
12          names of its contributors may be used to endorse or promote products
13          derived from this software without specific prior written permission.
14
15    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
26
27 /*
28  * Copyright (c) 2015 ARM Ltd
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. The name of the company may not be used to endorse or promote
40  *    products derived from this software without specific prior written
41  *    permission.
42  *
43  * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
44  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
45  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46  * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
48  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
49  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
50  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
51  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
52  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54
55 /* Assumptions:
56  *
57  * ARMv8-a, AArch64, unaligned accesses.
58  *
59  */
60
61 #define dstin   x0
62 #define src     x1
63 #define count   x2
64 #define dst     x3
65 #define srcend  x4
66 #define dstend  x5
67 #define A_l     x6
68 #define A_lw    w6
69 #define A_h     x7
70 #define A_hw    w7
71 #define B_l     x8
72 #define B_lw    w8
73 #define B_h     x9
74 #define C_l     x10
75 #define C_h     x11
76 #define D_l     x12
77 #define D_h     x13
78 #define E_l     src
79 #define E_h     count
80 #define F_l     dst
81 #define F_h     srcend
82 #define tmp1    x9
83
84 #define L(l) .L ## l
85
86         .macro def_fn f p2align=0
87         .text
88         .p2align \p2align
89         .global \f
90         .type \f, %function
91 \f:
92         .endm
93
94 /* Copies are split into 3 main cases: small copies of up to 16 bytes,
95    medium copies of 17..96 bytes which are fully unrolled. Large copies
96    of more than 96 bytes align the destination and use an unrolled loop
97    processing 64 bytes per iteration.
98    Small and medium copies read all data before writing, allowing any
99    kind of overlap, and memmove tailcalls memcpy for these cases as
100    well as non-overlapping copies.
101 */
102
103 def_fn memcpy p2align=6
104         prfm    PLDL1KEEP, [src]
105         add     srcend, src, count
106         add     dstend, dstin, count
107         cmp     count, 16
108         b.ls    L(copy16)
109         cmp     count, 96
110         b.hi    L(copy_long)
111
112         /* Medium copies: 17..96 bytes.  */
113         sub     tmp1, count, 1
114         ldp     A_l, A_h, [src]
115         tbnz    tmp1, 6, L(copy96)
116         ldp     D_l, D_h, [srcend, -16]
117         tbz     tmp1, 5, 1f
118         ldp     B_l, B_h, [src, 16]
119         ldp     C_l, C_h, [srcend, -32]
120         stp     B_l, B_h, [dstin, 16]
121         stp     C_l, C_h, [dstend, -32]
122 1:
123         stp     A_l, A_h, [dstin]
124         stp     D_l, D_h, [dstend, -16]
125         ret
126
127         .p2align 4
128         /* Small copies: 0..16 bytes.  */
129 L(copy16):
130         cmp     count, 8
131         b.lo    1f
132         ldr     A_l, [src]
133         ldr     A_h, [srcend, -8]
134         str     A_l, [dstin]
135         str     A_h, [dstend, -8]
136         ret
137         .p2align 4
138 1:
139         tbz     count, 2, 1f
140         ldr     A_lw, [src]
141         ldr     A_hw, [srcend, -4]
142         str     A_lw, [dstin]
143         str     A_hw, [dstend, -4]
144         ret
145
146         /* Copy 0..3 bytes.  Use a branchless sequence that copies the same
147            byte 3 times if count==1, or the 2nd byte twice if count==2.  */
148 1:
149         cbz     count, 2f
150         lsr     tmp1, count, 1
151         ldrb    A_lw, [src]
152         ldrb    A_hw, [srcend, -1]
153         ldrb    B_lw, [src, tmp1]
154         strb    A_lw, [dstin]
155         strb    B_lw, [dstin, tmp1]
156         strb    A_hw, [dstend, -1]
157 2:      ret
158
159         .p2align 4
160         /* Copy 64..96 bytes.  Copy 64 bytes from the start and
161            32 bytes from the end.  */
162 L(copy96):
163         ldp     B_l, B_h, [src, 16]
164         ldp     C_l, C_h, [src, 32]
165         ldp     D_l, D_h, [src, 48]
166         ldp     E_l, E_h, [srcend, -32]
167         ldp     F_l, F_h, [srcend, -16]
168         stp     A_l, A_h, [dstin]
169         stp     B_l, B_h, [dstin, 16]
170         stp     C_l, C_h, [dstin, 32]
171         stp     D_l, D_h, [dstin, 48]
172         stp     E_l, E_h, [dstend, -32]
173         stp     F_l, F_h, [dstend, -16]
174         ret
175
176         /* Align DST to 16 byte alignment so that we don't cross cache line
177            boundaries on both loads and stores.  There are at least 96 bytes
178            to copy, so copy 16 bytes unaligned and then align.  The loop
179            copies 64 bytes per iteration and prefetches one iteration ahead.  */
180
181         .p2align 4
182 L(copy_long):
183         and     tmp1, dstin, 15
184         bic     dst, dstin, 15
185         ldp     D_l, D_h, [src]
186         sub     src, src, tmp1
187         add     count, count, tmp1      /* Count is now 16 too large.  */
188         ldp     A_l, A_h, [src, 16]
189         stp     D_l, D_h, [dstin]
190         ldp     B_l, B_h, [src, 32]
191         ldp     C_l, C_h, [src, 48]
192         ldp     D_l, D_h, [src, 64]!
193         subs    count, count, 128 + 16  /* Test and readjust count.  */
194         b.ls    2f
195 1:
196         stp     A_l, A_h, [dst, 16]
197         ldp     A_l, A_h, [src, 16]
198         stp     B_l, B_h, [dst, 32]
199         ldp     B_l, B_h, [src, 32]
200         stp     C_l, C_h, [dst, 48]
201         ldp     C_l, C_h, [src, 48]
202         stp     D_l, D_h, [dst, 64]!
203         ldp     D_l, D_h, [src, 64]!
204         subs    count, count, 64
205         b.hi    1b
206
207         /* Write the last full set of 64 bytes.  The remainder is at most 64
208            bytes, so it is safe to always copy 64 bytes from the end even if
209            there is just 1 byte left.  */
210 2:
211         ldp     E_l, E_h, [srcend, -64]
212         stp     A_l, A_h, [dst, 16]
213         ldp     A_l, A_h, [srcend, -48]
214         stp     B_l, B_h, [dst, 32]
215         ldp     B_l, B_h, [srcend, -32]
216         stp     C_l, C_h, [dst, 48]
217         ldp     C_l, C_h, [srcend, -16]
218         stp     D_l, D_h, [dst, 64]
219         stp     E_l, E_h, [dstend, -64]
220         stp     A_l, A_h, [dstend, -48]
221         stp     B_l, B_h, [dstend, -32]
222         stp     C_l, C_h, [dstend, -16]
223         ret
224
225         .size   memcpy, . - memcpy