Cygwin: access: Fix X_OK behaviour for backup operators and admins
[newlib-cygwin.git] / newlib / libc / machine / arc / memcpy-archs.S
blobe8a2a7e039247976cf33e7bfe06d0f476cb37ce3
1 /*
2    Copyright (c) 2015-2024, Synopsys, Inc. All rights reserved.
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions are met:
7    1) Redistributions of source code must retain the above copyright notice,
8    this list of conditions and the following disclaimer.
10    2) Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
14    3) Neither the name of the Synopsys, Inc., nor the names of its contributors
15    may be used to endorse or promote products derived from this software
16    without specific prior written permission.
18    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28    POSSIBILITY OF SUCH DAMAGE.
31 /* This implementation is optimized for performance.  For code size a generic
32    implementation of this function from newlib/libc/string/memcpy.c will be
33    used.  */
34 #if !defined (__OPTIMIZE_SIZE__) && !defined (PREFER_SIZE_OVER_SPEED) \
35     && !defined (__ARC_RF16__)
37 #include "asm.h"
39 #if defined (__ARCHS__)
41 #ifdef __LITTLE_ENDIAN__
42 # define SHIFT_1(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
43 # define SHIFT_2(RX,RY,IMM)     lsr     RX, RY, IMM     ; >>
44 # define MERGE_1(RX,RY,IMM)     asl     RX, RY, IMM
45 # define MERGE_2(RX,RY,IMM)
46 # define EXTRACT_1(RX,RY,IMM)   and     RX, RY, 0xFFFF
47 # define EXTRACT_2(RX,RY,IMM)   lsr     RX, RY, IMM
48 #else
49 # define SHIFT_1(RX,RY,IMM)     lsr     RX, RY, IMM     ; >>
50 # define SHIFT_2(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
51 # define MERGE_1(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
52 # define MERGE_2(RX,RY,IMM)     asl     RX, RY, IMM     ; <<
53 # define EXTRACT_1(RX,RY,IMM)   lsr     RX, RY, IMM
54 # define EXTRACT_2(RX,RY,IMM)   lsr     RX, RY, 0x08
55 #endif
57 #ifdef __ARC_LL64__
58 # define PREFETCH_READ(RX)      prefetch        [RX, 56]
59 # define PREFETCH_WRITE(RX)     prefetchw       [RX, 64]
60 # define LOADX(DST,RX)          ldd.ab  DST, [RX, 8]
61 # define STOREX(SRC,RX)         std.ab  SRC, [RX, 8]
62 # define ZOLSHFT                5
63 # define ZOLAND                 0x1F
64 #else
65 # define PREFETCH_READ(RX)      prefetch        [RX, 28]
66 # define PREFETCH_WRITE(RX)     prefetchw       [RX, 32]
67 # define LOADX(DST,RX)          ld.ab   DST, [RX, 4]
68 # define STOREX(SRC,RX)         st.ab   SRC, [RX, 4]
69 # define ZOLSHFT                4
70 # define ZOLAND                 0xF
71 #endif
74 ;;; MEMCPY copy memory regions
75 ;;; Input arguments:
76 ;;;   r0 - output memory region
77 ;;;   r1 - input memory region
78 ;;;   r2 - size in bytes
79 ;;; Returns:
80 ;;;   r0 - pointer to the first byte of the output region
81 ;;; Clobber:
82 ;;;   r1, r2, r3, r4, r5, r6, r8r9, r10r11, lp_count
84 #if !defined (__ARC_UNALIGNED__)
86 ;;; MEMCPY routine for the case when the CPU only accepts ALIGNED
87 ;;; accesses to memory.
88 ENTRY (memcpy)
89         prefetch  [r1]          ; Prefetch the read location
90         prefetchw [r0]          ; Prefetch the write location
91         mov.f   0, r2
92 ; if size is zero
93         jz.d    [blink]
94         mov     r3, r0          ; don't clobber ret val
96 ; if size <= 8
97         cmp     r2, 8
98         bls.d   .Lsmallchunk
99         mov.f   lp_count, r2
101         and.f   r4, r0, 0x03
102         rsub    lp_count, r4, 4
103         lpnz    .Laligndestination
104         ; LOOP BEGIN
105         ldb.ab  r5, [r1,1]
106         sub     r2, r2, 1
107         stb.ab  r5, [r3,1]
108 .Laligndestination:
110 ; Check the alignment of the source
111         and.f   r4, r1, 0x03
112         bnz.d   .Lsourceunaligned
114 ; CASE 0: Both source and destination are 32bit aligned
115 ; Convert len to Dwords, unfold x4
116         lsr.f   lp_count, r2, ZOLSHFT
117         lpnz    .Lcopy32_64bytes
118         ; LOOP START
119         LOADX (r6, r1)
120         PREFETCH_READ (r1)
121         PREFETCH_WRITE (r3)
122         LOADX (r8, r1)
123         LOADX (r10, r1)
124         LOADX (r4, r1)
125         STOREX (r6, r3)
126         STOREX (r8, r3)
127         STOREX (r10, r3)
128         STOREX (r4, r3)
129 .Lcopy32_64bytes:
131         and.f   lp_count, r2, ZOLAND ;Last remaining 31 bytes
132 .Lsmallchunk:
133         lpnz    .Lcopyremainingbytes
134         ; LOOP START
135         ldb.ab  r5, [r1,1]
136         stb.ab  r5, [r3,1]
137 .Lcopyremainingbytes:
139         j       [blink]
140 ; END CASE 0
142 .Lsourceunaligned:
143         cmp     r4, 2
144         beq.d   .LunalignedOffby2
145         sub     r2, r2, 1
147         bhi.d   .LunalignedOffby3
148         ldb.ab  r5, [r1, 1]
150 ; CASE 1: The source is unaligned, off by 1
151         ; Hence I need to read 1 byte for a 16bit alignment
152         ; and 2bytes to reach 32bit alignment
153         ldh.ab  r6, [r1, 2]
154         sub     r2, r2, 2
155         ; Convert to words, unfold x2
156         lsr.f   lp_count, r2, 3
157         MERGE_1 (r6, r6, 8)
158         MERGE_2 (r5, r5, 24)
159         or      r5, r5, r6
161         ; Both src and dst are aligned
162         lpnz    .Lcopy8bytes_1
163         ; LOOP START
164         ld.ab   r6, [r1, 4]
165         prefetch [r1, 28]       ;Prefetch the next read location
166         ld.ab   r8, [r1,4]
167         prefetchw [r3, 32]      ;Prefetch the next write location
169         SHIFT_1 (r7, r6, 24)
170         or      r7, r7, r5
171         SHIFT_2 (r5, r6, 8)
173         SHIFT_1 (r9, r8, 24)
174         or      r9, r9, r5
175         SHIFT_2 (r5, r8, 8)
177         st.ab   r7, [r3, 4]
178         st.ab   r9, [r3, 4]
179 .Lcopy8bytes_1:
181         ; Write back the remaining 16bits
182         EXTRACT_1 (r6, r5, 16)
183         sth.ab  r6, [r3, 2]
184         ; Write back the remaining 8bits
185         EXTRACT_2 (r5, r5, 16)
186         stb.ab  r5, [r3, 1]
188         and.f   lp_count, r2, 0x07 ;Last 8bytes
189         lpnz    .Lcopybytewise_1
190         ; LOOP START
191         ldb.ab  r6, [r1,1]
192         stb.ab  r6, [r3,1]
193 .Lcopybytewise_1:
194         j       [blink]
196 .LunalignedOffby2:
197 ; CASE 2: The source is unaligned, off by 2
198         ldh.ab  r5, [r1, 2]
199         sub     r2, r2, 1
201         ; Both src and dst are aligned
202         ; Convert to words, unfold x2
203         lsr.f   lp_count, r2, 3
204 #ifdef __BIG_ENDIAN__
205         asl.nz  r5, r5, 16
206 #endif
207         lpnz    .Lcopy8bytes_2
208         ; LOOP START
209         ld.ab   r6, [r1, 4]
210         prefetch [r1, 28]       ;Prefetch the next read location
211         ld.ab   r8, [r1,4]
212         prefetchw [r3, 32]      ;Prefetch the next write location
214         SHIFT_1 (r7, r6, 16)
215         or      r7, r7, r5
216         SHIFT_2 (r5, r6, 16)
218         SHIFT_1 (r9, r8, 16)
219         or      r9, r9, r5
220         SHIFT_2 (r5, r8, 16)
222         st.ab   r7, [r3, 4]
223         st.ab   r9, [r3, 4]
224 .Lcopy8bytes_2:
226 #ifdef __BIG_ENDIAN__
227         lsr.nz  r5, r5, 16
228 #endif
229         sth.ab  r5, [r3, 2]
231         and.f   lp_count, r2, 0x07 ;Last 8bytes
232         lpnz    .Lcopybytewise_2
233         ; LOOP START
234         ldb.ab  r6, [r1,1]
235         stb.ab  r6, [r3,1]
236 .Lcopybytewise_2:
237         j       [blink]
239 .LunalignedOffby3:
240 ; CASE 3: The source is unaligned, off by 3
241 ; Hence, I need to read 1byte for achieve the 32bit alignment
243         ; Both src and dst are aligned
244         ; Convert to words, unfold x2
245         lsr.f   lp_count, r2, 3
246 #ifdef __BIG_ENDIAN__
247         asl.ne  r5, r5, 24
248 #endif
249         lpnz    .Lcopy8bytes_3
250         ; LOOP START
251         ld.ab   r6, [r1, 4]
252         prefetch [r1, 28]       ;Prefetch the next read location
253         ld.ab   r8, [r1,4]
254         prefetchw [r3, 32]      ;Prefetch the next write location
256         SHIFT_1 (r7, r6, 8)
257         or      r7, r7, r5
258         SHIFT_2 (r5, r6, 24)
260         SHIFT_1 (r9, r8, 8)
261         or      r9, r9, r5
262         SHIFT_2 (r5, r8, 24)
264         st.ab   r7, [r3, 4]
265         st.ab   r9, [r3, 4]
266 .Lcopy8bytes_3:
268 #ifdef __BIG_ENDIAN__
269         lsr.nz  r5, r5, 24
270 #endif
271         stb.ab  r5, [r3, 1]
273         and.f   lp_count, r2, 0x07 ;Last 8bytes
274         lpnz    .Lcopybytewise_3
275         ; LOOP START
276         ldb.ab  r6, [r1,1]
277         stb.ab  r6, [r3,1]
278 .Lcopybytewise_3:
279         j       [blink]
281 ENDFUNC (memcpy)
283 #else
285 ;;; MEMCPY routine which is used by systems with unaligned memory
286 ;;; accesses.  This is the case for most of ARCHS CPU family.
287 ENTRY(memcpy)
288         prefetch  [r1]          ; Prefetch the read location
289         prefetchw [r0]          ; Prefetch the write location
290         mov.f   0, r2
291 ;;; if size is zero
292         jz.d    [blink]
293         mov     r3, r0          ; don't clobber ret val
295 ;;; if size <= 8
296         cmp     r2, 8
297         bls.d   .Lsmallchunk
298         mov.f   lp_count, r2
300 ;;; Convert len to Dwords, unfold x4
301         lsr.f   lp_count, r2, ZOLSHFT
302         lpnz    .Lcopyfast
303         ;; LOOP START
304         LOADX (r6, r1)
305         PREFETCH_READ (r1)
306         PREFETCH_WRITE (r3)
307         LOADX (r8, r1)
308         LOADX (r10, r1)
309         LOADX (r4, r1)
310         STOREX (r6, r3)
311         STOREX (r8, r3)
312         STOREX (r10, r3)
313         STOREX (r4, r3)
314 .Lcopyfast:
316 #ifdef __ARC_LL64__
317         and     r2, r2, ZOLAND  ;Remaining 31 bytes
318         lsr.f   lp_count, r2, 3 ;Convert to 64-bit words.
319         lpnz    .Lcopy64b
320         ;; LOOP START
321         ldd.ab  r6,[r1,8]
322         std.ab  r6,[r3,8]
323 .Lcopy64b:
325         and.f   lp_count, r2, 0x07 ; Last 7 bytes
326 #else
327         and.f   lp_count, r2, ZOLAND
328 #endif
330 .Lsmallchunk:
331         lpnz    .Lcopyremainingbytes
332         ;; LOOP START
333         ldb.ab  r5, [r1,1]
334         stb.ab  r5, [r3,1]
335 .Lcopyremainingbytes:
337         j       [blink]
339 ENDFUNC(memcpy)
340 #endif
342 #endif /* __ARCHS__ */
344 #endif /* !__OPTIMIZE_SIZE__ && !PREFER_SIZE_OVER_SPEED */