Merge branch 'for-linus-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad...
[linux-2.6-microblaze.git] / arch / arc / lib / memcpy-archs.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
4  */
5
6 #include <linux/linkage.h>
7
8 #ifdef __LITTLE_ENDIAN__
9 # define SHIFT_1(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
10 # define SHIFT_2(RX,RY,IMM)     lsr     RX, RY, IMM     ; >>
11 # define MERGE_1(RX,RY,IMM)     asl     RX, RY, IMM
12 # define MERGE_2(RX,RY,IMM)
13 # define EXTRACT_1(RX,RY,IMM)   and     RX, RY, 0xFFFF
14 # define EXTRACT_2(RX,RY,IMM)   lsr     RX, RY, IMM
15 #else
16 # define SHIFT_1(RX,RY,IMM)     lsr     RX, RY, IMM     ; >>
17 # define SHIFT_2(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
18 # define MERGE_1(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
19 # define MERGE_2(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
20 # define EXTRACT_1(RX,RY,IMM)   lsr     RX, RY, IMM
21 # define EXTRACT_2(RX,RY,IMM)   lsr     RX, RY, 0x08
22 #endif
23
24 #ifdef CONFIG_ARC_HAS_LL64
25 # define LOADX(DST,RX)          ldd.ab  DST, [RX, 8]
26 # define STOREX(SRC,RX)         std.ab  SRC, [RX, 8]
27 # define ZOLSHFT                5
28 # define ZOLAND                 0x1F
29 #else
30 # define LOADX(DST,RX)          ld.ab   DST, [RX, 4]
31 # define STOREX(SRC,RX)         st.ab   SRC, [RX, 4]
32 # define ZOLSHFT                4
33 # define ZOLAND                 0xF
34 #endif
35
36 ENTRY_CFI(memcpy)
37         mov.f   0, r2
38 ;;; if size is zero
39         jz.d    [blink]
40         mov     r3, r0          ; don;t clobber ret val
41
42 ;;; if size <= 8
43         cmp     r2, 8
44         bls.d   @.Lsmallchunk
45         mov.f   lp_count, r2
46
47         and.f   r4, r0, 0x03
48         rsub    lp_count, r4, 4
49         lpnz    @.Laligndestination
50         ;; LOOP BEGIN
51         ldb.ab  r5, [r1,1]
52         sub     r2, r2, 1
53         stb.ab  r5, [r3,1]
54 .Laligndestination:
55
56 ;;; Check the alignment of the source
57         and.f   r4, r1, 0x03
58         bnz.d   @.Lsourceunaligned
59
60 ;;; CASE 0: Both source and destination are 32bit aligned
61 ;;; Convert len to Dwords, unfold x4
62         lsr.f   lp_count, r2, ZOLSHFT
63         lpnz    @.Lcopy32_64bytes
64         ;; LOOP START
65         LOADX (r6, r1)
66         LOADX (r8, r1)
67         LOADX (r10, r1)
68         LOADX (r4, r1)
69         STOREX (r6, r3)
70         STOREX (r8, r3)
71         STOREX (r10, r3)
72         STOREX (r4, r3)
73 .Lcopy32_64bytes:
74
75         and.f   lp_count, r2, ZOLAND ;Last remaining 31 bytes
76 .Lsmallchunk:
77         lpnz    @.Lcopyremainingbytes
78         ;; LOOP START
79         ldb.ab  r5, [r1,1]
80         stb.ab  r5, [r3,1]
81 .Lcopyremainingbytes:
82
83         j       [blink]
84 ;;; END CASE 0
85
86 .Lsourceunaligned:
87         cmp     r4, 2
88         beq.d   @.LunalignedOffby2
89         sub     r2, r2, 1
90
91         bhi.d   @.LunalignedOffby3
92         ldb.ab  r5, [r1, 1]
93
94 ;;; CASE 1: The source is unaligned, off by 1
95         ;; Hence I need to read 1 byte for a 16bit alignment
96         ;; and 2bytes to reach 32bit alignment
97         ldh.ab  r6, [r1, 2]
98         sub     r2, r2, 2
99         ;; Convert to words, unfold x2
100         lsr.f   lp_count, r2, 3
101         MERGE_1 (r6, r6, 8)
102         MERGE_2 (r5, r5, 24)
103         or      r5, r5, r6
104
105         ;; Both src and dst are aligned
106         lpnz    @.Lcopy8bytes_1
107         ;; LOOP START
108         ld.ab   r6, [r1, 4]
109         ld.ab   r8, [r1,4]
110
111         SHIFT_1 (r7, r6, 24)
112         or      r7, r7, r5
113         SHIFT_2 (r5, r6, 8)
114
115         SHIFT_1 (r9, r8, 24)
116         or      r9, r9, r5
117         SHIFT_2 (r5, r8, 8)
118
119         st.ab   r7, [r3, 4]
120         st.ab   r9, [r3, 4]
121 .Lcopy8bytes_1:
122
123         ;; Write back the remaining 16bits
124         EXTRACT_1 (r6, r5, 16)
125         sth.ab  r6, [r3, 2]
126         ;; Write back the remaining 8bits
127         EXTRACT_2 (r5, r5, 16)
128         stb.ab  r5, [r3, 1]
129
130         and.f   lp_count, r2, 0x07 ;Last 8bytes
131         lpnz    @.Lcopybytewise_1
132         ;; LOOP START
133         ldb.ab  r6, [r1,1]
134         stb.ab  r6, [r3,1]
135 .Lcopybytewise_1:
136         j       [blink]
137
138 .LunalignedOffby2:
139 ;;; CASE 2: The source is unaligned, off by 2
140         ldh.ab  r5, [r1, 2]
141         sub     r2, r2, 1
142
143         ;; Both src and dst are aligned
144         ;; Convert to words, unfold x2
145         lsr.f   lp_count, r2, 3
146 #ifdef __BIG_ENDIAN__
147         asl.nz  r5, r5, 16
148 #endif
149         lpnz    @.Lcopy8bytes_2
150         ;; LOOP START
151         ld.ab   r6, [r1, 4]
152         ld.ab   r8, [r1,4]
153
154         SHIFT_1 (r7, r6, 16)
155         or      r7, r7, r5
156         SHIFT_2 (r5, r6, 16)
157
158         SHIFT_1 (r9, r8, 16)
159         or      r9, r9, r5
160         SHIFT_2 (r5, r8, 16)
161
162         st.ab   r7, [r3, 4]
163         st.ab   r9, [r3, 4]
164 .Lcopy8bytes_2:
165
166 #ifdef __BIG_ENDIAN__
167         lsr.nz  r5, r5, 16
168 #endif
169         sth.ab  r5, [r3, 2]
170
171         and.f   lp_count, r2, 0x07 ;Last 8bytes
172         lpnz    @.Lcopybytewise_2
173         ;; LOOP START
174         ldb.ab  r6, [r1,1]
175         stb.ab  r6, [r3,1]
176 .Lcopybytewise_2:
177         j       [blink]
178
179 .LunalignedOffby3:
180 ;;; CASE 3: The source is unaligned, off by 3
181 ;;; Hence, I need to read 1byte for achieve the 32bit alignment
182
183         ;; Both src and dst are aligned
184         ;; Convert to words, unfold x2
185         lsr.f   lp_count, r2, 3
186 #ifdef __BIG_ENDIAN__
187         asl.ne  r5, r5, 24
188 #endif
189         lpnz    @.Lcopy8bytes_3
190         ;; LOOP START
191         ld.ab   r6, [r1, 4]
192         ld.ab   r8, [r1,4]
193
194         SHIFT_1 (r7, r6, 8)
195         or      r7, r7, r5
196         SHIFT_2 (r5, r6, 24)
197
198         SHIFT_1 (r9, r8, 8)
199         or      r9, r9, r5
200         SHIFT_2 (r5, r8, 24)
201
202         st.ab   r7, [r3, 4]
203         st.ab   r9, [r3, 4]
204 .Lcopy8bytes_3:
205
206 #ifdef __BIG_ENDIAN__
207         lsr.nz  r5, r5, 24
208 #endif
209         stb.ab  r5, [r3, 1]
210
211         and.f   lp_count, r2, 0x07 ;Last 8bytes
212         lpnz    @.Lcopybytewise_3
213         ;; LOOP START
214         ldb.ab  r6, [r1,1]
215         stb.ab  r6, [r3,1]
216 .Lcopybytewise_3:
217         j       [blink]
218
219 END_CFI(memcpy)