1 /* memcpy - copy a block from source to destination. 31/64 bit S/390 version.
2 Copyright (C) 2012-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
21 #include "asm-syntax.h"
22 #include <ifunc-memcpy.h>
25 %r2 = address of destination memory area
26 %r3 = address of source memory area
27 %r4 = number of bytes to copy. */
43 #endif /* ! defined __s390x__ */
45 #if HAVE_MEMCPY_Z900_G5
46 ENTRY(MEMPCPY_Z900_G5)
47 # if defined __s390x__
51 # endif /* ! defined __s390x__ */
52 LGR %r1,%r2 # Use as dest
53 la %r2,0(%r4,%r2) # Return dest + n
58 # if defined __s390x__
62 # endif /* ! defined __s390x__ */
63 LGR %r1,%r2 # r1: Use as dest ; r2: Return dest
68 # if defined __s390x__
73 # endif /* ! defined __s390x__ */
77 # if defined __s390x__
78 larl %r5,.L_Z900_G5_15
79 # define Z900_G5_EX_D 0
83 # define Z900_G5_EX_D .L_Z900_G5_15-.L_Z900_G5_14
84 # endif /* ! defined __s390x__ */
85 ex %r4,Z900_G5_EX_D(%r5)
89 CGHI %r5,4096 # Switch to mvcle for copies >1MB
95 BRCTG %r5,.L_Z900_G5_12
100 #endif /* HAVE_MEMCPY_Z900_G5 */
102 ENTRY(__memcpy_mvcle)
103 # Using as standalone function will result in unexpected
104 # results since the length field is incremented by 1 in order to
105 # compensate the changes already done in the functions above.
106 LGR %r0,%r2 # backup return dest [ + n ]
107 AGHI %r4,1 # length + 1
108 LGR %r5,%r4 # source length
109 LGR %r4,%r3 # source address
110 LGR %r2,%r1 # destination address
111 LGR %r3,%r5 # destination length = source length
113 mvcle %r2,%r4,0 # thats it, MVCLE is your friend
115 LGR %r2,%r0 # return destination address
128 .machinemode "zarch_nohighgprs"
129 lgr %r1,%r2 # Use as dest
130 la %r2,0(%r4,%r2) # Return dest + n
136 .machinemode "zarch_nohighgprs"
137 lgr %r1,%r2 # r1: Use as dest ; r2: Return dest
139 # if !defined __s390x__
141 # endif /* !defined __s390x__ */
145 cgijlh %r5,0,.L_Z10_13
151 cgfi %r5,65535 # Switch to mvcle for copies >16MB
156 mvc 0(256,%r1),0(%r3)
164 #endif /* HAVE_MEMCPY_Z10 */
169 .machinemode "zarch_nohighgprs"
170 lgr %r1,%r2 # Use as dest
171 la %r2,0(%r4,%r2) # Return dest + n
177 .machinemode "zarch_nohighgprs"
178 lgr %r1,%r2 # r1: Use as dest ; r2: Return dest
180 # if !defined __s390x__
182 # endif /* !defined __s390x__ */
187 risbg %r5,%r4,8,128+63,56 # r0 = r5 / 256
194 cgfi %r5,255 # Switch to loop with pfd for copies >=64kB
197 mvc 0(256,%r1),0(%r3)
204 cgfi %r5,262144 # Switch to mvcle for copies >64MB
209 mvc 0(256,%r1),0(%r3)
218 #endif /* HAVE_MEMCPY_Z196 */
223 .machinemode "zarch_nohighgprs"
224 # if !defined __s390x__
225 /* Note: The 31bit dst and src pointers are prefixed with zeroes. */
229 # endif /* !defined __s390x__ */
231 clgijh %r4,16,.L_MEMMOVE_Z13_LARGE
233 .L_MEMMOVE_Z13_SMALL:
234 jl .L_MEMMOVE_Z13_END /* Jump away if len was zero. */
235 /* Store up to 16 bytes with vll/vstl which needs the index
236 instead of lengths. */
241 .L_MEMMOVE_Z13_LARGE:
242 lgr %r1,%r2 /* For memcpy: r1: Use as dest ;
244 /* The unsigned comparison (dst - src >= len) determines if we can
245 execute the forward case with memcpy. */
246 #if ! HAVE_MEMCPY_Z196
247 # error The z13 variant of memmove needs the z196 variant of memcpy!
249 clgrjhe %r0,%r4,.L_Z196_start2
250 risbgn %r5,%r4,4,128+63,60 /* r5 = r4 / 16 */
252 clgijhe %r5,8,.L_MEMMOVE_Z13_LARGE_64B
253 .L_MEMMOVE_Z13_LARGE_16B_LOOP:
254 /* Store at least 16 bytes with vl/vst. The number of 16byte blocks
259 brctg %r5,.L_MEMMOVE_Z13_LARGE_16B_LOOP
261 j .L_MEMMOVE_Z13_SMALL
262 .L_MEMMOVE_Z13_LARGE_64B:
263 /* Store at least 128 bytes with 4x vl/vst. The number of 64byte blocks
264 will be stored in r0. */
266 srlg %r0,%r5,2 /* r5 = %r0 / 4
267 => Number of 64byte blocks. */
268 .L_MEMMOVE_Z13_LARGE_64B_LOOP:
278 brctg %r0,.L_MEMMOVE_Z13_LARGE_64B_LOOP
280 /* Recalculate the number of 16byte blocks. */
281 risbg %r5,%r5,62,128+63,0 /* r5 = r5 & 3
282 => Remaining 16byte blocks. */
283 jne .L_MEMMOVE_Z13_LARGE_16B_LOOP
285 j .L_MEMMOVE_Z13_SMALL
287 #endif /* HAVE_MEMMOVE_Z13 */
289 #if HAVE_MEMMOVE_ARCH13
290 ENTRY(MEMMOVE_ARCH13)
292 .machinemode "zarch_nohighgprs"
293 # if ! defined __s390x__
294 /* Note: The 31bit dst and src pointers are prefixed with zeroes. */
298 # endif /* ! defined __s390x__ */
300 aghik %r0,%r4,-1 /* Both vstl and mvcrl needs highest index. */
301 clgijh %r4,16,.L_MEMMOVE_ARCH13_LARGE
302 .L_MEMMOVE_ARCH13_SMALL:
303 jl .L_MEMMOVE_ARCH13_END /* Return if len was zero (cc of aghik). */
304 /* Store up to 16 bytes with vll/vstl (needs highest index). */
307 .L_MEMMOVE_ARCH13_END:
309 .L_MEMMOVE_ARCH13_LARGE:
310 lgr %r1,%r2 /* For memcpy: r1: Use as dest ; r2: Return dest */
311 /* The unsigned comparison (dst - src >= len) determines if we can
312 execute the forward case with memcpy. */
313 #if ! HAVE_MEMCPY_Z196
314 # error The arch13 variant of memmove needs the z196 variant of memcpy!
317 clgrjhe %r5,%r4,.L_Z196_start2
318 clgijh %r0,255,.L_MEMMOVE_ARCH13_LARGER_256B
319 /* Move up to 256bytes with mvcrl (move right to left). */
320 mvcrl 0(%r1),0(%r3) /* Move (r0 + 1) bytes from r3 to r1. */
322 .L_MEMMOVE_ARCH13_LARGER_256B:
323 /* First move the "remaining" block of up to 256 bytes at the end of
324 src/dst buffers. Then move blocks of 256bytes in a loop starting
325 with the block at the end.
326 (If src/dst pointers are aligned e.g. to 256 bytes, then the pointers
327 passed to mvcrl instructions are aligned, too) */
328 risbgn %r5,%r0,8,128+63,56 /* r5 = r0 / 256 */
329 risbgn %r0,%r0,56,128+63,0 /* r0 = r0 & 0xFF */
333 mvcrl 0(%r1),0(%r3) /* Move (r0 + 1) bytes from r3 to r1. */
334 lghi %r0,255 /* Always copy 256 bytes in the loop below! */
335 .L_MEMMOVE_ARCH13_LARGE_256B_LOOP:
338 mvcrl 0(%r1),0(%r3) /* Move (r0 + 1) bytes from r3 to r1. */
339 brctg %r5,.L_MEMMOVE_ARCH13_LARGE_256B_LOOP
342 #endif /* HAVE_MEMMOVE_ARCH13 */
344 #if ! HAVE_MEMCPY_IFUNC
345 /* If we don't use ifunc, define an alias for mem[p]cpy here.
346 Otherwise see sysdeps/s390/mem[p]cpy.c. */
347 strong_alias (MEMCPY_DEFAULT, memcpy)
348 strong_alias (MEMPCPY_DEFAULT, __mempcpy)
349 weak_alias (__mempcpy, mempcpy)
352 #if ! HAVE_MEMMOVE_IFUNC
353 /* If we don't use ifunc, define an alias for memmove here.
354 Otherwise see sysdeps/s390/memmove.c. */
355 # if ! HAVE_MEMMOVE_C
356 /* If the c variant is needed, then sysdeps/s390/memmove-c.c
358 Otherwise MEMMOVE_DEFAULT is implemented here and we have to define it. */
359 strong_alias (MEMMOVE_DEFAULT, memmove)
363 #if defined SHARED && IS_IN (libc)
364 /* Defines the internal symbols.
365 Compare to libc_hidden_[builtin_]def (mem[p]cpy) in string/mem[p]cpy.c. */
366 strong_alias (MEMCPY_DEFAULT, __GI_memcpy)
367 strong_alias (MEMPCPY_DEFAULT, __GI_mempcpy)
368 strong_alias (MEMPCPY_DEFAULT, __GI___mempcpy)
369 # if ! HAVE_MEMMOVE_C
370 /* If the c variant is needed, then sysdeps/s390/memmove-c.c
371 defines the internal symbol.
372 Otherwise MEMMOVE_DEFAULT is implemented here and we have to define it. */
373 strong_alias (MEMMOVE_DEFAULT, __GI_memmove)