arc: Merge ARCv2 string routines in generic ARC .S files
[uclibc-ng.git] / libc / string / arc / memcpy.S
blob69d7220b8a7e78db3a536606e0f970af60cf3555
1 /*
2  * Copyright (C) 2013, 2014-2015, 2017 Synopsys, Inc. (www.synopsys.com)
3  * Copyright (C) 2007 ARC International (UK) LTD
4  *
5  * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
6  */
8 #include <sysdep.h>
10 #if !defined(__ARC700__) && !defined(__ARCHS__)
11 #error "Neither ARC700 nor ARCHS is defined!"
12 #endif
14 ENTRY(memcpy)
16 #ifdef __ARC700__
17 /* This memcpy implementation does not support objects of 1GB or larger -
18    the check for alignment does not work then.  */
19 /* We assume that most sources and destinations are aligned, and
20    that also lengths are mostly a multiple of four, although to a lesser
21    extent.  */
22         or      r3,r0,r1
23         asl_s   r3,r3,30
24         mov_s   r5,r0
25         brls.d  r2,r3,.Lcopy_bytewise
26         sub.f   r3,r2,1
27         ld_s    r12,[r1,0]
28         asr.f   lp_count,r3,3
29         bbit0.d r3,2,.Lnox4
30         bmsk_s  r2,r2,1
31         st.ab   r12,[r5,4]
32         ld.a    r12,[r1,4]
33 .Lnox4:
34         lppnz   .Lendloop
35         ld_s    r3,[r1,4]
36         st.ab   r12,[r5,4]
37         ld.a    r12,[r1,8]
38         st.ab   r3,[r5,4]
39 .Lendloop:
40         breq    r2,0,.Last_store
41         ld      r3,[r5,0]
42 #ifdef __LITTLE_ENDIAN__
43         add3    r2,-1,r2
44         ; uses long immediate
45         xor_s   r12,r12,r3
46         bmsk    r12,r12,r2
47         xor_s   r12,r12,r3
48 #else /* BIG ENDIAN */
49         sub3    r2,31,r2
50         ; uses long immediate
51         xor_s   r3,r3,r12
52         bmsk    r3,r3,r2
53         xor_s   r12,r12,r3
54 #endif /* ENDIAN */
55 .Last_store:
56         j_s.d   [blink]
57         st      r12,[r5,0]
59         .balign 4
60 .Lcopy_bytewise:
61         jcs     [blink]
62         ldb_s   r12,[r1,0]
63         lsr.f   lp_count,r3
64         bhs_s   .Lnox1
65         stb.ab  r12,[r5,1]
66         ldb.a   r12,[r1,1]
67 .Lnox1:
68         lppnz   .Lendbloop
69         ldb_s   r3,[r1,1]
70         stb.ab  r12,[r5,1]
71         ldb.a   r12,[r1,2]
72         stb.ab  r3,[r5,1]
73 .Lendbloop:
74         j_s.d   [blink]
75         stb     r12,[r5,0]
76 #endif /* __ARC700__ */
78 #ifdef __ARCHS__
79 #ifdef __LITTLE_ENDIAN__
80 # define SHIFT_1(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
81 # define SHIFT_2(RX,RY,IMM)     lsr     RX, RY, IMM     ; >>
82 # define MERGE_1(RX,RY,IMM)     asl     RX, RY, IMM
83 # define MERGE_2(RX,RY,IMM)
84 # define EXTRACT_1(RX,RY,IMM)   and     RX, RY, 0xFFFF
85 # define EXTRACT_2(RX,RY,IMM)   lsr     RX, RY, IMM
86 #else
87 # define SHIFT_1(RX,RY,IMM)     lsr     RX, RY, IMM     ; >>
88 # define SHIFT_2(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
89 # define MERGE_1(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
90 # define MERGE_2(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
91 # define EXTRACT_1(RX,RY,IMM)   lsr     RX, RY, IMM
92 # define EXTRACT_2(RX,RY,IMM)   lsr     RX, RY, 0x08
93 #endif
95 #if defined(__LL64__) || defined(__ARC_LL64__)
96 # define PREFETCH_READ(RX)      prefetch [RX, 56]
97 # define PREFETCH_WRITE(RX)     prefetchw [RX, 64]
98 # define LOADX(DST,RX)          ldd.ab  DST, [RX, 8]
99 # define STOREX(SRC,RX)         std.ab  SRC, [RX, 8]
100 # define ZOLSHFT                5
101 # define ZOLAND                 0x1F
102 #else
103 # define PREFETCH_READ(RX)      prefetch [RX, 28]
104 # define PREFETCH_WRITE(RX)     prefetchw [RX, 32]
105 # define LOADX(DST,RX)          ld.ab   DST, [RX, 4]
106 # define STOREX(SRC,RX)         st.ab   SRC, [RX, 4]
107 # define ZOLSHFT                4
108 # define ZOLAND                 0xF
109 #endif
111         prefetch  [r1]          ; Prefetch the read location
112         prefetchw [r0]          ; Prefetch the write location
113         mov.f   0, r2
114 ;;; if size is zero
115         jz.d    [blink]
116         mov     r3, r0          ; don't clobber ret val
118 ;;; if size <= 8
119         cmp     r2, 8
120         bls.d   @.Lsmallchunk
121         mov.f   lp_count, r2
123         and.f   r4, r0, 0x03
124         rsub    lp_count, r4, 4
125         lpnz    @.Laligndestination
126         ;; LOOP BEGIN
127         ldb.ab  r5, [r1,1]
128         sub     r2, r2, 1
129         stb.ab  r5, [r3,1]
130 .Laligndestination:
132 ;;; Check the alignment of the source
133         and.f   r4, r1, 0x03
134         bnz.d   @.Lsourceunaligned
136 ;;; CASE 0: Both source and destination are 32bit aligned
137 ;;; Convert len to Dwords, unfold x4
138         lsr.f   lp_count, r2, ZOLSHFT
139         lpnz    @.Lcopy32_64bytes
140         ;; LOOP START
141         LOADX (r6, r1)
142         PREFETCH_READ (r1)
143         PREFETCH_WRITE (r3)
144         LOADX (r8, r1)
145         LOADX (r10, r1)
146         LOADX (r4, r1)
147         STOREX (r6, r3)
148         STOREX (r8, r3)
149         STOREX (r10, r3)
150         STOREX (r4, r3)
151 .Lcopy32_64bytes:
153         and.f   lp_count, r2, ZOLAND ;Last remaining 31 bytes
154 .Lsmallchunk:
155         lpnz    @.Lcopyremainingbytes
156         ;; LOOP START
157         ldb.ab  r5, [r1,1]
158         stb.ab  r5, [r3,1]
159 .Lcopyremainingbytes:
161         j       [blink]
162 ;;; END CASE 0
164 .Lsourceunaligned:
165         cmp     r4, 2
166         beq.d   @.LunalignedOffby2
167         sub     r2, r2, 1
169         bhi.d   @.LunalignedOffby3
170         ldb.ab  r5, [r1, 1]
172 ;;; CASE 1: The source is unaligned, off by 1
173         ;; Hence I need to read 1 byte for a 16bit alignment
174         ;; and 2bytes to reach 32bit alignment
175         ldh.ab  r6, [r1, 2]
176         sub     r2, r2, 2
177         ;; Convert to words, unfold x2
178         lsr.f   lp_count, r2, 3
179         MERGE_1 (r6, r6, 8)
180         MERGE_2 (r5, r5, 24)
181         or      r5, r5, r6
183         ;; Both src and dst are aligned
184         lpnz    @.Lcopy8bytes_1
185         ;; LOOP START
186         ld.ab   r6, [r1, 4]
187         prefetch [r1, 28]       ;Prefetch the next read location
188         ld.ab   r8, [r1,4]
189         prefetchw [r3, 32]      ;Prefetch the next write location
191         SHIFT_1 (r7, r6, 24)
192         or      r7, r7, r5
193         SHIFT_2 (r5, r6, 8)
195         SHIFT_1 (r9, r8, 24)
196         or      r9, r9, r5
197         SHIFT_2 (r5, r8, 8)
199         st.ab   r7, [r3, 4]
200         st.ab   r9, [r3, 4]
201 .Lcopy8bytes_1:
203         ;; Write back the remaining 16bits
204         EXTRACT_1 (r6, r5, 16)
205         sth.ab  r6, [r3, 2]
206         ;; Write back the remaining 8bits
207         EXTRACT_2 (r5, r5, 16)
208         stb.ab  r5, [r3, 1]
210         and.f   lp_count, r2, 0x07 ;Last 8bytes
211         lpnz    @.Lcopybytewise_1
212         ;; LOOP START
213         ldb.ab  r6, [r1,1]
214         stb.ab  r6, [r3,1]
215 .Lcopybytewise_1:
216         j       [blink]
218 .LunalignedOffby2:
219 ;;; CASE 2: The source is unaligned, off by 2
220         ldh.ab  r5, [r1, 2]
221         sub     r2, r2, 1
223         ;; Both src and dst are aligned
224         ;; Convert to words, unfold x2
225         lsr.f   lp_count, r2, 3
226 #ifdef __BIG_ENDIAN__
227         asl.nz  r5, r5, 16
228 #endif
229         lpnz    @.Lcopy8bytes_2
230         ;; LOOP START
231         ld.ab   r6, [r1, 4]
232         prefetch [r1, 28]       ;Prefetch the next read location
233         ld.ab   r8, [r1,4]
234         prefetchw [r3, 32]      ;Prefetch the next write location
236         SHIFT_1 (r7, r6, 16)
237         or      r7, r7, r5
238         SHIFT_2 (r5, r6, 16)
240         SHIFT_1 (r9, r8, 16)
241         or      r9, r9, r5
242         SHIFT_2 (r5, r8, 16)
244         st.ab   r7, [r3, 4]
245         st.ab   r9, [r3, 4]
246 .Lcopy8bytes_2:
248 #ifdef __BIG_ENDIAN__
249         lsr.nz  r5, r5, 16
250 #endif
251         sth.ab  r5, [r3, 2]
253         and.f   lp_count, r2, 0x07 ;Last 8bytes
254         lpnz    @.Lcopybytewise_2
255         ;; LOOP START
256         ldb.ab  r6, [r1,1]
257         stb.ab  r6, [r3,1]
258 .Lcopybytewise_2:
259         j       [blink]
261 .LunalignedOffby3:
262 ;;; CASE 3: The source is unaligned, off by 3
263 ;;; Hence, I need to read 1byte for achieve the 32bit alignment
265         ;; Both src and dst are aligned
266         ;; Convert to words, unfold x2
267         lsr.f   lp_count, r2, 3
268 #ifdef __BIG_ENDIAN__
269         asl.ne  r5, r5, 24
270 #endif
271         lpnz    @.Lcopy8bytes_3
272         ;; LOOP START
273         ld.ab   r6, [r1, 4]
274         prefetch [r1, 28]       ;Prefetch the next read location
275         ld.ab   r8, [r1,4]
276         prefetchw [r3, 32]      ;Prefetch the next write location
278         SHIFT_1 (r7, r6, 8)
279         or      r7, r7, r5
280         SHIFT_2 (r5, r6, 24)
282         SHIFT_1 (r9, r8, 8)
283         or      r9, r9, r5
284         SHIFT_2 (r5, r8, 24)
286         st.ab   r7, [r3, 4]
287         st.ab   r9, [r3, 4]
288 .Lcopy8bytes_3:
290 #ifdef __BIG_ENDIAN__
291         lsr.nz  r5, r5, 24
292 #endif
293         stb.ab  r5, [r3, 1]
295         and.f   lp_count, r2, 0x07 ;Last 8bytes
296         lpnz    @.Lcopybytewise_3
297         ;; LOOP START
298         ldb.ab  r6, [r1,1]
299         stb.ab  r6, [r3,1]
300 .Lcopybytewise_3:
301         j       [blink]
302 #endif /* __ARCHS__ */
304 END(memcpy)
305 libc_hidden_def(memcpy)