arrfab / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

Blame SOURCES/glibc-rh1380680-4.patch

147e83
From 53f860e80162b09c44b48f207342c1452289072c Mon Sep 17 00:00:00 2001
147e83
From: Stefan Liebler <stli@linux.vnet.ibm.com>
147e83
Date: Mon, 7 Nov 2016 15:37:29 +0100
147e83
Subject: [PATCH 04/17] S390: Optimize builtin iconv-modules.
147e83
147e83
Upstream commit 3b704e26b33e35d99de920f8462d8e438f89be39
147e83
147e83
This patch introduces a s390 specific gconv_simple.c file which provides
147e83
optimized versions for z13 with vector instructions, which will be chosen at
147e83
runtime via ifunc.
147e83
The optimized conversions can convert between internal and ascii, ucs4, ucs4le,
147e83
ucs2, ucs2le.
147e83
If the build-environment lacks vector support, then iconv/gconv_simple.c
147e83
is used wihtout any change. Otherwise iconvdata/gconv_simple.c is used to create
147e83
conversion loop routines without vector instructions as fallback, if vector
147e83
instructions aren't available at runtime.
147e83
147e83
ChangeLog:
147e83
147e83
	* sysdeps/s390/multiarch/gconv_simple.c: New File.
147e83
	* sysdeps/s390/multiarch/Makefile (sysdep_routines): Add gconv_simple.
147e83
---
147e83
 sysdeps/s390/multiarch/Makefile       |    4 +
147e83
 sysdeps/s390/multiarch/gconv_simple.c | 1266 +++++++++++++++++++++++++++++++++
147e83
 2 files changed, 1270 insertions(+)
147e83
 create mode 100644 sysdeps/s390/multiarch/gconv_simple.c
147e83
147e83
diff --git a/sysdeps/s390/multiarch/Makefile b/sysdeps/s390/multiarch/Makefile
147e83
index 11ad2b9..24949cd 100644
147e83
--- a/sysdeps/s390/multiarch/Makefile
147e83
+++ b/sysdeps/s390/multiarch/Makefile
147e83
@@ -52,3 +52,7 @@ $(move-if-change) $(@:stmp=T) $(@:stmp=h)
147e83
 touch $@
147e83
 endef
147e83
 endif
147e83
+
147e83
+ifeq ($(subdir),iconv)
147e83
+sysdep_routines += gconv_simple
147e83
+endif
147e83
diff --git a/sysdeps/s390/multiarch/gconv_simple.c b/sysdeps/s390/multiarch/gconv_simple.c
147e83
new file mode 100644
147e83
index 0000000..dc53a48
147e83
--- /dev/null
147e83
+++ b/sysdeps/s390/multiarch/gconv_simple.c
147e83
@@ -0,0 +1,1266 @@
147e83
+/* Simple transformations functions - s390 version.
147e83
+   Copyright (C) 2016 Free Software Foundation, Inc.
147e83
+   This file is part of the GNU C Library.
147e83
+
147e83
+   The GNU C Library is free software; you can redistribute it and/or
147e83
+   modify it under the terms of the GNU Lesser General Public
147e83
+   License as published by the Free Software Foundation; either
147e83
+   version 2.1 of the License, or (at your option) any later version.
147e83
+
147e83
+   The GNU C Library is distributed in the hope that it will be useful,
147e83
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
147e83
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147e83
+   Lesser General Public License for more details.
147e83
+
147e83
+   You should have received a copy of the GNU Lesser General Public
147e83
+   License along with the GNU C Library; if not, see
147e83
+   <http://www.gnu.org/licenses/>.  */
147e83
+
147e83
+#if defined HAVE_S390_VX_ASM_SUPPORT
147e83
+# include <ifunc-resolve.h>
147e83
+
147e83
+# if defined HAVE_S390_VX_GCC_SUPPORT
147e83
+#  define ASM_CLOBBER_VR(NR) , NR
147e83
+# else
147e83
+#  define ASM_CLOBBER_VR(NR)
147e83
+# endif
147e83
+
147e83
+# define ICONV_C_NAME(NAME) __##NAME##_c
147e83
+# define ICONV_VX_NAME(NAME) __##NAME##_vx
147e83
+# define ICONV_VX_IFUNC(FUNC)						\
147e83
+  extern __typeof (ICONV_C_NAME (FUNC)) __##FUNC;			\
147e83
+  s390_vx_libc_ifunc (__##FUNC)						\
147e83
+  int FUNC (struct __gconv_step *step, struct __gconv_step_data *data,	\
147e83
+	    const unsigned char **inptrp, const unsigned char *inend,	\
147e83
+	    unsigned char **outbufstart, size_t *irreversible,		\
147e83
+	    int do_flush, int consume_incomplete)			\
147e83
+  {									\
147e83
+    return __##FUNC (step, data, inptrp, inend,outbufstart,		\
147e83
+		     irreversible, do_flush, consume_incomplete);	\
147e83
+  }
147e83
+# define ICONV_VX_SINGLE(NAME)						\
147e83
+  static __typeof (NAME##_single) __##NAME##_vx_single __attribute__((alias(#NAME "_single")));
147e83
+
147e83
+/* Generate the transformations which are used, if the target machine does not
147e83
+   support vector instructions.  */
147e83
+# define __gconv_transform_ascii_internal		\
147e83
+  ICONV_C_NAME (__gconv_transform_ascii_internal)
147e83
+# define __gconv_transform_internal_ascii		\
147e83
+  ICONV_C_NAME (__gconv_transform_internal_ascii)
147e83
+# define __gconv_transform_internal_ucs4le		\
147e83
+  ICONV_C_NAME (__gconv_transform_internal_ucs4le)
147e83
+# define __gconv_transform_ucs4_internal		\
147e83
+  ICONV_C_NAME (__gconv_transform_ucs4_internal)
147e83
+# define __gconv_transform_ucs4le_internal		\
147e83
+  ICONV_C_NAME (__gconv_transform_ucs4le_internal)
147e83
+# define __gconv_transform_ucs2_internal		\
147e83
+  ICONV_C_NAME (__gconv_transform_ucs2_internal)
147e83
+# define __gconv_transform_ucs2reverse_internal		\
147e83
+  ICONV_C_NAME (__gconv_transform_ucs2reverse_internal)
147e83
+# define __gconv_transform_internal_ucs2		\
147e83
+  ICONV_C_NAME (__gconv_transform_internal_ucs2)
147e83
+# define __gconv_transform_internal_ucs2reverse		\
147e83
+  ICONV_C_NAME (__gconv_transform_internal_ucs2reverse)
147e83
+
147e83
+
147e83
+# include <iconv/gconv_simple.c>
147e83
+
147e83
+# undef __gconv_transform_ascii_internal
147e83
+# undef __gconv_transform_internal_ascii
147e83
+# undef __gconv_transform_internal_ucs4le
147e83
+# undef __gconv_transform_ucs4_internal
147e83
+# undef __gconv_transform_ucs4le_internal
147e83
+# undef __gconv_transform_ucs2_internal
147e83
+# undef __gconv_transform_ucs2reverse_internal
147e83
+# undef __gconv_transform_internal_ucs2
147e83
+# undef __gconv_transform_internal_ucs2reverse
147e83
+
147e83
+/* Now define the functions with vector support.  */
147e83
+# if defined __s390x__
147e83
+#  define CONVERT_32BIT_SIZE_T(REG)
147e83
+# else
147e83
+#  define CONVERT_32BIT_SIZE_T(REG) "llgfr %" #REG ",%" #REG "\n\t"
147e83
+# endif
147e83
+
147e83
+/* Convert from ISO 646-IRV to the internal (UCS4-like) format.  */
147e83
+# define DEFINE_INIT		0
147e83
+# define DEFINE_FINI		0
147e83
+# define MIN_NEEDED_FROM	1
147e83
+# define MIN_NEEDED_TO		4
147e83
+# define FROM_DIRECTION		1
147e83
+# define FROM_LOOP		ICONV_VX_NAME (ascii_internal_loop)
147e83
+# define TO_LOOP		ICONV_VX_NAME (ascii_internal_loop) /* This is not used.  */
147e83
+# define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ascii_internal)
147e83
+# define ONE_DIRECTION		1
147e83
+
147e83
+# define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
147e83
+# define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
147e83
+# define LOOPFCT		FROM_LOOP
147e83
+# define BODY_ORIG_ERROR						\
147e83
+    /* The value is too large.  We don't try transliteration here since \
147e83
+       this is not an error because of the lack of possibilities to	\
147e83
+       represent the result.  This is a genuine bug in the input since	\
147e83
+       ASCII does not allow such values.  */				\
147e83
+    STANDARD_FROM_LOOP_ERR_HANDLER (1);
147e83
+
147e83
+# define BODY_ORIG							\
147e83
+  {									\
147e83
+    if (__glibc_unlikely (*inptr > '\x7f'))				\
147e83
+      {									\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+    else								\
147e83
+      {									\
147e83
+	/* It's an one byte sequence.  */				\
147e83
+	*((uint32_t *) outptr) = *inptr++;				\
147e83
+	outptr += sizeof (uint32_t);					\
147e83
+      }									\
147e83
+  }
147e83
+# define BODY								\
147e83
+  {									\
147e83
+    size_t len = inend - inptr;						\
147e83
+    if (len > (outend - outptr) / 4)					\
147e83
+      len = (outend - outptr) / 4;					\
147e83
+    size_t loop_count, tmp;						\
147e83
+    __asm__ volatile (".machine push\n\t"				\
147e83
+		      ".machine \"z13\"\n\t"				\
147e83
+		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
147e83
+		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
147e83
+		      "    vrepib %%v30,0x7f\n\t" /* For compare > 0x7f.  */ \
147e83
+		      "    srlg %[R_LI],%[R_LEN],4\n\t"			\
147e83
+		      "    vrepib %%v31,0x20\n\t"			\
147e83
+		      "    clgije %[R_LI],0,1f\n\t"			\
147e83
+		      "0:  \n\t" /* Handle 16-byte blocks.  */		\
147e83
+		      "    vl %%v16,0(%[R_IN])\n\t"			\
147e83
+		      /* Checking for values > 0x7f.  */		\
147e83
+		      "    vstrcbs %%v17,%%v16,%%v30,%%v31\n\t"		\
147e83
+		      "    jno 10f\n\t"					\
147e83
+		      /* Enlarge to UCS4.  */				\
147e83
+		      "    vuplhb %%v17,%%v16\n\t"			\
147e83
+		      "    vupllb %%v18,%%v16\n\t"			\
147e83
+		      "    vuplhh %%v19,%%v17\n\t"			\
147e83
+		      "    vupllh %%v20,%%v17\n\t"			\
147e83
+		      "    vuplhh %%v21,%%v18\n\t"			\
147e83
+		      "    vupllh %%v22,%%v18\n\t"			\
147e83
+		      /* Store 64bytes to buf_out.  */			\
147e83
+		      "    vstm %%v19,%%v22,0(%[R_OUT])\n\t"		\
147e83
+		      "    la %[R_IN],16(%[R_IN])\n\t"			\
147e83
+		      "    la %[R_OUT],64(%[R_OUT])\n\t"		\
147e83
+		      "    brctg %[R_LI],0b\n\t"			\
147e83
+		      "    lghi %[R_LI],15\n\t"				\
147e83
+		      "    ngr %[R_LEN],%[R_LI]\n\t"			\
147e83
+		      "    je 20f\n\t" /* Jump away if no remaining bytes.  */ \
147e83
+		      /* Handle remaining bytes.  */			\
147e83
+		      "1: aghik %[R_LI],%[R_LEN],-1\n\t"		\
147e83
+		      "    jl 20f\n\t" /* Jump away if no remaining bytes.  */ \
147e83
+		      "    vll %%v16,%[R_LI],0(%[R_IN])\n\t"		\
147e83
+		      /* Checking for values > 0x7f.  */		\
147e83
+		      "    vstrcbs %%v17,%%v16,%%v30,%%v31\n\t"		\
147e83
+		      "    vlgvb %[R_TMP],%%v17,7\n\t"			\
147e83
+		      "    clr %[R_TMP],%[R_LI]\n\t"			\
147e83
+		      "    locrh %[R_TMP],%[R_LEN]\n\t"			\
147e83
+		      "    locghih %[R_LEN],0\n\t"			\
147e83
+		      "    j 12f\n\t"					\
147e83
+		      "10:\n\t"						\
147e83
+		      /* Found a value > 0x7f.				\
147e83
+			 Store the preceding chars.  */			\
147e83
+		      "    vlgvb %[R_TMP],%%v17,7\n\t"			\
147e83
+		      "12: la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
147e83
+		      "    sllk %[R_TMP],%[R_TMP],2\n\t"		\
147e83
+		      "    ahi %[R_TMP],-1\n\t"				\
147e83
+		      "    jl 20f\n\t"					\
147e83
+		      "    lgr %[R_LI],%[R_TMP]\n\t"			\
147e83
+		      "    vuplhb %%v17,%%v16\n\t"			\
147e83
+		      "    vuplhh %%v19,%%v17\n\t"			\
147e83
+		      "    vstl %%v19,%[R_LI],0(%[R_OUT])\n\t"		\
147e83
+		      "    ahi %[R_LI],-16\n\t"				\
147e83
+		      "    jl 11f\n\t"					\
147e83
+		      "    vupllh %%v20,%%v17\n\t"			\
147e83
+		      "    vstl %%v20,%[R_LI],16(%[R_OUT])\n\t"		\
147e83
+		      "    ahi %[R_LI],-16\n\t"				\
147e83
+		      "    jl 11f\n\t"					\
147e83
+		      "    vupllb %%v18,%%v16\n\t"			\
147e83
+		      "    vuplhh %%v21,%%v18\n\t"			\
147e83
+		      "    vstl %%v21,%[R_LI],32(%[R_OUT])\n\t"		\
147e83
+		      "    ahi %[R_LI],-16\n\t"				\
147e83
+		      "    jl 11f\n\t"					\
147e83
+		      "    vupllh %%v22,%%v18\n\t"			\
147e83
+		      "    vstl %%v22,%[R_LI],48(%[R_OUT])\n\t"		\
147e83
+		      "11:\n\t"						\
147e83
+		      "    la %[R_OUT],1(%[R_TMP],%[R_OUT])\n\t"	\
147e83
+		      "20:\n\t"						\
147e83
+		      ".machine pop"					\
147e83
+		      : /* outputs */ [R_OUT] "+a" (outptr)		\
147e83
+			, [R_IN] "+a" (inptr)				\
147e83
+			, [R_LEN] "+d" (len)				\
147e83
+			, [R_LI] "=d" (loop_count)			\
147e83
+			, [R_TMP] "=a" (tmp)				\
147e83
+		      : /* inputs */					\
147e83
+		      : /* clobber list*/ "memory", "cc"		\
147e83
+			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
147e83
+			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
147e83
+			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
147e83
+			ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v30")	\
147e83
+			ASM_CLOBBER_VR ("v31")				\
147e83
+		      );						\
147e83
+    if (len > 0)							\
147e83
+      {									\
147e83
+	/* Found an invalid character at the next input byte.  */	\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+  }
147e83
+
147e83
+# define LOOP_NEED_FLAGS
147e83
+# include <iconv/loop.c>
147e83
+# include <iconv/skeleton.c>
147e83
+# undef BODY_ORIG
147e83
+# undef BODY_ORIG_ERROR
147e83
+ICONV_VX_IFUNC (__gconv_transform_ascii_internal)
147e83
+
147e83
+/* Convert from the internal (UCS4-like) format to ISO 646-IRV.  */
147e83
+# define DEFINE_INIT		0
147e83
+# define DEFINE_FINI		0
147e83
+# define MIN_NEEDED_FROM	4
147e83
+# define MIN_NEEDED_TO		1
147e83
+# define FROM_DIRECTION		1
147e83
+# define FROM_LOOP		ICONV_VX_NAME (internal_ascii_loop)
147e83
+# define TO_LOOP		ICONV_VX_NAME (internal_ascii_loop) /* This is not used.  */
147e83
+# define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ascii)
147e83
+# define ONE_DIRECTION		1
147e83
+
147e83
+# define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
147e83
+# define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
147e83
+# define LOOPFCT		FROM_LOOP
147e83
+# define BODY_ORIG_ERROR						\
147e83
+  UNICODE_TAG_HANDLER (*((const uint32_t *) inptr), 4);			\
147e83
+  STANDARD_TO_LOOP_ERR_HANDLER (4);
147e83
+
147e83
+# define BODY_ORIG							\
147e83
+  {									\
147e83
+    if (__glibc_unlikely (*((const uint32_t *) inptr) > 0x7f))		\
147e83
+      {									\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+    else								\
147e83
+      {									\
147e83
+	/* It's an one byte sequence.  */				\
147e83
+	*outptr++ = *((const uint32_t *) inptr);			\
147e83
+	inptr += sizeof (uint32_t);					\
147e83
+      }									\
147e83
+  }
147e83
+# define BODY								\
147e83
+  {									\
147e83
+    size_t len = (inend - inptr) / 4;					\
147e83
+    if (len > outend - outptr)						\
147e83
+      len = outend - outptr;						\
147e83
+    size_t loop_count, tmp, tmp2;					\
147e83
+    __asm__ volatile (".machine push\n\t"				\
147e83
+		      ".machine \"z13\"\n\t"				\
147e83
+		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
147e83
+		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
147e83
+		      /* Setup to check for ch > 0x7f.  */		\
147e83
+		      "    vzero %%v21\n\t"				\
147e83
+		      "    srlg %[R_LI],%[R_LEN],4\n\t"			\
147e83
+		      "    vleih %%v21,8192,0\n\t"  /* element 0:   >  */ \
147e83
+		      "    vleih %%v21,-8192,2\n\t" /* element 1: =<>  */ \
147e83
+		      "    vleif %%v20,127,0\n\t"   /* element 0: 127  */ \
147e83
+		      "    lghi %[R_TMP],0\n\t"				\
147e83
+		      "    clgije %[R_LI],0,1f\n\t"			\
147e83
+		      "0:\n\t"						\
147e83
+		      "    vlm %%v16,%%v19,0(%[R_IN])\n\t"		\
147e83
+		      /* Shorten to byte values.  */			\
147e83
+		      "    vpkf %%v23,%%v16,%%v17\n\t"			\
147e83
+		      "    vpkf %%v24,%%v18,%%v19\n\t"			\
147e83
+		      "    vpkh %%v23,%%v23,%%v24\n\t"			\
147e83
+		      /* Checking for values > 0x7f.  */		\
147e83
+		      "    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"		\
147e83
+		      "    jno 10f\n\t"					\
147e83
+		      "    vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
147e83
+		      "    jno 11f\n\t"					\
147e83
+		      "    vstrcfs %%v22,%%v18,%%v20,%%v21\n\t"		\
147e83
+		      "    jno 12f\n\t"					\
147e83
+		      "    vstrcfs %%v22,%%v19,%%v20,%%v21\n\t"		\
147e83
+		      "    jno 13f\n\t"					\
147e83
+		      /* Store 16bytes to outptr.  */			\
147e83
+		      "    vst %%v23,0(%[R_OUT])\n\t"			\
147e83
+		      "    la %[R_IN],64(%[R_IN])\n\t"			\
147e83
+		      "    la %[R_OUT],16(%[R_OUT])\n\t"		\
147e83
+		      "    brctg %[R_LI],0b\n\t"			\
147e83
+		      "    lghi %[R_LI],15\n\t"				\
147e83
+		      "    ngr %[R_LEN],%[R_LI]\n\t"			\
147e83
+		      "    je 20f\n\t" /* Jump away if no remaining bytes.  */ \
147e83
+		      /* Handle remaining bytes.  */			\
147e83
+		      "1: sllg %[R_LI],%[R_LEN],2\n\t"			\
147e83
+		      "    aghi %[R_LI],-1\n\t"				\
147e83
+		      "    jl 20f\n\t" /* Jump away if no remaining bytes.  */ \
147e83
+		      /* Load remaining 1...63 bytes.  */		\
147e83
+		      "    vll %%v16,%[R_LI],0(%[R_IN])\n\t"		\
147e83
+		      "    ahi %[R_LI],-16\n\t"				\
147e83
+		      "    jl 2f\n\t"					\
147e83
+		      "    vll %%v17,%[R_LI],16(%[R_IN])\n\t"		\
147e83
+		      "    ahi %[R_LI],-16\n\t"				\
147e83
+		      "    jl 2f\n\t"					\
147e83
+		      "    vll %%v18,%[R_LI],32(%[R_IN])\n\t"		\
147e83
+		      "    ahi %[R_LI],-16\n\t"				\
147e83
+		      "    jl 2f\n\t"					\
147e83
+		      "    vll %%v19,%[R_LI],48(%[R_IN])\n\t"		\
147e83
+		      "2:\n\t"						\
147e83
+		      /* Shorten to byte values.  */			\
147e83
+		      "    vpkf %%v23,%%v16,%%v17\n\t"			\
147e83
+		      "    vpkf %%v24,%%v18,%%v19\n\t"			\
147e83
+		      "    vpkh %%v23,%%v23,%%v24\n\t"			\
147e83
+		      "    sllg %[R_LI],%[R_LEN],2\n\t"			\
147e83
+		      "    aghi %[R_LI],-16\n\t"			\
147e83
+		      "    jl 3f\n\t" /* v16 is not fully loaded.  */	\
147e83
+		      "    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"		\
147e83
+		      "    jno 10f\n\t"					\
147e83
+		      "    aghi %[R_LI],-16\n\t"			\
147e83
+		      "    jl 4f\n\t" /* v17 is not fully loaded.  */	\
147e83
+		      "    vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
147e83
+		      "    jno 11f\n\t"					\
147e83
+		      "    aghi %[R_LI],-16\n\t"			\
147e83
+		      "    jl 5f\n\t" /* v18 is not fully loaded.  */	\
147e83
+		      "    vstrcfs %%v22,%%v18,%%v20,%%v21\n\t"		\
147e83
+		      "    jno 12f\n\t"					\
147e83
+		      "    aghi %[R_LI],-16\n\t"			\
147e83
+		      /* v19 is not fully loaded. */			\
147e83
+		      "    lghi %[R_TMP],12\n\t"			\
147e83
+		      "    vstrcfs %%v22,%%v19,%%v20,%%v21\n\t"		\
147e83
+		      "6: vlgvb %[R_I],%%v22,7\n\t"			\
147e83
+		      "    aghi %[R_LI],16\n\t"				\
147e83
+		      "    clrjl %[R_I],%[R_LI],14f\n\t"		\
147e83
+		      "    lgr %[R_I],%[R_LEN]\n\t"			\
147e83
+		      "    lghi %[R_LEN],0\n\t"				\
147e83
+		      "    j 15f\n\t"					\
147e83
+		      "3: vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"		\
147e83
+		      "    j 6b\n\t"					\
147e83
+		      "4: vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
147e83
+		      "    lghi %[R_TMP],4\n\t"				\
147e83
+		      "    j 6b\n\t"					\
147e83
+		      "5: vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
147e83
+		      "    lghi %[R_TMP],8\n\t"				\
147e83
+		      "    j 6b\n\t"					\
147e83
+		      /* Found a value > 0x7f.  */			\
147e83
+		      "13: ahi %[R_TMP],4\n\t"				\
147e83
+		      "12: ahi %[R_TMP],4\n\t"				\
147e83
+		      "11: ahi %[R_TMP],4\n\t"				\
147e83
+		      "10: vlgvb %[R_I],%%v22,7\n\t"			\
147e83
+		      "14: srlg %[R_I],%[R_I],2\n\t"			\
147e83
+		      "    agr %[R_I],%[R_TMP]\n\t"			\
147e83
+		      "    je 20f\n\t"					\
147e83
+		      /* Store characters before invalid one...  */	\
147e83
+		      "15: aghi %[R_I],-1\n\t"				\
147e83
+		      "    vstl %%v23,%[R_I],0(%[R_OUT])\n\t"		\
147e83
+		      /* ... and update pointers.  */			\
147e83
+		      "    la %[R_OUT],1(%[R_I],%[R_OUT])\n\t"		\
147e83
+		      "    sllg %[R_I],%[R_I],2\n\t"			\
147e83
+		      "    la %[R_IN],4(%[R_I],%[R_IN])\n\t"		\
147e83
+		      "20:\n\t"						\
147e83
+		      ".machine pop"					\
147e83
+		      : /* outputs */ [R_OUT] "+a" (outptr)		\
147e83
+			, [R_IN] "+a" (inptr)				\
147e83
+			, [R_LEN] "+d" (len)				\
147e83
+			, [R_LI] "=d" (loop_count)			\
147e83
+			, [R_I] "=a" (tmp2)				\
147e83
+			, [R_TMP] "=d" (tmp)				\
147e83
+		      : /* inputs */					\
147e83
+		      : /* clobber list*/ "memory", "cc"		\
147e83
+			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
147e83
+			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
147e83
+			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
147e83
+			ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v23")	\
147e83
+			ASM_CLOBBER_VR ("v24")				\
147e83
+		      );						\
147e83
+    if (len > 0)							\
147e83
+      {									\
147e83
+	/* Found an invalid character > 0x7f at next character.  */	\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+  }
147e83
+# define LOOP_NEED_FLAGS
147e83
+# include <iconv/loop.c>
147e83
+# include <iconv/skeleton.c>
147e83
+# undef BODY_ORIG
147e83
+# undef BODY_ORIG_ERROR
147e83
+ICONV_VX_IFUNC (__gconv_transform_internal_ascii)
147e83
+
147e83
+
147e83
+/* Convert from internal UCS4 to UCS4 little endian form.  */
147e83
+# define DEFINE_INIT		0
147e83
+# define DEFINE_FINI		0
147e83
+# define MIN_NEEDED_FROM	4
147e83
+# define MIN_NEEDED_TO		4
147e83
+# define FROM_DIRECTION		1
147e83
+# define FROM_LOOP		ICONV_VX_NAME (internal_ucs4le_loop)
147e83
+# define TO_LOOP		ICONV_VX_NAME (internal_ucs4le_loop) /* This is not used.  */
147e83
+# define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ucs4le)
147e83
+# define ONE_DIRECTION		0
147e83
+
147e83
+static inline int
147e83
+__attribute ((always_inline))
147e83
+ICONV_VX_NAME (internal_ucs4le_loop) (struct __gconv_step *step,
147e83
+				      struct __gconv_step_data *step_data,
147e83
+				      const unsigned char **inptrp,
147e83
+				      const unsigned char *inend,
147e83
+				      unsigned char **outptrp,
147e83
+				      unsigned char *outend,
147e83
+				      size_t *irreversible)
147e83
+{
147e83
+  const unsigned char *inptr = *inptrp;
147e83
+  unsigned char *outptr = *outptrp;
147e83
+  int result;
147e83
+  size_t len = MIN (inend - inptr, outend - outptr) / 4;
147e83
+  size_t loop_count;
147e83
+  __asm__ volatile (".machine push\n\t"
147e83
+		    ".machine \"z13\"\n\t"
147e83
+		    ".machinemode \"zarch_nohighgprs\"\n\t"
147e83
+		    CONVERT_32BIT_SIZE_T ([R_LEN])
147e83
+		    "    bras %[R_LI],1f\n\t"
147e83
+		    /* Vector permute mask:  */
147e83
+		    "    .long 0x03020100,0x7060504,0x0B0A0908,0x0F0E0D0C\n\t"
147e83
+		    "1:  vl %%v20,0(%[R_LI])\n\t"
147e83
+		    /* Process 64byte (16char) blocks.  */
147e83
+		    "    srlg %[R_LI],%[R_LEN],4\n\t"
147e83
+		    "    clgije %[R_LI],0,10f\n\t"
147e83
+		    "0:  vlm %%v16,%%v19,0(%[R_IN])\n\t"
147e83
+		    "    vperm %%v16,%%v16,%%v16,%%v20\n\t"
147e83
+		    "    vperm %%v17,%%v17,%%v17,%%v20\n\t"
147e83
+		    "    vperm %%v18,%%v18,%%v18,%%v20\n\t"
147e83
+		    "    vperm %%v19,%%v19,%%v19,%%v20\n\t"
147e83
+		    "    vstm %%v16,%%v19,0(%[R_OUT])\n\t"
147e83
+		    "    la %[R_IN],64(%[R_IN])\n\t"
147e83
+		    "    la %[R_OUT],64(%[R_OUT])\n\t"
147e83
+		    "    brctg %[R_LI],0b\n\t"
147e83
+		    "    llgfr %[R_LEN],%[R_LEN]\n\t"
147e83
+		    "    nilf %[R_LEN],15\n\t"
147e83
+		    /* Process 16byte (4char) blocks.  */
147e83
+		    "10: srlg %[R_LI],%[R_LEN],2\n\t"
147e83
+		    "    clgije %[R_LI],0,20f\n\t"
147e83
+		    "11: vl %%v16,0(%[R_IN])\n\t"
147e83
+		    "    vperm %%v16,%%v16,%%v16,%%v20\n\t"
147e83
+		    "    vst %%v16,0(%[R_OUT])\n\t"
147e83
+		    "    la %[R_IN],16(%[R_IN])\n\t"
147e83
+		    "    la %[R_OUT],16(%[R_OUT])\n\t"
147e83
+		    "    brctg %[R_LI],11b\n\t"
147e83
+		    "    nill %[R_LEN],3\n\t"
147e83
+		    /* Process <16bytes.  */
147e83
+		    "20: sll %[R_LEN],2\n\t"
147e83
+		    "    ahi %[R_LEN],-1\n\t"
147e83
+		    "    jl 30f\n\t"
147e83
+		    "    vll %%v16,%[R_LEN],0(%[R_IN])\n\t"
147e83
+		    "    vperm %%v16,%%v16,%%v16,%%v20\n\t"
147e83
+		    "    vstl %%v16,%[R_LEN],0(%[R_OUT])\n\t"
147e83
+		    "    la %[R_IN],1(%[R_LEN],%[R_IN])\n\t"
147e83
+		    "    la %[R_OUT],1(%[R_LEN],%[R_OUT])\n\t"
147e83
+		    "30: \n\t"
147e83
+		    ".machine pop"
147e83
+		    : /* outputs */ [R_OUT] "+a" (outptr)
147e83
+		      , [R_IN] "+a" (inptr)
147e83
+		      , [R_LI] "=a" (loop_count)
147e83
+		      , [R_LEN] "+a" (len)
147e83
+		    : /* inputs */
147e83
+		    : /* clobber list*/ "memory", "cc"
147e83
+		      ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")
147e83
+		      ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")
147e83
+		      ASM_CLOBBER_VR ("v20")
147e83
+		    );
147e83
+  *inptrp = inptr;
147e83
+  *outptrp = outptr;
147e83
+
147e83
+  /* Determine the status.  */
147e83
+  if (*inptrp == inend)
147e83
+    result = __GCONV_EMPTY_INPUT;
147e83
+  else if (*outptrp + 4 > outend)
147e83
+    result = __GCONV_FULL_OUTPUT;
147e83
+  else
147e83
+    result = __GCONV_INCOMPLETE_INPUT;
147e83
+
147e83
+  return result;
147e83
+}
147e83
+
147e83
+ICONV_VX_SINGLE (internal_ucs4le_loop)
147e83
+# include <iconv/skeleton.c>
147e83
+ICONV_VX_IFUNC (__gconv_transform_internal_ucs4le)
147e83
+
147e83
+
147e83
+/* Transform from UCS4 to the internal, UCS4-like format.  Unlike
147e83
+   for the other direction we have to check for correct values here.  */
147e83
+# define DEFINE_INIT		0
147e83
+# define DEFINE_FINI		0
147e83
+# define MIN_NEEDED_FROM	4
147e83
+# define MIN_NEEDED_TO		4
147e83
+# define FROM_DIRECTION		1
147e83
+# define FROM_LOOP		ICONV_VX_NAME (ucs4_internal_loop)
147e83
+# define TO_LOOP		ICONV_VX_NAME (ucs4_internal_loop) /* This is not used.  */
147e83
+# define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs4_internal)
147e83
+# define ONE_DIRECTION		0
147e83
+
147e83
+
147e83
+static inline int
147e83
+__attribute ((always_inline))
147e83
+ICONV_VX_NAME (ucs4_internal_loop) (struct __gconv_step *step,
147e83
+				    struct __gconv_step_data *step_data,
147e83
+				    const unsigned char **inptrp,
147e83
+				    const unsigned char *inend,
147e83
+				    unsigned char **outptrp,
147e83
+				    unsigned char *outend,
147e83
+				    size_t *irreversible)
147e83
+{
147e83
+  int flags = step_data->__flags;
147e83
+  const unsigned char *inptr = *inptrp;
147e83
+  unsigned char *outptr = *outptrp;
147e83
+  int result;
147e83
+  size_t len, loop_count;
147e83
+  do
147e83
+    {
147e83
+      len = MIN (inend - inptr, outend - outptr) / 4;
147e83
+      __asm__ volatile (".machine push\n\t"
147e83
+			".machine \"z13\"\n\t"
147e83
+			".machinemode \"zarch_nohighgprs\"\n\t"
147e83
+			CONVERT_32BIT_SIZE_T ([R_LEN])
147e83
+			/* Setup to check for ch > 0x7fffffff.  */
147e83
+			"    larl %[R_LI],9f\n\t"
147e83
+			"    vlm %%v20,%%v21,0(%[R_LI])\n\t"
147e83
+			"    srlg %[R_LI],%[R_LEN],2\n\t"
147e83
+			"    clgije %[R_LI],0,1f\n\t"
147e83
+			/* Process 16byte (4char) blocks.  */
147e83
+			"0:  vl %%v16,0(%[R_IN])\n\t"
147e83
+			"    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"
147e83
+			"    jno 10f\n\t"
147e83
+			"    vst %%v16,0(%[R_OUT])\n\t"
147e83
+			"    la %[R_IN],16(%[R_IN])\n\t"
147e83
+			"    la %[R_OUT],16(%[R_OUT])\n\t"
147e83
+			"    brctg %[R_LI],0b\n\t"
147e83
+			"    llgfr %[R_LEN],%[R_LEN]\n\t"
147e83
+			"    nilf %[R_LEN],3\n\t"
147e83
+			/* Process <16bytes.  */
147e83
+			"1:  sll %[R_LEN],2\n\t"
147e83
+			"    ahik %[R_LI],%[R_LEN],-1\n\t"
147e83
+			"    jl 20f\n\t" /* No further bytes available.  */
147e83
+			"    vll %%v16,%[R_LI],0(%[R_IN])\n\t"
147e83
+			"    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"
147e83
+			"    vlgvb %[R_LI],%%v22,7\n\t"
147e83
+			"    clr %[R_LI],%[R_LEN]\n\t"
147e83
+			"    locgrhe %[R_LI],%[R_LEN]\n\t"
147e83
+			"    locghihe %[R_LEN],0\n\t"
147e83
+			"    j 11f\n\t"
147e83
+			/* v20: Vector string range compare values.  */
147e83
+			"9:  .long 0x7fffffff,0x0,0x0,0x0\n\t"
147e83
+			/* v21: Vector string range compare control-bits.
147e83
+			   element 0: >; element 1: =<> (always true)  */
147e83
+			"    .long 0x20000000,0xE0000000,0x0,0x0\n\t"
147e83
+			/* Found a value > 0x7fffffff.  */
147e83
+			"10: vlgvb %[R_LI],%%v22,7\n\t"
147e83
+			/* Store characters before invalid one.  */
147e83
+			"11: aghi %[R_LI],-1\n\t"
147e83
+			"    jl 20f\n\t"
147e83
+			"    vstl %%v16,%[R_LI],0(%[R_OUT])\n\t"
147e83
+			"    la %[R_IN],1(%[R_LI],%[R_IN])\n\t"
147e83
+			"    la %[R_OUT],1(%[R_LI],%[R_OUT])\n\t"
147e83
+			"20:\n\t"
147e83
+			".machine pop"
147e83
+			: /* outputs */ [R_OUT] "+a" (outptr)
147e83
+			  , [R_IN] "+a" (inptr)
147e83
+			  , [R_LI] "=a" (loop_count)
147e83
+			  , [R_LEN] "+d" (len)
147e83
+			: /* inputs */
147e83
+			: /* clobber list*/ "memory", "cc"
147e83
+			  ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v20")
147e83
+			  ASM_CLOBBER_VR ("v21") ASM_CLOBBER_VR ("v22")
147e83
+			);
147e83
+      if (len > 0)
147e83
+	{
147e83
+	  /* The value is too large.  We don't try transliteration here since
147e83
+	     this is not an error because of the lack of possibilities to
147e83
+	     represent the result.  This is a genuine bug in the input since
147e83
+	     UCS4 does not allow such values.  */
147e83
+	  if (irreversible == NULL)
147e83
+	    /* We are transliterating, don't try to correct anything.  */
147e83
+	    return __GCONV_ILLEGAL_INPUT;
147e83
+
147e83
+	  if (flags & __GCONV_IGNORE_ERRORS)
147e83
+	    {
147e83
+	      /* Just ignore this character.  */
147e83
+	      ++*irreversible;
147e83
+	      inptr += 4;
147e83
+	      continue;
147e83
+	    }
147e83
+
147e83
+	  *inptrp = inptr;
147e83
+	  *outptrp = outptr;
147e83
+	  return __GCONV_ILLEGAL_INPUT;
147e83
+	}
147e83
+    }
147e83
+  while (len > 0);
147e83
+
147e83
+  *inptrp = inptr;
147e83
+  *outptrp = outptr;
147e83
+
147e83
+  /* Determine the status.  */
147e83
+  if (*inptrp == inend)
147e83
+    result = __GCONV_EMPTY_INPUT;
147e83
+  else if (*outptrp + 4 > outend)
147e83
+    result = __GCONV_FULL_OUTPUT;
147e83
+  else
147e83
+    result = __GCONV_INCOMPLETE_INPUT;
147e83
+
147e83
+  return result;
147e83
+}
147e83
+
147e83
+ICONV_VX_SINGLE (ucs4_internal_loop)
147e83
+# include <iconv/skeleton.c>
147e83
+ICONV_VX_IFUNC (__gconv_transform_ucs4_internal)
147e83
+
147e83
+
147e83
+/* Transform from UCS4-LE to the internal encoding.  */
147e83
+# define DEFINE_INIT		0
147e83
+# define DEFINE_FINI		0
147e83
+# define MIN_NEEDED_FROM	4
147e83
+# define MIN_NEEDED_TO		4
147e83
+# define FROM_DIRECTION		1
147e83
+# define FROM_LOOP		ICONV_VX_NAME (ucs4le_internal_loop)
147e83
+# define TO_LOOP		ICONV_VX_NAME (ucs4le_internal_loop) /* This is not used.  */
147e83
+# define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs4le_internal)
147e83
+# define ONE_DIRECTION		0
147e83
+
147e83
+static inline int
147e83
+__attribute ((always_inline))
147e83
+ICONV_VX_NAME (ucs4le_internal_loop) (struct __gconv_step *step,
147e83
+				      struct __gconv_step_data *step_data,
147e83
+				      const unsigned char **inptrp,
147e83
+				      const unsigned char *inend,
147e83
+				      unsigned char **outptrp,
147e83
+				      unsigned char *outend,
147e83
+				      size_t *irreversible)
147e83
+{
147e83
+  int flags = step_data->__flags;
147e83
+  const unsigned char *inptr = *inptrp;
147e83
+  unsigned char *outptr = *outptrp;
147e83
+  int result;
147e83
+  size_t len, loop_count;
147e83
+  do
147e83
+    {
147e83
+      len = MIN (inend - inptr, outend - outptr) / 4;
147e83
+      __asm__ volatile (".machine push\n\t"
147e83
+			".machine \"z13\"\n\t"
147e83
+			".machinemode \"zarch_nohighgprs\"\n\t"
147e83
+			CONVERT_32BIT_SIZE_T ([R_LEN])
147e83
+			/* Setup to check for ch > 0x7fffffff.  */
147e83
+			"    larl %[R_LI],9f\n\t"
147e83
+			"    vlm %%v20,%%v22,0(%[R_LI])\n\t"
147e83
+			"    srlg %[R_LI],%[R_LEN],2\n\t"
147e83
+			"    clgije %[R_LI],0,1f\n\t"
147e83
+			/* Process 16byte (4char) blocks.  */
147e83
+			"0:  vl %%v16,0(%[R_IN])\n\t"
147e83
+			"    vperm %%v16,%%v16,%%v16,%%v22\n\t"
147e83
+			"    vstrcfs %%v23,%%v16,%%v20,%%v21\n\t"
147e83
+			"    jno 10f\n\t"
147e83
+			"    vst %%v16,0(%[R_OUT])\n\t"
147e83
+			"    la %[R_IN],16(%[R_IN])\n\t"
147e83
+			"    la %[R_OUT],16(%[R_OUT])\n\t"
147e83
+			"    brctg %[R_LI],0b\n\t"
147e83
+			"    llgfr %[R_LEN],%[R_LEN]\n\t"
147e83
+			"    nilf %[R_LEN],3\n\t"
147e83
+			/* Process <16bytes.  */
147e83
+			"1:  sll %[R_LEN],2\n\t"
147e83
+			"    ahik %[R_LI],%[R_LEN],-1\n\t"
147e83
+			"    jl 20f\n\t" /* No further bytes available.  */
147e83
+			"    vll %%v16,%[R_LI],0(%[R_IN])\n\t"
147e83
+			"    vperm %%v16,%%v16,%%v16,%%v22\n\t"
147e83
+			"    vstrcfs %%v23,%%v16,%%v20,%%v21\n\t"
147e83
+			"    vlgvb %[R_LI],%%v23,7\n\t"
147e83
+			"    clr %[R_LI],%[R_LEN]\n\t"
147e83
+			"    locgrhe %[R_LI],%[R_LEN]\n\t"
147e83
+			"    locghihe %[R_LEN],0\n\t"
147e83
+			"    j 11f\n\t"
147e83
+			/* v20: Vector string range compare values.  */
147e83
+			"9: .long 0x7fffffff,0x0,0x0,0x0\n\t"
147e83
+			/* v21: Vector string range compare control-bits.
147e83
+			   element 0: >; element 1: =<> (always true)  */
147e83
+			"    .long 0x20000000,0xE0000000,0x0,0x0\n\t"
147e83
+			/* v22: Vector permute mask.  */
147e83
+			"    .long 0x03020100,0x7060504,0x0B0A0908,0x0F0E0D0C\n\t"
147e83
+			/* Found a value > 0x7fffffff.  */
147e83
+			"10: vlgvb %[R_LI],%%v23,7\n\t"
147e83
+			/* Store characters before invalid one.  */
147e83
+			"11: aghi %[R_LI],-1\n\t"
147e83
+			"    jl 20f\n\t"
147e83
+			"    vstl %%v16,%[R_LI],0(%[R_OUT])\n\t"
147e83
+			"    la %[R_IN],1(%[R_LI],%[R_IN])\n\t"
147e83
+			"    la %[R_OUT],1(%[R_LI],%[R_OUT])\n\t"
147e83
+			"20:\n\t"
147e83
+			".machine pop"
147e83
+			: /* outputs */ [R_OUT] "+a" (outptr)
147e83
+			  , [R_IN] "+a" (inptr)
147e83
+			  , [R_LI] "=a" (loop_count)
147e83
+			  , [R_LEN] "+d" (len)
147e83
+			: /* inputs */
147e83
+			: /* clobber list*/ "memory", "cc"
147e83
+			  ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v20")
147e83
+			  ASM_CLOBBER_VR ("v21") ASM_CLOBBER_VR ("v22")
147e83
+			  ASM_CLOBBER_VR ("v23")
147e83
+			);
147e83
+      if (len > 0)
147e83
+	{
147e83
+	  /* The value is too large.  We don't try transliteration here since
147e83
+	     this is not an error because of the lack of possibilities to
147e83
+	     represent the result.  This is a genuine bug in the input since
147e83
+	     UCS4 does not allow such values.  */
147e83
+	  if (irreversible == NULL)
147e83
+	    /* We are transliterating, don't try to correct anything.  */
147e83
+	    return __GCONV_ILLEGAL_INPUT;
147e83
+
147e83
+	  if (flags & __GCONV_IGNORE_ERRORS)
147e83
+	    {
147e83
+	      /* Just ignore this character.  */
147e83
+	      ++*irreversible;
147e83
+	      inptr += 4;
147e83
+	      continue;
147e83
+	    }
147e83
+
147e83
+	  *inptrp = inptr;
147e83
+	  *outptrp = outptr;
147e83
+	  return __GCONV_ILLEGAL_INPUT;
147e83
+	}
147e83
+    }
147e83
+  while (len > 0);
147e83
+
147e83
+  *inptrp = inptr;
147e83
+  *outptrp = outptr;
147e83
+
147e83
+  /* Determine the status.  */
147e83
+  if (*inptrp == inend)
147e83
+    result = __GCONV_EMPTY_INPUT;
147e83
+  else if (*inptrp + 4 > inend)
147e83
+    result = __GCONV_INCOMPLETE_INPUT;
147e83
+  else
147e83
+    {
147e83
+      assert (*outptrp + 4 > outend);
147e83
+      result = __GCONV_FULL_OUTPUT;
147e83
+    }
147e83
+
147e83
+  return result;
147e83
+}
147e83
+ICONV_VX_SINGLE (ucs4le_internal_loop)
147e83
+# include <iconv/skeleton.c>
147e83
+ICONV_VX_IFUNC (__gconv_transform_ucs4le_internal)
147e83
+
147e83
+/* Convert from UCS2 to the internal (UCS4-like) format.  */
147e83
+# define DEFINE_INIT		0
147e83
+# define DEFINE_FINI		0
147e83
+# define MIN_NEEDED_FROM	2
147e83
+# define MIN_NEEDED_TO		4
147e83
+# define FROM_DIRECTION		1
147e83
+# define FROM_LOOP		ICONV_VX_NAME (ucs2_internal_loop)
147e83
+# define TO_LOOP		ICONV_VX_NAME (ucs2_internal_loop) /* This is not used.  */
147e83
+# define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs2_internal)
147e83
+# define ONE_DIRECTION		1
147e83
+
147e83
+# define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
147e83
+# define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
147e83
+# define LOOPFCT		FROM_LOOP
147e83
+# define BODY_ORIG_ERROR						\
147e83
+  /* Surrogate characters in UCS-2 input are not valid.  Reject		\
147e83
+     them.  (Catching this here is not security relevant.)  */		\
147e83
+  STANDARD_FROM_LOOP_ERR_HANDLER (2);
147e83
+# define BODY_ORIG							\
147e83
+  {									\
147e83
+    uint16_t u1 = get16 (inptr);					\
147e83
+									\
147e83
+    if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			\
147e83
+      {									\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+									\
147e83
+    *((uint32_t *) outptr) = u1;					\
147e83
+    outptr += sizeof (uint32_t);					\
147e83
+    inptr += 2;								\
147e83
+  }
147e83
+# define BODY								\
147e83
+  {									\
147e83
+    size_t len, tmp, tmp2;						\
147e83
+    len = MIN ((inend - inptr) / 2, (outend - outptr) / 4);		\
147e83
+    __asm__ volatile (".machine push\n\t"				\
147e83
+		      ".machine \"z13\"\n\t"				\
147e83
+		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
147e83
+		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
147e83
+		      /* Setup to check for ch >= 0xd800 && ch < 0xe000.  */ \
147e83
+		      "    larl %[R_TMP],9f\n\t"			\
147e83
+		      "    vlm %%v20,%%v21,0(%[R_TMP])\n\t"		\
147e83
+		      "    srlg %[R_TMP],%[R_LEN],3\n\t"		\
147e83
+		      "    clgije %[R_TMP],0,1f\n\t"			\
147e83
+		      /* Process 16byte (8char) blocks.  */		\
147e83
+		      "0:  vl %%v16,0(%[R_IN])\n\t"			\
147e83
+		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
147e83
+		      /* Enlarge UCS2 to UCS4.  */			\
147e83
+		      "    vuplhh %%v17,%%v16\n\t"			\
147e83
+		      "    vupllh %%v18,%%v16\n\t"			\
147e83
+		      "    jno 10f\n\t"					\
147e83
+		      /* Store 32bytes to buf_out.  */			\
147e83
+		      "    vstm %%v17,%%v18,0(%[R_OUT])\n\t"		\
147e83
+		      "    la %[R_IN],16(%[R_IN])\n\t"			\
147e83
+		      "    la %[R_OUT],32(%[R_OUT])\n\t"		\
147e83
+		      "    brctg %[R_TMP],0b\n\t"			\
147e83
+		      "    llgfr %[R_LEN],%[R_LEN]\n\t"			\
147e83
+		      "    nilf %[R_LEN],7\n\t"				\
147e83
+		      /* Process <16bytes.  */				\
147e83
+		      "1:  sll %[R_LEN],1\n\t"				\
147e83
+		      "    ahik %[R_TMP],%[R_LEN],-1\n\t"		\
147e83
+		      "    jl 20f\n\t" /* No further bytes available.  */ \
147e83
+		      "    vll %%v16,%[R_TMP],0(%[R_IN])\n\t"		\
147e83
+		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
147e83
+		      /* Enlarge UCS2 to UCS4.  */			\
147e83
+		      "    vuplhh %%v17,%%v16\n\t"			\
147e83
+		      "    vupllh %%v18,%%v16\n\t"			\
147e83
+		      "    vlgvb %[R_TMP],%%v19,7\n\t"			\
147e83
+		      "    clr %[R_TMP],%[R_LEN]\n\t"			\
147e83
+		      "    locgrhe %[R_TMP],%[R_LEN]\n\t"		\
147e83
+		      "    locghihe %[R_LEN],0\n\t"			\
147e83
+		      "    j 11f\n\t"					\
147e83
+		      /* v20: Vector string range compare values.  */	\
147e83
+		      "9:  .short 0xd800,0xe000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
147e83
+		      /* v21: Vector string range compare control-bits.	\
147e83
+			 element 0: =>; element 1: <  */		\
147e83
+		      "    .short 0xa000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
147e83
+		      /* Found an element: ch >= 0xd800 && ch < 0xe000  */ \
147e83
+		      "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
147e83
+		      "11: la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
147e83
+		      "    sll %[R_TMP],1\n\t"				\
147e83
+		      "    lgr %[R_TMP2],%[R_TMP]\n\t"			\
147e83
+		      "    ahi %[R_TMP],-1\n\t"				\
147e83
+		      "    jl 20f\n\t"					\
147e83
+		      "    vstl %%v17,%[R_TMP],0(%[R_OUT])\n\t"		\
147e83
+		      "    ahi %[R_TMP],-16\n\t"			\
147e83
+		      "    jl 19f\n\t"					\
147e83
+		      "    vstl %%v18,%[R_TMP],16(%[R_OUT])\n\t"	\
147e83
+		      "19: la %[R_OUT],0(%[R_TMP2],%[R_OUT])\n\t"	\
147e83
+		      "20: \n\t"					\
147e83
+		      ".machine pop"					\
147e83
+		      : /* outputs */ [R_OUT] "+a" (outptr)		\
147e83
+			, [R_IN] "+a" (inptr)				\
147e83
+			, [R_TMP] "=a" (tmp)				\
147e83
+			, [R_TMP2] "=a" (tmp2)				\
147e83
+			, [R_LEN] "+d" (len)				\
147e83
+		      : /* inputs */					\
147e83
+		      : /* clobber list*/ "memory", "cc"		\
147e83
+			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
147e83
+			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
147e83
+			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
147e83
+		      );						\
147e83
+    if (len > 0)							\
147e83
+      {									\
147e83
+	/* Found an invalid character at next input-char.  */		\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+  }
147e83
+
147e83
+# define LOOP_NEED_FLAGS
147e83
+# include <iconv/loop.c>
147e83
+# include <iconv/skeleton.c>
147e83
+# undef BODY_ORIG
147e83
+# undef BODY_ORIG_ERROR
147e83
+ICONV_VX_IFUNC (__gconv_transform_ucs2_internal)
147e83
+
147e83
+/* Convert from UCS2 in other endianness to the internal (UCS4-like) format. */
147e83
+# define DEFINE_INIT		0
147e83
+# define DEFINE_FINI		0
147e83
+# define MIN_NEEDED_FROM	2
147e83
+# define MIN_NEEDED_TO		4
147e83
+# define FROM_DIRECTION		1
147e83
+# define FROM_LOOP		ICONV_VX_NAME (ucs2reverse_internal_loop)
147e83
+# define TO_LOOP		ICONV_VX_NAME (ucs2reverse_internal_loop) /* This is not used.*/
147e83
+# define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs2reverse_internal)
147e83
+# define ONE_DIRECTION		1
147e83
+
147e83
+# define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
147e83
+# define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
147e83
+# define LOOPFCT		FROM_LOOP
147e83
+# define BODY_ORIG_ERROR						\
147e83
+  /* Surrogate characters in UCS-2 input are not valid.  Reject		\
147e83
+     them.  (Catching this here is not security relevant.)  */		\
147e83
+  if (! ignore_errors_p ())						\
147e83
+    {									\
147e83
+      result = __GCONV_ILLEGAL_INPUT;					\
147e83
+      break;								\
147e83
+    }									\
147e83
+  inptr += 2;								\
147e83
+  ++*irreversible;							\
147e83
+  continue;
147e83
+
147e83
+# define BODY_ORIG \
147e83
+  {									\
147e83
+    uint16_t u1 = bswap_16 (get16 (inptr));				\
147e83
+									\
147e83
+    if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			\
147e83
+      {									\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+									\
147e83
+    *((uint32_t *) outptr) = u1;					\
147e83
+    outptr += sizeof (uint32_t);					\
147e83
+    inptr += 2;								\
147e83
+  }
147e83
+# define BODY								\
147e83
+  {									\
147e83
+    size_t len, tmp, tmp2;						\
147e83
+    len = MIN ((inend - inptr) / 2, (outend - outptr) / 4);		\
147e83
+    __asm__ volatile (".machine push\n\t"				\
147e83
+		      ".machine \"z13\"\n\t"				\
147e83
+		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
147e83
+		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
147e83
+		      /* Setup to check for ch >= 0xd800 && ch < 0xe000.  */ \
147e83
+		      "    larl %[R_TMP],9f\n\t"			\
147e83
+		      "    vlm %%v20,%%v22,0(%[R_TMP])\n\t"		\
147e83
+		      "    srlg %[R_TMP],%[R_LEN],3\n\t"		\
147e83
+		      "    clgije %[R_TMP],0,1f\n\t"			\
147e83
+		      /* Process 16byte (8char) blocks.  */		\
147e83
+		      "0:  vl %%v16,0(%[R_IN])\n\t"			\
147e83
+		      "    vperm %%v16,%%v16,%%v16,%%v22\n\t"		\
147e83
+		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
147e83
+		      /* Enlarge UCS2 to UCS4.  */			\
147e83
+		      "    vuplhh %%v17,%%v16\n\t"			\
147e83
+		      "    vupllh %%v18,%%v16\n\t"			\
147e83
+		      "    jno 10f\n\t"					\
147e83
+		      /* Store 32bytes to buf_out.  */			\
147e83
+		      "    vstm %%v17,%%v18,0(%[R_OUT])\n\t"		\
147e83
+		      "    la %[R_IN],16(%[R_IN])\n\t"			\
147e83
+		      "    la %[R_OUT],32(%[R_OUT])\n\t"		\
147e83
+		      "    brctg %[R_TMP],0b\n\t"			\
147e83
+		      "    llgfr %[R_LEN],%[R_LEN]\n\t"			\
147e83
+		      "    nilf %[R_LEN],7\n\t"				\
147e83
+		      /* Process <16bytes.  */				\
147e83
+		      "1:  sll %[R_LEN],1\n\t"				\
147e83
+		      "    ahik %[R_TMP],%[R_LEN],-1\n\t"		\
147e83
+		      "    jl 20f\n\t" /* No further bytes available.  */ \
147e83
+		      "    vll %%v16,%[R_TMP],0(%[R_IN])\n\t"		\
147e83
+		      "    vperm %%v16,%%v16,%%v16,%%v22\n\t"		\
147e83
+		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
147e83
+		      /* Enlarge UCS2 to UCS4.  */			\
147e83
+		      "    vuplhh %%v17,%%v16\n\t"			\
147e83
+		      "    vupllh %%v18,%%v16\n\t"			\
147e83
+		      "    vlgvb %[R_TMP],%%v19,7\n\t"			\
147e83
+		      "    clr %[R_TMP],%[R_LEN]\n\t"			\
147e83
+		      "    locgrhe %[R_TMP],%[R_LEN]\n\t"		\
147e83
+		      "    locghihe %[R_LEN],0\n\t"			\
147e83
+		      "    j 11f\n\t"					\
147e83
+		      /* v20: Vector string range compare values.  */	\
147e83
+		      "9:  .short 0xd800,0xe000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
147e83
+		      /* v21: Vector string range compare control-bits.	\
147e83
+			 element 0: =>; element 1: <  */		\
147e83
+		      "    .short 0xa000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
147e83
+		      /* v22: Vector permute mask.  */			\
147e83
+		      "    .short 0x0100,0x0302,0x0504,0x0706\n\t"	\
147e83
+		      "    .short 0x0908,0x0b0a,0x0d0c,0x0f0e\n\t"	\
147e83
+		      /* Found an element: ch >= 0xd800 && ch < 0xe000  */ \
147e83
+		      "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
147e83
+		      "11: la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
147e83
+		      "    sll %[R_TMP],1\n\t"				\
147e83
+		      "    lgr %[R_TMP2],%[R_TMP]\n\t"			\
147e83
+		      "    ahi %[R_TMP],-1\n\t"				\
147e83
+		      "    jl 20f\n\t"					\
147e83
+		      "    vstl %%v17,%[R_TMP],0(%[R_OUT])\n\t"		\
147e83
+		      "    ahi %[R_TMP],-16\n\t"			\
147e83
+		      "    jl 19f\n\t"					\
147e83
+		      "    vstl %%v18,%[R_TMP],16(%[R_OUT])\n\t"	\
147e83
+		      "19: la %[R_OUT],0(%[R_TMP2],%[R_OUT])\n\t"	\
147e83
+		      "20: \n\t"					\
147e83
+		      ".machine pop"					\
147e83
+		      : /* outputs */ [R_OUT] "+a" (outptr)		\
147e83
+			, [R_IN] "+a" (inptr)				\
147e83
+			, [R_TMP] "=a" (tmp)				\
147e83
+			, [R_TMP2] "=a" (tmp2)				\
147e83
+			, [R_LEN] "+d" (len)				\
147e83
+		      : /* inputs */					\
147e83
+		      : /* clobber list*/ "memory", "cc"		\
147e83
+			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
147e83
+			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
147e83
+			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
147e83
+			ASM_CLOBBER_VR ("v22")				\
147e83
+		      );						\
147e83
+    if (len > 0)							\
147e83
+      {									\
147e83
+	/* Found an invalid character at next input-char.  */		\
147e83
+	BODY_ORIG_ERROR							\
147e83
+      }									\
147e83
+  }
147e83
+# define LOOP_NEED_FLAGS
147e83
+# include <iconv/loop.c>
147e83
+# include <iconv/skeleton.c>
147e83
+# undef BODY_ORIG
147e83
+# undef BODY_ORIG_ERROR
147e83
+ICONV_VX_IFUNC (__gconv_transform_ucs2reverse_internal)
147e83
+
147e83
+/* Convert from the internal (UCS4-like) format to UCS2.  */
147e83
+#define DEFINE_INIT		0
147e83
+#define DEFINE_FINI		0
147e83
+#define MIN_NEEDED_FROM		4
147e83
+#define MIN_NEEDED_TO		2
147e83
+#define FROM_DIRECTION		1
147e83
+#define FROM_LOOP		ICONV_VX_NAME (internal_ucs2_loop)
147e83
+#define TO_LOOP			ICONV_VX_NAME (internal_ucs2_loop) /* This is not used.  */
147e83
+#define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ucs2)
147e83
+#define ONE_DIRECTION		1
147e83
+
147e83
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
147e83
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
147e83
+#define LOOPFCT			FROM_LOOP
147e83
+#define BODY_ORIG							\
147e83
+  {									\
147e83
+    uint32_t val = *((const uint32_t *) inptr);				\
147e83
+									\
147e83
+    if (__glibc_unlikely (val >= 0x10000))				\
147e83
+      {									\
147e83
+	UNICODE_TAG_HANDLER (val, 4);					\
147e83
+	STANDARD_TO_LOOP_ERR_HANDLER (4);				\
147e83
+      }									\
147e83
+    else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		\
147e83
+      {									\
147e83
+	/* Surrogate characters in UCS-4 input are not valid.		\
147e83
+	   We must catch this, because the UCS-2 output might be	\
147e83
+	   interpreted as UTF-16 by other programs.  If we let		\
147e83
+	   surrogates pass through, attackers could make a security	\
147e83
+	   hole exploit by synthesizing any desired plane 1-16		\
147e83
+	   character.  */						\
147e83
+	result = __GCONV_ILLEGAL_INPUT;					\
147e83
+	if (! ignore_errors_p ())					\
147e83
+	  break;							\
147e83
+	inptr += 4;							\
147e83
+	++*irreversible;						\
147e83
+	continue;							\
147e83
+      }									\
147e83
+    else								\
147e83
+      {									\
147e83
+	put16 (outptr, val);						\
147e83
+	outptr += sizeof (uint16_t);					\
147e83
+	inptr += 4;							\
147e83
+      }									\
147e83
+  }
147e83
+# define BODY								\
147e83
+  {									\
147e83
+    if (__builtin_expect (inend - inptr < 32, 1)			\
147e83
+	|| outend - outptr < 16)					\
147e83
+      /* Convert remaining bytes with c code.  */			\
147e83
+      BODY_ORIG								\
147e83
+    else								\
147e83
+      {									\
147e83
+	/* Convert in 32 byte blocks.  */				\
147e83
+	size_t loop_count = (inend - inptr) / 32;			\
147e83
+	size_t tmp, tmp2;						\
147e83
+	if (loop_count > (outend - outptr) / 16)			\
147e83
+	  loop_count = (outend - outptr) / 16;				\
147e83
+	__asm__ volatile (".machine push\n\t"				\
147e83
+			  ".machine \"z13\"\n\t"			\
147e83
+			  ".machinemode \"zarch_nohighgprs\"\n\t"	\
147e83
+			  CONVERT_32BIT_SIZE_T ([R_LI])			\
147e83
+			  "    larl %[R_I],3f\n\t"			\
147e83
+			  "    vlm %%v20,%%v23,0(%[R_I])\n\t"		\
147e83
+			  "0:  \n\t"					\
147e83
+			  "    vlm %%v16,%%v17,0(%[R_IN])\n\t"		\
147e83
+			  /* Shorten UCS4 to UCS2.  */			\
147e83
+			  "    vpkf %%v18,%%v16,%%v17\n\t"		\
147e83
+			  "    vstrcfs %%v19,%%v16,%%v20,%%v21\n\t"	\
147e83
+			  "    jno 11f\n\t"				\
147e83
+			  "1:  vstrcfs %%v19,%%v17,%%v20,%%v21\n\t"	\
147e83
+			  "    jno 10f\n\t"				\
147e83
+			  /* Store 16bytes to buf_out.  */		\
147e83
+			  "2:  vst %%v18,0(%[R_OUT])\n\t"		\
147e83
+			  "    la %[R_IN],32(%[R_IN])\n\t"		\
147e83
+			  "    la %[R_OUT],16(%[R_OUT])\n\t"		\
147e83
+			  "    brctg %[R_LI],0b\n\t"			\
147e83
+			  "    j 20f\n\t"				\
147e83
+			  /* Setup to check for ch >= 0xd800. (v20, v21)  */ \
147e83
+			  "3:  .long 0xd800,0xd800,0x0,0x0\n\t"		\
147e83
+			  "    .long 0xa0000000,0xa0000000,0x0,0x0\n\t"	\
147e83
+			  /* Setup to check for ch >= 0xe000		\
147e83
+			     && ch < 0x10000. (v22,v23)  */		\
147e83
+			  "    .long 0xe000,0x10000,0x0,0x0\n\t"	\
147e83
+			  "    .long 0xa0000000,0x40000000,0x0,0x0\n\t"	\
147e83
+			  /* v16 contains only valid chars. Check in v17: \
147e83
+			     ch >= 0xe000 && ch <= 0xffff.  */		\
147e83
+			  "10: vstrcfs %%v19,%%v17,%%v22,%%v23,8\n\t"	\
147e83
+			  "    jo 2b\n\t" /* All ch's in this range, proceed.   */ \
147e83
+			  "    lghi %[R_TMP],16\n\t"			\
147e83
+			  "    j 12f\n\t"				\
147e83
+			  /* Maybe v16 contains invalid chars.		\
147e83
+			     Check ch >= 0xe000 && ch <= 0xffff.  */	\
147e83
+			  "11: vstrcfs %%v19,%%v16,%%v22,%%v23,8\n\t"	\
147e83
+			  "    jo 1b\n\t" /* All ch's in this range, proceed.   */ \
147e83
+			  "    lghi %[R_TMP],0\n\t"			\
147e83
+			  "12: vlgvb %[R_I],%%v19,7\n\t"		\
147e83
+			  "    agr %[R_I],%[R_TMP]\n\t"			\
147e83
+			  "    la %[R_IN],0(%[R_I],%[R_IN])\n\t"	\
147e83
+			  "    srl %[R_I],1\n\t"			\
147e83
+			  "    ahi %[R_I],-1\n\t"			\
147e83
+			  "    jl 20f\n\t"				\
147e83
+			  "    vstl %%v18,%[R_I],0(%[R_OUT])\n\t"	\
147e83
+			  "    la %[R_OUT],1(%[R_I],%[R_OUT])\n\t"	\
147e83
+			  "20:\n\t"					\
147e83
+			  ".machine pop"				\
147e83
+			  : /* outputs */ [R_OUT] "+a" (outptr)		\
147e83
+			    , [R_IN] "+a" (inptr)			\
147e83
+			    , [R_LI] "+d" (loop_count)			\
147e83
+			    , [R_I] "=a" (tmp2)				\
147e83
+			    , [R_TMP] "=d" (tmp)			\
147e83
+			  : /* inputs */				\
147e83
+			  : /* clobber list*/ "memory", "cc"		\
147e83
+			    ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17") \
147e83
+			    ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19") \
147e83
+			    ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21") \
147e83
+			    ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v23") \
147e83
+			  );						\
147e83
+	if (loop_count > 0)						\
147e83
+	  {								\
147e83
+	    /* Found an invalid character at next character.  */	\
147e83
+	    BODY_ORIG							\
147e83
+	  }								\
147e83
+      }									\
147e83
+  }
147e83
+#define LOOP_NEED_FLAGS
147e83
+#include <iconv/loop.c>
147e83
+#include <iconv/skeleton.c>
147e83
+# undef BODY_ORIG
147e83
+ICONV_VX_IFUNC (__gconv_transform_internal_ucs2)
147e83
+
147e83
+/* Convert from the internal (UCS4-like) format to UCS2 in other endianness. */
147e83
+#define DEFINE_INIT		0
147e83
+#define DEFINE_FINI		0
147e83
+#define MIN_NEEDED_FROM		4
147e83
+#define MIN_NEEDED_TO		2
147e83
+#define FROM_DIRECTION		1
147e83
+#define FROM_LOOP		ICONV_VX_NAME (internal_ucs2reverse_loop)
147e83
+#define TO_LOOP			ICONV_VX_NAME (internal_ucs2reverse_loop)/* This is not used.*/
147e83
+#define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ucs2reverse)
147e83
+#define ONE_DIRECTION		1
147e83
+
147e83
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
147e83
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
147e83
+#define LOOPFCT			FROM_LOOP
147e83
+#define BODY_ORIG							\
147e83
+  {									\
147e83
+    uint32_t val = *((const uint32_t *) inptr);				\
147e83
+    if (__glibc_unlikely (val >= 0x10000))				\
147e83
+      {									\
147e83
+	UNICODE_TAG_HANDLER (val, 4);					\
147e83
+	STANDARD_TO_LOOP_ERR_HANDLER (4);				\
147e83
+      }									\
147e83
+    else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		\
147e83
+      {									\
147e83
+	/* Surrogate characters in UCS-4 input are not valid.		\
147e83
+	   We must catch this, because the UCS-2 output might be	\
147e83
+	   interpreted as UTF-16 by other programs.  If we let		\
147e83
+	   surrogates pass through, attackers could make a security	\
147e83
+	   hole exploit by synthesizing any desired plane 1-16		\
147e83
+	   character.  */						\
147e83
+	if (! ignore_errors_p ())					\
147e83
+	  {								\
147e83
+	    result = __GCONV_ILLEGAL_INPUT;				\
147e83
+	    break;							\
147e83
+	  }								\
147e83
+	inptr += 4;							\
147e83
+	++*irreversible;						\
147e83
+	continue;							\
147e83
+      }									\
147e83
+    else								\
147e83
+      {									\
147e83
+	put16 (outptr, bswap_16 (val));					\
147e83
+	outptr += sizeof (uint16_t);					\
147e83
+	inptr += 4;							\
147e83
+      }									\
147e83
+  }
147e83
+# define BODY								\
147e83
+  {									\
147e83
+    if (__builtin_expect (inend - inptr < 32, 1)			\
147e83
+	|| outend - outptr < 16)					\
147e83
+      /* Convert remaining bytes with c code.  */			\
147e83
+      BODY_ORIG								\
147e83
+    else								\
147e83
+      {									\
147e83
+	/* Convert in 32 byte blocks.  */				\
147e83
+	size_t loop_count = (inend - inptr) / 32;			\
147e83
+	size_t tmp, tmp2;						\
147e83
+	if (loop_count > (outend - outptr) / 16)			\
147e83
+	  loop_count = (outend - outptr) / 16;				\
147e83
+	__asm__ volatile (".machine push\n\t"				\
147e83
+			  ".machine \"z13\"\n\t"			\
147e83
+			  ".machinemode \"zarch_nohighgprs\"\n\t"	\
147e83
+			  CONVERT_32BIT_SIZE_T ([R_LI])			\
147e83
+			  "    larl %[R_I],3f\n\t"			\
147e83
+			  "    vlm %%v20,%%v24,0(%[R_I])\n\t"		\
147e83
+			  "0:  \n\t"					\
147e83
+			  "    vlm %%v16,%%v17,0(%[R_IN])\n\t"		\
147e83
+			  /* Shorten UCS4 to UCS2 and byteswap.  */	\
147e83
+			  "    vpkf %%v18,%%v16,%%v17\n\t"		\
147e83
+			  "    vperm %%v18,%%v18,%%v18,%%v24\n\t"	\
147e83
+			  "    vstrcfs %%v19,%%v16,%%v20,%%v21\n\t"	\
147e83
+			  "    jno 11f\n\t"				\
147e83
+			  "1:  vstrcfs %%v19,%%v17,%%v20,%%v21\n\t"	\
147e83
+			  "    jno 10f\n\t"				\
147e83
+			  /* Store 16bytes to buf_out.  */		\
147e83
+			  "2: vst %%v18,0(%[R_OUT])\n\t"		\
147e83
+			  "    la %[R_IN],32(%[R_IN])\n\t"		\
147e83
+			  "    la %[R_OUT],16(%[R_OUT])\n\t"		\
147e83
+			  "    brctg %[R_LI],0b\n\t"			\
147e83
+			  "    j 20f\n\t"				\
147e83
+			  /* Setup to check for ch >= 0xd800. (v20, v21)  */ \
147e83
+			  "3: .long 0xd800,0xd800,0x0,0x0\n\t"		\
147e83
+			  "    .long 0xa0000000,0xa0000000,0x0,0x0\n\t"	\
147e83
+			  /* Setup to check for ch >= 0xe000		\
147e83
+			     && ch < 0x10000. (v22,v23)  */		\
147e83
+			  "    .long 0xe000,0x10000,0x0,0x0\n\t"	\
147e83
+			  "    .long 0xa0000000,0x40000000,0x0,0x0\n\t"	\
147e83
+			  /* Vector permute mask (v24)  */		\
147e83
+			  "    .short 0x0100,0x0302,0x0504,0x0706\n\t"	\
147e83
+			  "    .short 0x0908,0x0b0a,0x0d0c,0x0f0e\n\t"	\
147e83
+			  /* v16 contains only valid chars. Check in v17: \
147e83
+			     ch >= 0xe000 && ch <= 0xffff.  */		\
147e83
+			  "10: vstrcfs %%v19,%%v17,%%v22,%%v23,8\n\t"	\
147e83
+			  "    jo 2b\n\t" /* All ch's in this range, proceed.  */ \
147e83
+			  "    lghi %[R_TMP],16\n\t"			\
147e83
+			  "    j 12f\n\t"				\
147e83
+			  /* Maybe v16 contains invalid chars.		\
147e83
+			     Check ch >= 0xe000 && ch <= 0xffff.  */	\
147e83
+			  "11: vstrcfs %%v19,%%v16,%%v22,%%v23,8\n\t"	\
147e83
+			  "    jo 1b\n\t" /* All ch's in this range, proceed.  */ \
147e83
+			  "    lghi %[R_TMP],0\n\t"			\
147e83
+			  "12: vlgvb %[R_I],%%v19,7\n\t"		\
147e83
+			  "    agr %[R_I],%[R_TMP]\n\t"			\
147e83
+			  "    la %[R_IN],0(%[R_I],%[R_IN])\n\t"	\
147e83
+			  "    srl %[R_I],1\n\t"			\
147e83
+			  "    ahi %[R_I],-1\n\t"			\
147e83
+			  "    jl 20f\n\t"				\
147e83
+			  "    vstl %%v18,%[R_I],0(%[R_OUT])\n\t"	\
147e83
+			  "    la %[R_OUT],1(%[R_I],%[R_OUT])\n\t"	\
147e83
+			  "20:\n\t"					\
147e83
+			  ".machine pop"				\
147e83
+			  : /* outputs */ [R_OUT] "+a" (outptr)		\
147e83
+			    , [R_IN] "+a" (inptr)			\
147e83
+			    , [R_LI] "+d" (loop_count)			\
147e83
+			    , [R_I] "=a" (tmp2)				\
147e83
+			    , [R_TMP] "=d" (tmp)			\
147e83
+			  : /* inputs */				\
147e83
+			  : /* clobber list*/ "memory", "cc"		\
147e83
+			    ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17") \
147e83
+			    ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19") \
147e83
+			    ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21") \
147e83
+			    ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v23") \
147e83
+			    ASM_CLOBBER_VR ("v24")			\
147e83
+			  );						\
147e83
+	if (loop_count > 0)						\
147e83
+	  {								\
147e83
+	    /* Found an invalid character at next character.  */	\
147e83
+	    BODY_ORIG							\
147e83
+	  }								\
147e83
+      }									\
147e83
+  }
147e83
+#define LOOP_NEED_FLAGS
147e83
+#include <iconv/loop.c>
147e83
+#include <iconv/skeleton.c>
147e83
+# undef BODY_ORIG
147e83
+ICONV_VX_IFUNC (__gconv_transform_internal_ucs2reverse)
147e83
+
147e83
+
147e83
+#else
147e83
+/* Generate the internal transformations without ifunc if build environment
147e83
+   lacks vector support. Instead simply include the common version.  */
147e83
+# include <iconv/gconv_simple.c>
147e83
+#endif /* !defined HAVE_S390_VX_ASM_SUPPORT */
147e83
-- 
147e83
1.8.3.1
147e83