S390: Implement mempcpy with help of memcpy. [BZ #19765]

There exist optimized memcpy functions on s390, but no optimized mempcpy.
This patch adds mempcpy entry points in memcpy.S files, which
use the memcpy implementation. Now mempcpy itself is also an IFUNC function
as memcpy is and the variants are listed in ifunc-impl-list.c.

The s390 string.h does not define _HAVE_STRING_ARCH_mempcpy.
Instead mempcpy string/string.h inlines memcpy() + n.
If n is constant and small enough, GCC emits instructions like mvi or mvc
and avoids the function call to memcpy.
If n is not constant, then memcpy is called and n is added afterwards.
If _HAVE_STRING_ARCH_mempcpy would be defined, mempcpy would be called in
every case.

According to PR70140 "Inefficient expansion of __builtin_mempcpy"
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70140) GCC should handle a
call to mempcpy in the same way as memcpy. Then either the mempcpy macro
in string/string.h has to be removed or _HAVE_STRING_ARCH_mempcpy has to
be defined for S390.

ChangeLog:

	[BZ #19765]
	* sysdeps/s390/mempcpy.S: New File.
	* sysdeps/s390/multiarch/mempcpy.c: Likewise.
	* sysdeps/s390/multiarch/Makefile (sysdep_routines): Add mempcpy.
	* sysdeps/s390/multiarch/ifunc-impl-list.c (__libc_ifunc_impl_list):
	Add mempcpy variants.
	* sysdeps/s390/s390-32/memcpy.S: Add mempcpy entry point.
	(memcpy): Adjust to be usable from mempcpy entry point.
	(__memcpy_mvcle): Likewise.
	* sysdeps/s390/s390-64/memcpy.S: Likewise.
	* sysdeps/s390/s390-32/multiarch/memcpy-s390.S: Add entry points
	____mempcpy_z196, ____mempcpy_z10 and add __GI_ symbols for mempcpy.
	(__memcpy_z196): Adjust to be usable from mempcpy entry point.
	(__memcpy_z10): Likewise.
	* sysdeps/s390/s390-64/multiarch/memcpy-s390x.S: Likewise.
This commit is contained in:
Stefan Liebler 2016-05-24 10:39:13 +02:00
parent 7165583255
commit 4c01126896
9 changed files with 188 additions and 48 deletions

View file

@ -1,3 +1,21 @@
2016-05-24 Stefan Liebler <stli@linux.vnet.ibm.com>
[BZ #19765]
* sysdeps/s390/mempcpy.S: New File.
* sysdeps/s390/multiarch/mempcpy.c: Likewise.
* sysdeps/s390/multiarch/Makefile (sysdep_routines): Add mempcpy.
* sysdeps/s390/multiarch/ifunc-impl-list.c (__libc_ifunc_impl_list):
Add mempcpy variants.
* sysdeps/s390/s390-32/memcpy.S: Add mempcpy entry point.
(memcpy): Adjust to be usable from mempcpy entry point.
(__memcpy_mvcle): Likewise.
* sysdeps/s390/s390-64/memcpy.S: Likewise.
* sysdeps/s390/s390-32/multiarch/memcpy-s390.S: Add entry points
____mempcpy_z196, ____mempcpy_z10 and add __GI_ symbols for mempcpy.
(__memcpy_z196): Adjust to be usable from mempcpy entry point.
(__memcpy_z10): Likewise.
* sysdeps/s390/s390-64/multiarch/memcpy-s390x.S: Likewise.
2016-05-24 Stefan Liebler <stli@linux.vnet.ibm.com>
* sysdeps/s390/multiarch/ifunc-resolve.h (s390_libc_ifunc):

19
sysdeps/s390/mempcpy.S Normal file
View file

@ -0,0 +1,19 @@
/* CPU specific mempcpy without multiarch - 32/64 bit S/390 version.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* mempcpy is implemented in memcpy.S. */

View file

@ -18,7 +18,8 @@ sysdep_routines += strlen strlen-vx strlen-c \
memchr memchr-vx \
rawmemchr rawmemchr-vx rawmemchr-c \
memccpy memccpy-vx memccpy-c \
memrchr memrchr-vx memrchr-c
memrchr memrchr-vx memrchr-c \
mempcpy
endif
ifeq ($(subdir),wcsmbs)

View file

@ -69,6 +69,13 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
S390_IS_Z10 (stfle_bits), __memcpy_z10)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_default))
IFUNC_IMPL (i, name, mempcpy,
IFUNC_IMPL_ADD (array, i, mempcpy,
S390_IS_Z196 (stfle_bits), ____mempcpy_z196)
IFUNC_IMPL_ADD (array, i, mempcpy,
S390_IS_Z10 (stfle_bits), ____mempcpy_z10)
IFUNC_IMPL_ADD (array, i, mempcpy, 1, ____mempcpy_default))
#endif /* SHARED */
#ifdef HAVE_S390_VX_ASM_SUPPORT

View file

@ -0,0 +1,26 @@
/* Multiple versions of mempcpy.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#if defined SHARED && IS_IN (libc)
# include <ifunc-resolve.h>
s390_libc_ifunc (__mempcpy)
__asm__ (".weak mempcpy\n\t"
".set mempcpy,__mempcpy\n\t");
#endif

View file

@ -25,12 +25,23 @@
%r3 = address of source memory area
%r4 = number of bytes to copy. */
#ifdef USE_MULTIARCH
ENTRY(__memcpy_default)
#else
ENTRY(memcpy)
#endif
.text
ENTRY(__mempcpy)
.machine "g5"
lr %r1,%r2 # Use as dest
la %r2,0(%r4,%r2) # Return dest + n
j .L_G5_start
END(__mempcpy)
#ifndef USE_MULTIARCH
libc_hidden_def (__mempcpy)
weak_alias (__mempcpy, mempcpy)
libc_hidden_builtin_def (mempcpy)
#endif
ENTRY(memcpy)
.machine "g5"
lr %r1,%r2 # r1: Use as dest ; r2: Return dest
.L_G5_start:
st %r13,52(%r15)
.cfi_offset 13, -44
basr %r13,0
@ -41,14 +52,13 @@ ENTRY(memcpy)
lr %r5,%r4
srl %r5,8
ltr %r5,%r5
lr %r1,%r2
jne .L_G5_13
ex %r4,.L_G5_17-.L_G5_16(%r13)
.L_G5_4:
l %r13,52(%r15)
br %r14
.L_G5_13:
chi %r5,4096 # Switch to mvcle for copies >1MB
chi %r5,4096 # Switch to mvcle for copies >1MB
jh __memcpy_mvcle
.L_G5_12:
mvc 0(256,%r1),0(%r3)
@ -59,24 +69,24 @@ ENTRY(memcpy)
j .L_G5_4
.L_G5_17:
mvc 0(1,%r1),0(%r3)
#ifdef USE_MULTIARCH
END(__memcpy_default)
#else
END(memcpy)
#ifndef USE_MULTIARCH
libc_hidden_builtin_def (memcpy)
#endif
ENTRY(__memcpy_mvcle)
# Using as standalone function will result in unexpected
# results since the length field is incremented by 1 in order to
# compensate the changes already done in the functions above.
ahi %r4,1 # length + 1
lr %r5,%r4 # source length
lr %r4,%r3 # source address
lr %r3,%r5 # destination length = source length
# Using as standalone function will result in unexpected
# results since the length field is incremented by 1 in order to
# compensate the changes already done in the functions above.
lr %r0,%r2 # backup return dest [ + n ]
ahi %r4,1 # length + 1
lr %r5,%r4 # source length
lr %r4,%r3 # source address
lr %r2,%r1 # destination address
lr %r3,%r5 # destination length = source length
.L_MVCLE_1:
mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L_MVCLE_1
lr %r2,%r1 # return destination address
br %r14
mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L_MVCLE_1
lr %r2,%r0 # return destination address
br %r14
END(__memcpy_mvcle)

View file

@ -29,14 +29,23 @@
#if defined SHARED && IS_IN (libc)
ENTRY(____mempcpy_z196)
.machine "z196"
.machinemode "zarch_nohighgprs"
lr %r1,%r2 # Use as dest
la %r2,0(%r4,%r2) # Return dest + n
j .L_Z196_start
END(____mempcpy_z196)
ENTRY(__memcpy_z196)
.machine "z196"
.machinemode "zarch_nohighgprs"
lr %r1,%r2 # r1: Use as dest ; r2: Return dest
.L_Z196_start:
llgfr %r4,%r4
ltgr %r4,%r4
je .L_Z196_4
aghi %r4,-1
lr %r1,%r2
srlg %r5,%r4,8
ltgr %r5,%r5
jne .L_Z196_5
@ -60,13 +69,22 @@ ENTRY(__memcpy_z196)
mvc 0(1,%r1),0(%r3)
END(__memcpy_z196)
ENTRY(____mempcpy_z10)
.machine "z10"
.machinemode "zarch_nohighgprs"
lr %r1,%r2 # Use as dest
la %r2,0(%r4,%r2) # Return dest + n
j .L_Z10_start
END(____mempcpy_z10)
ENTRY(__memcpy_z10)
.machine "z10"
.machinemode "zarch_nohighgprs"
lr %r1,%r2 # r1: Use as dest ; r2: Return dest
.L_Z10_start:
llgfr %r4,%r4
cgije %r4,0,.L_Z10_4
aghi %r4,-1
lr %r1,%r2
srlg %r5,%r4,8
cgijlh %r5,0,.L_Z10_13
.L_Z10_3:
@ -88,14 +106,23 @@ ENTRY(__memcpy_z10)
mvc 0(1,%r1),0(%r3)
END(__memcpy_z10)
# define __mempcpy ____mempcpy_default
#endif /* SHARED && IS_IN (libc) */
#define memcpy __memcpy_default
#include "../memcpy.S"
#undef memcpy
#if defined SHARED && IS_IN (libc)
.globl __GI_memcpy
.set __GI_memcpy,__memcpy_default
.globl __GI_mempcpy
.set __GI_mempcpy,____mempcpy_default
.globl __GI___mempcpy
.set __GI___mempcpy,____mempcpy_default
#else
.globl memcpy
.set memcpy,__memcpy_default
.weak mempcpy
.set mempcpy,__mempcpy
#endif

View file

@ -27,19 +27,27 @@
.text
#ifdef USE_MULTIARCH
ENTRY(__memcpy_default)
#else
ENTRY(memcpy)
#endif
ENTRY(__mempcpy)
.machine "z900"
lgr %r1,%r2 # Use as dest
la %r2,0(%r4,%r2) # Return dest + n
j .L_Z900_start
END(__mempcpy)
#ifndef USE_MULTIARCH
libc_hidden_def (__mempcpy)
weak_alias (__mempcpy, mempcpy)
libc_hidden_builtin_def (mempcpy)
#endif
ENTRY(memcpy)
.machine "z900"
lgr %r1,%r2 # r1: Use as dest ; r2: Return dest
.L_Z900_start:
ltgr %r4,%r4
je .L_Z900_4
aghi %r4,-1
srlg %r5,%r4,8
ltgr %r5,%r5
lgr %r1,%r2
jne .L_Z900_13
.L_Z900_3:
larl %r5,.L_Z900_15
@ -57,25 +65,24 @@ ENTRY(memcpy)
j .L_Z900_3
.L_Z900_15:
mvc 0(1,%r1),0(%r3)
#ifdef USE_MULTIARCH
END(__memcpy_default)
#else
END(memcpy)
#ifndef USE_MULTIARCH
libc_hidden_builtin_def (memcpy)
#endif
ENTRY(__memcpy_mvcle)
# Using as standalone function will result in unexpected
# results since the length field is incremented by 1 in order to
# compensate the changes already done in the functions above.
aghi %r4,1 # length + 1
lgr %r5,%r4 # source length
lgr %r4,%r3 # source address
lgr %r3,%r5 # destination length = source length
# Using as standalone function will result in unexpected
# results since the length field is incremented by 1 in order to
# compensate the changes already done in the functions above.
lgr %r0,%r2 # backup return dest [ + n ]
aghi %r4,1 # length + 1
lgr %r5,%r4 # source length
lgr %r4,%r3 # source address
lgr %r2,%r1 # destination address
lgr %r3,%r5 # destination length = source length
.L_MVCLE_1:
mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L_MVCLE_1
lgr %r2,%r1 # return destination address
br %r14
mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L_MVCLE_1
lgr %r2,%r0 # return destination address
br %r14
END(__memcpy_mvcle)

View file

@ -29,12 +29,20 @@
#if defined SHARED && IS_IN (libc)
ENTRY(____mempcpy_z196)
.machine "z196"
lgr %r1,%r2 # Use as dest
la %r2,0(%r4,%r2) # Return dest + n
j .L_Z196_start
END(____mempcpy_z196)
ENTRY(__memcpy_z196)
.machine "z196"
lgr %r1,%r2 # r1: Use as dest ; r2: Return dest
.L_Z196_start:
ltgr %r4,%r4
je .L_Z196_4
aghi %r4,-1
lgr %r1,%r2
srlg %r5,%r4,8
ltgr %r5,%r5
jne .L_Z196_5
@ -58,11 +66,19 @@ ENTRY(__memcpy_z196)
mvc 0(1,%r1),0(%r3)
END(__memcpy_z196)
ENTRY(____mempcpy_z10)
.machine "z10"
lgr %r1,%r2 # Use as dest
la %r2,0(%r4,%r2) # Return dest + n
j .L_Z10_start
END(____mempcpy_z10)
ENTRY(__memcpy_z10)
.machine "z10"
lgr %r1,%r2 # r1: Use as dest ; r2: Return dest
.L_Z10_start:
cgije %r4,0,.L_Z10_4
aghi %r4,-1
lgr %r1,%r2
srlg %r5,%r4,8
cgijlh %r5,0,.L_Z10_13
.L_Z10_3:
@ -84,14 +100,23 @@ ENTRY(__memcpy_z10)
mvc 0(1,%r1),0(%r3)
END(__memcpy_z10)
# define __mempcpy ____mempcpy_default
#endif /* SHARED && IS_IN (libc) */
#define memcpy __memcpy_default
#include "../memcpy.S"
#undef memcpy
#if defined SHARED && IS_IN (libc)
.globl __GI_memcpy
.set __GI_memcpy,__memcpy_default
.globl __GI_mempcpy
.set __GI_mempcpy,____mempcpy_default
.globl __GI___mempcpy
.set __GI___mempcpy,____mempcpy_default
#else
.globl memcpy
.set memcpy,__memcpy_default
.weak mempcpy
.set mempcpy,__mempcpy
#endif