GNU Linux-libre 4.19.264-gnu1
[releases.git] / arch / arm64 / lib / memmove.S
1 /*
2  * Copyright (C) 2013 ARM Ltd.
3  * Copyright (C) 2013 Linaro.
4  *
5  * This code is based on glibc cortex strings work originally authored by Linaro
6  * and re-licensed under GPLv2 for the Linux kernel. The original code can
7  * be found @
8  *
9  * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
10  * files/head:/src/aarch64/
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include <linux/linkage.h>
26 #include <asm/assembler.h>
27 #include <asm/cache.h>
28
29 /*
30  * Move a buffer from src to test (alignment handled by the hardware).
31  * If dest <= src, call memcpy, otherwise copy in reverse order.
32  *
33  * Parameters:
34  *      x0 - dest
35  *      x1 - src
36  *      x2 - n
37  * Returns:
38  *      x0 - dest
39  */
40 dstin   .req    x0
41 src     .req    x1
42 count   .req    x2
43 tmp1    .req    x3
44 tmp1w   .req    w3
45 tmp2    .req    x4
46 tmp2w   .req    w4
47 tmp3    .req    x5
48 tmp3w   .req    w5
49 dst     .req    x6
50
51 A_l     .req    x7
52 A_h     .req    x8
53 B_l     .req    x9
54 B_h     .req    x10
55 C_l     .req    x11
56 C_h     .req    x12
57 D_l     .req    x13
58 D_h     .req    x14
59
60 ENTRY(__memmove)
61 WEAK(memmove)
62         cmp     dstin, src
63         b.lo    __memcpy
64         add     tmp1, src, count
65         cmp     dstin, tmp1
66         b.hs    __memcpy                /* No overlap.  */
67
68         add     dst, dstin, count
69         add     src, src, count
70         cmp     count, #16
71         b.lo    .Ltail15  /*probably non-alignment accesses.*/
72
73         ands    tmp2, src, #15     /* Bytes to reach alignment.  */
74         b.eq    .LSrcAligned
75         sub     count, count, tmp2
76         /*
77         * process the aligned offset length to make the src aligned firstly.
78         * those extra instructions' cost is acceptable. It also make the
79         * coming accesses are based on aligned address.
80         */
81         tbz     tmp2, #0, 1f
82         ldrb    tmp1w, [src, #-1]!
83         strb    tmp1w, [dst, #-1]!
84 1:
85         tbz     tmp2, #1, 2f
86         ldrh    tmp1w, [src, #-2]!
87         strh    tmp1w, [dst, #-2]!
88 2:
89         tbz     tmp2, #2, 3f
90         ldr     tmp1w, [src, #-4]!
91         str     tmp1w, [dst, #-4]!
92 3:
93         tbz     tmp2, #3, .LSrcAligned
94         ldr     tmp1, [src, #-8]!
95         str     tmp1, [dst, #-8]!
96
97 .LSrcAligned:
98         cmp     count, #64
99         b.ge    .Lcpy_over64
100
101         /*
102         * Deal with small copies quickly by dropping straight into the
103         * exit block.
104         */
105 .Ltail63:
106         /*
107         * Copy up to 48 bytes of data. At this point we only need the
108         * bottom 6 bits of count to be accurate.
109         */
110         ands    tmp1, count, #0x30
111         b.eq    .Ltail15
112         cmp     tmp1w, #0x20
113         b.eq    1f
114         b.lt    2f
115         ldp     A_l, A_h, [src, #-16]!
116         stp     A_l, A_h, [dst, #-16]!
117 1:
118         ldp     A_l, A_h, [src, #-16]!
119         stp     A_l, A_h, [dst, #-16]!
120 2:
121         ldp     A_l, A_h, [src, #-16]!
122         stp     A_l, A_h, [dst, #-16]!
123
124 .Ltail15:
125         tbz     count, #3, 1f
126         ldr     tmp1, [src, #-8]!
127         str     tmp1, [dst, #-8]!
128 1:
129         tbz     count, #2, 2f
130         ldr     tmp1w, [src, #-4]!
131         str     tmp1w, [dst, #-4]!
132 2:
133         tbz     count, #1, 3f
134         ldrh    tmp1w, [src, #-2]!
135         strh    tmp1w, [dst, #-2]!
136 3:
137         tbz     count, #0, .Lexitfunc
138         ldrb    tmp1w, [src, #-1]
139         strb    tmp1w, [dst, #-1]
140
141 .Lexitfunc:
142         ret
143
144 .Lcpy_over64:
145         subs    count, count, #128
146         b.ge    .Lcpy_body_large
147         /*
148         * Less than 128 bytes to copy, so handle 64 bytes here and then jump
149         * to the tail.
150         */
151         ldp     A_l, A_h, [src, #-16]
152         stp     A_l, A_h, [dst, #-16]
153         ldp     B_l, B_h, [src, #-32]
154         ldp     C_l, C_h, [src, #-48]
155         stp     B_l, B_h, [dst, #-32]
156         stp     C_l, C_h, [dst, #-48]
157         ldp     D_l, D_h, [src, #-64]!
158         stp     D_l, D_h, [dst, #-64]!
159
160         tst     count, #0x3f
161         b.ne    .Ltail63
162         ret
163
164         /*
165         * Critical loop. Start at a new cache line boundary. Assuming
166         * 64 bytes per line this ensures the entire loop is in one line.
167         */
168         .p2align        L1_CACHE_SHIFT
169 .Lcpy_body_large:
170         /* pre-load 64 bytes data. */
171         ldp     A_l, A_h, [src, #-16]
172         ldp     B_l, B_h, [src, #-32]
173         ldp     C_l, C_h, [src, #-48]
174         ldp     D_l, D_h, [src, #-64]!
175 1:
176         /*
177         * interlace the load of next 64 bytes data block with store of the last
178         * loaded 64 bytes data.
179         */
180         stp     A_l, A_h, [dst, #-16]
181         ldp     A_l, A_h, [src, #-16]
182         stp     B_l, B_h, [dst, #-32]
183         ldp     B_l, B_h, [src, #-32]
184         stp     C_l, C_h, [dst, #-48]
185         ldp     C_l, C_h, [src, #-48]
186         stp     D_l, D_h, [dst, #-64]!
187         ldp     D_l, D_h, [src, #-64]!
188         subs    count, count, #64
189         b.ge    1b
190         stp     A_l, A_h, [dst, #-16]
191         stp     B_l, B_h, [dst, #-32]
192         stp     C_l, C_h, [dst, #-48]
193         stp     D_l, D_h, [dst, #-64]!
194
195         tst     count, #0x3f
196         b.ne    .Ltail63
197         ret
198 ENDPIPROC(memmove)
199 ENDPROC(__memmove)