Merge branch 'spectre' of git://git.armlinux.org.uk/~rmk/linux-arm
[linux-2.6-microblaze.git] / arch / sparc / lib / memcpy.S
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* memcpy.S: Sparc optimized memcpy and memmove code
3  * Hand optimized from GNU libc's memcpy and memmove
4  * Copyright (C) 1991,1996 Free Software Foundation
5  * Copyright (C) 1995 Linus Torvalds (Linus.Torvalds@helsinki.fi)
6  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
7  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
8  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
9  */
10
11 #include <asm/export.h>
12 #define FUNC(x)                 \
13         .globl  x;              \
14         .type   x,@function;    \
15         .align  4;              \
16 x:
17
18 /* Both these macros have to start with exactly the same insn */
19 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
20         ldd     [%src + (offset) + 0x00], %t0; \
21         ldd     [%src + (offset) + 0x08], %t2; \
22         ldd     [%src + (offset) + 0x10], %t4; \
23         ldd     [%src + (offset) + 0x18], %t6; \
24         st      %t0, [%dst + (offset) + 0x00]; \
25         st      %t1, [%dst + (offset) + 0x04]; \
26         st      %t2, [%dst + (offset) + 0x08]; \
27         st      %t3, [%dst + (offset) + 0x0c]; \
28         st      %t4, [%dst + (offset) + 0x10]; \
29         st      %t5, [%dst + (offset) + 0x14]; \
30         st      %t6, [%dst + (offset) + 0x18]; \
31         st      %t7, [%dst + (offset) + 0x1c];
32
33 #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
34         ldd     [%src + (offset) + 0x00], %t0; \
35         ldd     [%src + (offset) + 0x08], %t2; \
36         ldd     [%src + (offset) + 0x10], %t4; \
37         ldd     [%src + (offset) + 0x18], %t6; \
38         std     %t0, [%dst + (offset) + 0x00]; \
39         std     %t2, [%dst + (offset) + 0x08]; \
40         std     %t4, [%dst + (offset) + 0x10]; \
41         std     %t6, [%dst + (offset) + 0x18];
42
43 #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
44         ldd     [%src - (offset) - 0x10], %t0; \
45         ldd     [%src - (offset) - 0x08], %t2; \
46         st      %t0, [%dst - (offset) - 0x10]; \
47         st      %t1, [%dst - (offset) - 0x0c]; \
48         st      %t2, [%dst - (offset) - 0x08]; \
49         st      %t3, [%dst - (offset) - 0x04];
50
51 #define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1, t2, t3) \
52         ldd     [%src - (offset) - 0x10], %t0; \
53         ldd     [%src - (offset) - 0x08], %t2; \
54         std     %t0, [%dst - (offset) - 0x10]; \
55         std     %t2, [%dst - (offset) - 0x08];
56
57 #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
58         ldub    [%src - (offset) - 0x02], %t0; \
59         ldub    [%src - (offset) - 0x01], %t1; \
60         stb     %t0, [%dst - (offset) - 0x02]; \
61         stb     %t1, [%dst - (offset) - 0x01];
62
63         .text
64         .align  4
65
66 FUNC(memmove)
67 EXPORT_SYMBOL(memmove)
68         cmp             %o0, %o1
69         mov             %o0, %g7
70         bleu            9f
71          sub            %o0, %o1, %o4
72
73         add             %o1, %o2, %o3
74         cmp             %o3, %o0
75         bleu            0f
76          andcc          %o4, 3, %o5
77
78         add             %o1, %o2, %o1
79         add             %o0, %o2, %o0
80         sub             %o1, 1, %o1
81         sub             %o0, 1, %o0
82         
83 1:      /* reverse_bytes */
84
85         ldub            [%o1], %o4
86         subcc           %o2, 1, %o2
87         stb             %o4, [%o0]
88         sub             %o1, 1, %o1
89         bne             1b
90          sub            %o0, 1, %o0
91
92         retl
93          mov            %g7, %o0
94
95 /* NOTE: This code is executed just for the cases,
96          where %src (=%o1) & 3 is != 0.
97          We need to align it to 4. So, for (%src & 3)
98          1 we need to do ldub,lduh
99          2 lduh
100          3 just ldub
101          so even if it looks weird, the branches
102          are correct here. -jj
103  */
104 78:     /* dword_align */
105
106         andcc           %o1, 1, %g0
107         be              4f
108          andcc          %o1, 2, %g0
109
110         ldub            [%o1], %g2
111         add             %o1, 1, %o1
112         stb             %g2, [%o0]
113         sub             %o2, 1, %o2
114         bne             3f
115          add            %o0, 1, %o0
116 4:
117         lduh            [%o1], %g2
118         add             %o1, 2, %o1
119         sth             %g2, [%o0]
120         sub             %o2, 2, %o2
121         b               3f
122          add            %o0, 2, %o0
123
124 FUNC(memcpy)    /* %o0=dst %o1=src %o2=len */
125 EXPORT_SYMBOL(memcpy)
126
127         sub             %o0, %o1, %o4
128         mov             %o0, %g7
129 9:
130         andcc           %o4, 3, %o5
131 0:
132         bne             86f
133          cmp            %o2, 15
134
135         bleu            90f
136          andcc          %o1, 3, %g0
137
138         bne             78b
139 3:
140          andcc          %o1, 4, %g0
141
142         be              2f
143          mov            %o2, %g1
144
145         ld              [%o1], %o4
146         sub             %g1, 4, %g1
147         st              %o4, [%o0]
148         add             %o1, 4, %o1
149         add             %o0, 4, %o0
150 2:
151         andcc           %g1, 0xffffff80, %g0
152         be              3f
153          andcc          %o0, 4, %g0
154
155         be              82f + 4
156 5:
157         MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
158         MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
159         MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
160         MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
161         sub             %g1, 128, %g1
162         add             %o1, 128, %o1
163         cmp             %g1, 128
164         bge             5b
165          add            %o0, 128, %o0
166 3:
167         andcc           %g1, 0x70, %g4
168         be              80f
169          andcc          %g1, 8, %g0
170
171         sethi           %hi(80f), %o5
172         srl             %g4, 1, %o4
173         add             %g4, %o4, %o4
174         add             %o1, %g4, %o1
175         sub             %o5, %o4, %o5
176         jmpl            %o5 + %lo(80f), %g0
177          add            %o0, %g4, %o0
178
179 79:     /* memcpy_table */
180
181         MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
182         MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
183         MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
184         MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
185         MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
186         MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
187         MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
188
189 80:     /* memcpy_table_end */
190         be              81f
191          andcc          %g1, 4, %g0
192
193         ldd             [%o1], %g2
194         add             %o0, 8, %o0
195         st              %g2, [%o0 - 0x08]
196         add             %o1, 8, %o1
197         st              %g3, [%o0 - 0x04]
198
199 81:     /* memcpy_last7 */
200
201         be              1f
202          andcc          %g1, 2, %g0
203
204         ld              [%o1], %g2
205         add             %o1, 4, %o1
206         st              %g2, [%o0]
207         add             %o0, 4, %o0
208 1:
209         be              1f
210          andcc          %g1, 1, %g0
211
212         lduh            [%o1], %g2
213         add             %o1, 2, %o1
214         sth             %g2, [%o0]
215         add             %o0, 2, %o0
216 1:
217         be              1f
218          nop
219
220         ldub            [%o1], %g2
221         stb             %g2, [%o0]
222 1:
223         retl
224          mov            %g7, %o0
225
226 82:     /* ldd_std */
227         MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
228         MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
229         MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
230         MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
231         subcc           %g1, 128, %g1
232         add             %o1, 128, %o1
233         cmp             %g1, 128
234         bge             82b
235          add            %o0, 128, %o0
236
237         andcc           %g1, 0x70, %g4
238         be              84f
239          andcc          %g1, 8, %g0
240
241         sethi           %hi(84f), %o5
242         add             %o1, %g4, %o1
243         sub             %o5, %g4, %o5
244         jmpl            %o5 + %lo(84f), %g0
245          add            %o0, %g4, %o0
246
247 83:     /* amemcpy_table */
248
249         MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
250         MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
251         MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
252         MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
253         MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
254         MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
255         MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
256
257 84:     /* amemcpy_table_end */
258         be              85f
259          andcc          %g1, 4, %g0
260
261         ldd             [%o1], %g2
262         add             %o0, 8, %o0
263         std             %g2, [%o0 - 0x08]
264         add             %o1, 8, %o1
265 85:     /* amemcpy_last7 */
266         be              1f
267          andcc          %g1, 2, %g0
268
269         ld              [%o1], %g2
270         add             %o1, 4, %o1
271         st              %g2, [%o0]
272         add             %o0, 4, %o0
273 1:
274         be              1f
275          andcc          %g1, 1, %g0
276
277         lduh            [%o1], %g2
278         add             %o1, 2, %o1
279         sth             %g2, [%o0]
280         add             %o0, 2, %o0
281 1:
282         be              1f
283          nop
284
285         ldub            [%o1], %g2
286         stb             %g2, [%o0]
287 1:
288         retl
289          mov            %g7, %o0
290
291 86:     /* non_aligned */
292         cmp             %o2, 6
293         bleu            88f
294          nop
295
296         save            %sp, -96, %sp
297         andcc           %i0, 3, %g0
298         be              61f
299          andcc          %i0, 1, %g0
300         be              60f
301          andcc          %i0, 2, %g0
302
303         ldub            [%i1], %g5
304         add             %i1, 1, %i1
305         stb             %g5, [%i0]
306         sub             %i2, 1, %i2
307         bne             61f
308          add            %i0, 1, %i0
309 60:
310         ldub            [%i1], %g3
311         add             %i1, 2, %i1
312         stb             %g3, [%i0]
313         sub             %i2, 2, %i2
314         ldub            [%i1 - 1], %g3
315         add             %i0, 2, %i0
316         stb             %g3, [%i0 - 1]
317 61:
318         and             %i1, 3, %g2
319         and             %i2, 0xc, %g3
320         and             %i1, -4, %i1
321         cmp             %g3, 4
322         sll             %g2, 3, %g4
323         mov             32, %g2
324         be              4f
325          sub            %g2, %g4, %l0
326         
327         blu             3f
328          cmp            %g3, 0x8
329
330         be              2f
331          srl            %i2, 2, %g3
332
333         ld              [%i1], %i3
334         add             %i0, -8, %i0
335         ld              [%i1 + 4], %i4
336         b               8f
337          add            %g3, 1, %g3
338 2:
339         ld              [%i1], %i4
340         add             %i0, -12, %i0
341         ld              [%i1 + 4], %i5
342         add             %g3, 2, %g3
343         b               9f
344          add            %i1, -4, %i1
345 3:
346         ld              [%i1], %g1
347         add             %i0, -4, %i0
348         ld              [%i1 + 4], %i3
349         srl             %i2, 2, %g3
350         b               7f
351          add            %i1, 4, %i1
352 4:
353         ld              [%i1], %i5
354         cmp             %i2, 7
355         ld              [%i1 + 4], %g1
356         srl             %i2, 2, %g3
357         bleu            10f
358          add            %i1, 8, %i1
359
360         ld              [%i1], %i3
361         add             %g3, -1, %g3
362 5:
363         sll             %i5, %g4, %g2
364         srl             %g1, %l0, %g5
365         or              %g2, %g5, %g2
366         st              %g2, [%i0]
367 7:
368         ld              [%i1 + 4], %i4
369         sll             %g1, %g4, %g2
370         srl             %i3, %l0, %g5
371         or              %g2, %g5, %g2
372         st              %g2, [%i0 + 4]
373 8:
374         ld              [%i1 + 8], %i5
375         sll             %i3, %g4, %g2
376         srl             %i4, %l0, %g5
377         or              %g2, %g5, %g2
378         st              %g2, [%i0 + 8]
379 9:
380         ld              [%i1 + 12], %g1
381         sll             %i4, %g4, %g2
382         srl             %i5, %l0, %g5
383         addcc           %g3, -4, %g3
384         or              %g2, %g5, %g2
385         add             %i1, 16, %i1
386         st              %g2, [%i0 + 12]
387         add             %i0, 16, %i0
388         bne,a           5b
389          ld             [%i1], %i3
390 10:
391         sll             %i5, %g4, %g2
392         srl             %g1, %l0, %g5
393         srl             %l0, 3, %g3
394         or              %g2, %g5, %g2
395         sub             %i1, %g3, %i1
396         andcc           %i2, 2, %g0
397         st              %g2, [%i0]
398         be              1f
399          andcc          %i2, 1, %g0
400
401         ldub            [%i1], %g2
402         add             %i1, 2, %i1
403         stb             %g2, [%i0 + 4]
404         add             %i0, 2, %i0
405         ldub            [%i1 - 1], %g2
406         stb             %g2, [%i0 + 3]
407 1:
408         be              1f
409          nop
410         ldub            [%i1], %g2
411         stb             %g2, [%i0 + 4]
412 1:
413         ret
414          restore        %g7, %g0, %o0
415
416 88:     /* short_end */
417
418         and             %o2, 0xe, %o3
419 20:
420         sethi           %hi(89f), %o5
421         sll             %o3, 3, %o4
422         add             %o0, %o3, %o0
423         sub             %o5, %o4, %o5
424         add             %o1, %o3, %o1
425         jmpl            %o5 + %lo(89f), %g0
426          andcc          %o2, 1, %g0
427
428         MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
429         MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
430         MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
431         MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
432         MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
433         MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
434         MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
435
436 89:     /* short_table_end */
437
438         be              1f
439          nop
440
441         ldub            [%o1], %g2
442         stb             %g2, [%o0]
443 1:
444         retl
445          mov            %g7, %o0
446
447 90:     /* short_aligned_end */
448         bne             88b
449          andcc          %o2, 8, %g0
450
451         be              1f
452          andcc          %o2, 4, %g0
453
454         ld              [%o1 + 0x00], %g2
455         ld              [%o1 + 0x04], %g3
456         add             %o1, 8, %o1
457         st              %g2, [%o0 + 0x00]
458         st              %g3, [%o0 + 0x04]
459         add             %o0, 8, %o0
460 1:
461         b               81b
462          mov            %o2, %g1