Cygwin: access: Fix X_OK behaviour for backup operators and admins
[newlib-cygwin.git] / newlib / libc / machine / arc64 / memmove.S
blob5458dd012644d498a1fb1dd20671e352ac463708
1 /*
2    Copyright (c) 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 #include <sys/asm.h>
33 ; r0 void* dest
34 ; r1 const void* src
35 ; r2 size_t count
37 ; The 64-bit crunching implementation.
39 #if defined (__ARC64_ARCH32__) && !defined(__ARC64_LL64__)
41 ENTRY (memmove)
43 ; If the destination is greater than the source
44         cmp     r0, r1
45         ADDP    r4, r1, r2
46 ; or if the source plus count is smaller than the destination
47         cmp.eq r4, r0
49 ; We can safely perform a normal memcpy. Otherwise, we need to perform it
50 ; backwards
51         blo.d   @.L_normal_memcpy
52         lsr.f   r11, r2, 4              ; counter for 16-byte chunks
54         ADDP    r3, r0, r2
56 ; Backwards search
57 ; The only thing that changes between memcpy and memmove is copy direction
58 ; in case the dest and src address memory locations overlap
59 ; More detailed information is in the forwards copy and at the end of
60 ; this document
62         ADDP    r1, r1, r2
63         bmsk_s  r2, r2, 3
65         bbit0.d r2, 1, @1f
66         lsr     r5, r2, 2
67         ldh.aw  r4, [r1, -2]
68         sth.aw  r4, [r3, -2]
70         bbit0.d r2, 0, @1f
71         xor     r5, r5, 3
72         ldb.aw  r4, [r1, -1]
73         stb.aw  r4, [r3, -1]
75         asl     r5, r5, 1
76         bi      [r5]
77         ld.aw   r4,[r1, -4]
78         st.aw   r4,[r3, -4]
79         ld.aw   r4,[r1, -4]
80         st.aw   r4,[r3, -4]
81         ld.aw   r4,[r1, -4]
82         st.aw   r4,[r3, -4]
84 ; Return if there are no 16 byte chunks
85         jeq     [blink]
87 .L_write_backwards_16_bytes:
88         ld.aw   r4, [r1, -4]
89         ld.aw   r5, [r1, -4]
90         ld.aw   r6, [r1, -4]
91         ld.aw   r7, [r1, -4]
92         st.aw   r4, [r3, -4]
93         st.aw   r5, [r3, -4]
94         st.aw   r6, [r3, -4]
95         dbnz.d  r11, @.L_write_backwards_16_bytes
96         st.aw   r7, [r3, -4]
98         j_s     [blink]
100 .L_normal_memcpy:
101         beq.d   @.L_write_forwards_15_bytes
102         mov     r3, r0                  ; work on a copy of "r0"
104 .L_write_forwards_16_bytes:
105         ld.ab   r4, [r1, 4]
106         ld.ab   r5, [r1, 4]
107         ld.ab   r6, [r1, 4]
108         ld.ab   r7, [r1, 4]
109         st.ab   r4, [r3, 4]
110         st.ab   r5, [r3, 4]
111         st.ab   r6, [r3, 4]
112         dbnz.d  r11, @.L_write_forwards_16_bytes
113         st.ab   r7, [r3, 4]
114         bmsk_s  r2, r2, 3
116 .L_write_forwards_15_bytes:
117         bbit0.d r2, 1, @1f
118         lsr     r11, r2, 2
119         ldh.ab  r4, [r1, 2]
120         sth.ab  r4, [r3, 2]
122         bbit0.d r2, 0, @1f
123         xor     r11, r11, 3
124         ldb.ab  r4, [r1, 1]
125         stb.ab  r4, [r3, 1]
127         asl     r11, r11, 1
128         bi      [r11]
129         ld.ab   r4,[r1, 4]
130         st.ab   r4,[r3, 4]
131         ld.ab   r4,[r1, 4]
132         st.ab   r4,[r3, 4]
133         ld      r4,[r1]
134         st      r4,[r3]
136         j_s     [blink]
138 ENDFUNC (memmove)
140 #else
142 ENTRY (memmove)
143 ; If the destination is greater than the source
144         cmp     r0, r1
145         ADDP    r4, r1, r2
146 ; or if the source plus count is smaller than the destination
147         cmp.eq r4, r0
149 ; We can safely perform a normal memcpy. Otherwise, we need to perform it
150 ; backwards
151         blo.d   @.L_normal_memcpy
152         LSRP.f  r12, r2, 5              ; counter for 32-byte chunks
154         ADDP    r3, r0, r2
156 ; Backwards search
157 ; The only thing that changes between memcpy and memmove is copy direction
158 ; in case the dest and src address memory locations overlap
159 ; More detailed information is in the forwards copy and at the end of
160 ; this document
162 ; Set both r0 and r1 to point to the end of each memory location
163         ADDP    r1, r1, r2
164         bmsk_s  r2, r2, 4
166         bbit0.d r2, 0, @1f
167         lsr     r11, r2, 3
168         ldb.aw  r4, [r1, -1]
169         stb.aw  r4, [r3, -1]
171         bbit0.d r2, 1, @1f
172         xor     r11, r11, 3
173         ldh.aw  r4, [r1, -2]
174         sth.aw  r4, [r3, -2]
176         bbit0.d r2, 2, @1f
177         asl     r11, r11, 1
178         ld.aw   r4, [r1, -4]
179         st.aw   r4, [r3, -4]
181         bi      [r11]
182         LD64.aw r4, [r1, -8]
183         ST64.aw r4, [r3, -8]
184         LD64.aw r4, [r1, -8]
185         ST64.aw r4, [r3, -8]
186         LD64.aw r4, [r1, -8]
187         ST64.aw r4, [r3, -8]
189 ; Jump if there are no 32 byte chunks
190         jeq     [blink]
192 .L_write_backwards_32_bytes:                    ; Take care of 32 byte chunks
193 #if defined (__ARC64_M128__)
195         lddl.aw r4r5, [r1, -16]
196         lddl.aw r6r7, [r1, -16]
198         stdl.aw r4r5, [r3, -16]
199         stdl.aw r6r7, [r3, -16]
200         dbnz    r12, @.L_write_backwards_32_bytes
202 #elif defined (__ARC64_ARCH64__) || (  defined (__ARC64_ARCH32__) && defined (__ARC64_LL64__) )
204         LD64.aw r4, [r1, -8]
205         LD64.aw r6, [r1, -8]
206         LD64.aw r8, [r1, -8]
207         LD64.aw r10,[r1, -8]
209         ST64.aw r4, [r3, -8]
210         ST64.aw r6, [r3, -8]
211         ST64.aw r8, [r3, -8]
212         dbnz.d  r12, @.L_write_backwards_32_bytes
213         ST64.aw r10, [r3, -8]
215 #else
216 # error Unknown configuration
217 #endif
219         j_s     [blink]
221 ; Normal memcpy
222 .L_normal_memcpy:
223         ;LSRP.f r12, r2, 5              ; Moved up
225         beq.d   @.L_write_forwards_31_bytes
226         MOVP    r3, r0                  ; do not clobber the "dest"
228 .L_write_forwards_32_bytes:                     ; Take care of 32 byte chunks
229 #if defined (__ARC64_M128__)
231         lddl.ab r4r5, [r1, +16]
232         lddl.ab r6r7, [r1, +16]
234         stdl.ab r4r5, [r3, +16]
235         stdl.ab r6r7, [r3, +16]
236         dbnz    r12, @.L_write_forwards_32_bytes
238 #elif defined (__ARC64_ARCH64__) || (  defined (__ARC64_ARCH32__) && defined (__ARC64_LL64__) )
240         LD64.ab r4, [r1, +8]
241         LD64.ab r6, [r1, +8]
242         LD64.ab r8, [r1, +8]
243         LD64.ab r10,[r1, +8]
244         ST64.ab r4, [r3, +8]
245         ST64.ab r6, [r3, +8]
246         ST64.ab r8, [r3, +8]
247         dbnz.d  r12, @.L_write_forwards_32_bytes
248         ST64.ab r10, [r3, +8]   ; Shove store in delay slot
250 #else
251 # error Unknown configuration
252 #endif
254         bmsk_s  r2, r2, 4               ; From now on, we only care for the remainder % 32
257 ; The remainder bits indicating how many more bytes to copy
258 ; .------------------------.
259 ; | b4 | b3 | b2 | b1 | b0 |
260 ; `------------------------'
261 ;   16    8    4    2    1
262 .L_write_forwards_31_bytes:
263         bbit0.d r2, 2, @1f              ; is b2 set? then copy 4 bytes
264         lsr         r12, r2, 3          ; see the notes below
265         ld.ab   r4, [r1, 4]
266         st.ab   r4, [r3, 4]
268         bbit0.d r2, 1, @1f              ; is b1 set? then copy 2 bytes
269         xor         r12, r12, 3
270         ldh.ab  r4, [r1, 2]
271         sth.ab  r4, [r3, 2]
273         bbit0.d r2, 0, @1f              ; is b0 set? then copy 1 byte
274         asl         r12, r12, 1
275         ldb.ab  r4, [r1, 1]
276         stb.ab  r4, [r3, 1]
278 ; Interpreting bits (b4,b3) [1] and how they correlate to branch index:
280 ; (b4,b3) | bytes to copy | branch index
281 ; --------+---------------+-------------
282 ;   00b   |       0       |   3 (11b)
283 ;   01b   |       8       |   2 (10b)
284 ;   10b   |      16       |   1 (01b)
285 ;   11b   |      24       |   0 (00b)
287 ; To go from (b4,b3) to branch index, the bits must be flipped.
288 ; In other words, they must be XORed with 11b [2].
290 ; Last but not least, "bi" jumps at boundaries of 4. We need to double
291 ; the index to jump 8 bytes [3].
293 ; Hence, the 3 operations for calculating the branch index that are spread
294 ; in "bbit0" delay slots:
296 ;       lsr         r12, r2,  3    [1]
297 ;       xor         r12, r12, 3    [2]
298 ;       asl         r12, r12, 1    [3]
300         bi          [r12]
301         LD64.ab r4, [r1, 8]
302         ST64.ab r4, [r3, 8]
303         LD64.ab r4, [r1, 8]
304         ST64.ab r4, [r3, 8]
305         LD64.ab r4, [r1, 8]
306         ST64.ab r4, [r3, 8]
308         j_s     [blink]
310 ENDFUNC (memmove)
312 #endif