Blame sysdeps/s390/multiarch/gconv_simple.c

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