(root)/
glibc-2.38/
sysdeps/
s390/
multiarch/
gconv_simple.c
       1  /* Simple transformations functions - s390 version.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #if defined HAVE_S390_VX_ASM_SUPPORT
      20  # include <ifunc-resolve.h>
      21  
      22  # if defined HAVE_S390_VX_GCC_SUPPORT
      23  #  define ASM_CLOBBER_VR(NR) , NR
      24  # else
      25  #  define ASM_CLOBBER_VR(NR)
      26  # endif
      27  
      28  # define ICONV_C_NAME(NAME) __##NAME##_c
      29  # define ICONV_VX_NAME(NAME) __##NAME##_vx
      30  # ifdef HAVE_S390_MIN_Z13_ZARCH_ASM_SUPPORT
      31  /* We support z13 instructions by default -> Just use the vector variant.  */
      32  #  define ICONV_VX_IFUNC(FUNC) strong_alias (ICONV_VX_NAME (FUNC), FUNC)
      33  # else
      34  /* We have to use ifunc to determine if z13 instructions are supported.  */
      35  #  define ICONV_VX_IFUNC(FUNC)						\
      36    s390_libc_ifunc_expr (ICONV_C_NAME (FUNC), FUNC,			\
      37  			(hwcap & HWCAP_S390_VX)				\
      38  			? ICONV_VX_NAME (FUNC)				\
      39  			: ICONV_C_NAME (FUNC)				\
      40  			)
      41  # endif
      42  # define ICONV_VX_SINGLE(NAME)						\
      43    static __typeof (NAME##_single) __##NAME##_vx_single __attribute__((alias(#NAME "_single")));
      44  
      45  /* Generate the transformations which are used, if the target machine does not
      46     support vector instructions.  */
      47  # define __gconv_transform_ascii_internal		\
      48    ICONV_C_NAME (__gconv_transform_ascii_internal)
      49  # define __gconv_transform_internal_ascii		\
      50    ICONV_C_NAME (__gconv_transform_internal_ascii)
      51  # define __gconv_transform_internal_ucs4le		\
      52    ICONV_C_NAME (__gconv_transform_internal_ucs4le)
      53  # define __gconv_transform_ucs4_internal		\
      54    ICONV_C_NAME (__gconv_transform_ucs4_internal)
      55  # define __gconv_transform_ucs4le_internal		\
      56    ICONV_C_NAME (__gconv_transform_ucs4le_internal)
      57  # define __gconv_transform_ucs2_internal		\
      58    ICONV_C_NAME (__gconv_transform_ucs2_internal)
      59  # define __gconv_transform_ucs2reverse_internal		\
      60    ICONV_C_NAME (__gconv_transform_ucs2reverse_internal)
      61  # define __gconv_transform_internal_ucs2		\
      62    ICONV_C_NAME (__gconv_transform_internal_ucs2)
      63  # define __gconv_transform_internal_ucs2reverse		\
      64    ICONV_C_NAME (__gconv_transform_internal_ucs2reverse)
      65  
      66  
      67  # include <iconv/gconv_simple.c>
      68  
      69  # undef __gconv_transform_ascii_internal
      70  # undef __gconv_transform_internal_ascii
      71  # undef __gconv_transform_internal_ucs4le
      72  # undef __gconv_transform_ucs4_internal
      73  # undef __gconv_transform_ucs4le_internal
      74  # undef __gconv_transform_ucs2_internal
      75  # undef __gconv_transform_ucs2reverse_internal
      76  # undef __gconv_transform_internal_ucs2
      77  # undef __gconv_transform_internal_ucs2reverse
      78  
      79  /* Now define the functions with vector support.  */
      80  # if defined __s390x__
      81  #  define CONVERT_32BIT_SIZE_T(REG)
      82  # else
      83  #  define CONVERT_32BIT_SIZE_T(REG) "llgfr %" #REG ",%" #REG "\n\t"
      84  # endif
      85  
      86  /* Convert from ISO 646-IRV to the internal (UCS4-like) format.  */
      87  # define DEFINE_INIT		0
      88  # define DEFINE_FINI		0
      89  # define MIN_NEEDED_FROM	1
      90  # define MIN_NEEDED_TO		4
      91  # define FROM_DIRECTION		1
      92  # define FROM_LOOP		ICONV_VX_NAME (ascii_internal_loop)
      93  # define TO_LOOP		ICONV_VX_NAME (ascii_internal_loop) /* This is not used.  */
      94  # define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ascii_internal)
      95  # define ONE_DIRECTION		1
      96  
      97  # define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
      98  # define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
      99  # define LOOPFCT		FROM_LOOP
     100  # define BODY_ORIG_ERROR						\
     101      /* The value is too large.  We don't try transliteration here since \
     102         this is not an error because of the lack of possibilities to	\
     103         represent the result.  This is a genuine bug in the input since	\
     104         ASCII does not allow such values.  */				\
     105      STANDARD_FROM_LOOP_ERR_HANDLER (1);
     106  
     107  # define BODY_ORIG							\
     108    {									\
     109      if (__glibc_unlikely (*inptr > '\x7f'))				\
     110        {									\
     111  	BODY_ORIG_ERROR							\
     112        }									\
     113      else								\
     114        {									\
     115  	/* It's an one byte sequence.  */				\
     116  	*((uint32_t *) outptr) = *inptr++;				\
     117  	outptr += sizeof (uint32_t);					\
     118        }									\
     119    }
     120  # define BODY								\
     121    {									\
     122      size_t len = inend - inptr;						\
     123      if (len > (outend - outptr) / 4)					\
     124        len = (outend - outptr) / 4;					\
     125      size_t loop_count, tmp;						\
     126      __asm__ volatile (".machine push\n\t"				\
     127  		      ".machine \"z13\"\n\t"				\
     128  		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
     129  		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
     130  		      "    vrepib %%v30,0x7f\n\t" /* For compare > 0x7f.  */ \
     131  		      "    srlg %[R_LI],%[R_LEN],4\n\t"			\
     132  		      "    vrepib %%v31,0x20\n\t"			\
     133  		      "    clgije %[R_LI],0,1f\n\t"			\
     134  		      "0:  \n\t" /* Handle 16-byte blocks.  */		\
     135  		      "    vl %%v16,0(%[R_IN])\n\t"			\
     136  		      /* Checking for values > 0x7f.  */		\
     137  		      "    vstrcbs %%v17,%%v16,%%v30,%%v31\n\t"		\
     138  		      "    jno 10f\n\t"					\
     139  		      /* Enlarge to UCS4.  */				\
     140  		      "    vuplhb %%v17,%%v16\n\t"			\
     141  		      "    vupllb %%v18,%%v16\n\t"			\
     142  		      "    vuplhh %%v19,%%v17\n\t"			\
     143  		      "    vupllh %%v20,%%v17\n\t"			\
     144  		      "    vuplhh %%v21,%%v18\n\t"			\
     145  		      "    vupllh %%v22,%%v18\n\t"			\
     146  		      /* Store 64bytes to buf_out.  */			\
     147  		      "    vstm %%v19,%%v22,0(%[R_OUT])\n\t"		\
     148  		      "    la %[R_IN],16(%[R_IN])\n\t"			\
     149  		      "    la %[R_OUT],64(%[R_OUT])\n\t"		\
     150  		      "    brctg %[R_LI],0b\n\t"			\
     151  		      "    lghi %[R_LI],15\n\t"				\
     152  		      "    ngr %[R_LEN],%[R_LI]\n\t"			\
     153  		      "    je 20f\n\t" /* Jump away if no remaining bytes.  */ \
     154  		      /* Handle remaining bytes.  */			\
     155  		      "1: aghik %[R_LI],%[R_LEN],-1\n\t"		\
     156  		      "    jl 20f\n\t" /* Jump away if no remaining bytes.  */ \
     157  		      "    vll %%v16,%[R_LI],0(%[R_IN])\n\t"		\
     158  		      /* Checking for values > 0x7f.  */		\
     159  		      "    vstrcbs %%v17,%%v16,%%v30,%%v31\n\t"		\
     160  		      "    vlgvb %[R_TMP],%%v17,7\n\t"			\
     161  		      "    clr %[R_TMP],%[R_LI]\n\t"			\
     162  		      "    locrh %[R_TMP],%[R_LEN]\n\t"			\
     163  		      "    locghih %[R_LEN],0\n\t"			\
     164  		      "    j 12f\n\t"					\
     165  		      "10:\n\t"						\
     166  		      /* Found a value > 0x7f.				\
     167  			 Store the preceding chars.  */			\
     168  		      "    vlgvb %[R_TMP],%%v17,7\n\t"			\
     169  		      "12: la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
     170  		      "    sllk %[R_TMP],%[R_TMP],2\n\t"		\
     171  		      "    ahi %[R_TMP],-1\n\t"				\
     172  		      "    jl 20f\n\t"					\
     173  		      "    lgr %[R_LI],%[R_TMP]\n\t"			\
     174  		      "    vuplhb %%v17,%%v16\n\t"			\
     175  		      "    vuplhh %%v19,%%v17\n\t"			\
     176  		      "    vstl %%v19,%[R_LI],0(%[R_OUT])\n\t"		\
     177  		      "    ahi %[R_LI],-16\n\t"				\
     178  		      "    jl 11f\n\t"					\
     179  		      "    vupllh %%v20,%%v17\n\t"			\
     180  		      "    vstl %%v20,%[R_LI],16(%[R_OUT])\n\t"		\
     181  		      "    ahi %[R_LI],-16\n\t"				\
     182  		      "    jl 11f\n\t"					\
     183  		      "    vupllb %%v18,%%v16\n\t"			\
     184  		      "    vuplhh %%v21,%%v18\n\t"			\
     185  		      "    vstl %%v21,%[R_LI],32(%[R_OUT])\n\t"		\
     186  		      "    ahi %[R_LI],-16\n\t"				\
     187  		      "    jl 11f\n\t"					\
     188  		      "    vupllh %%v22,%%v18\n\t"			\
     189  		      "    vstl %%v22,%[R_LI],48(%[R_OUT])\n\t"		\
     190  		      "11:\n\t"						\
     191  		      "    la %[R_OUT],1(%[R_TMP],%[R_OUT])\n\t"	\
     192  		      "20:\n\t"						\
     193  		      ".machine pop"					\
     194  		      : /* outputs */ [R_OUT] "+a" (outptr)		\
     195  			, [R_IN] "+a" (inptr)				\
     196  			, [R_LEN] "+d" (len)				\
     197  			, [R_LI] "=d" (loop_count)			\
     198  			, [R_TMP] "=a" (tmp)				\
     199  		      : /* inputs */					\
     200  		      : /* clobber list*/ "memory", "cc"		\
     201  			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
     202  			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
     203  			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
     204  			ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v30")	\
     205  			ASM_CLOBBER_VR ("v31")				\
     206  		      );						\
     207      if (len > 0)							\
     208        {									\
     209  	/* Found an invalid character at the next input byte.  */	\
     210  	BODY_ORIG_ERROR							\
     211        }									\
     212    }
     213  
     214  # define LOOP_NEED_FLAGS
     215  # include <iconv/loop.c>
     216  # include <iconv/skeleton.c>
     217  # undef BODY_ORIG
     218  # undef BODY_ORIG_ERROR
     219  ICONV_VX_IFUNC (__gconv_transform_ascii_internal)
     220  
     221  /* Convert from the internal (UCS4-like) format to ISO 646-IRV.  */
     222  # define DEFINE_INIT		0
     223  # define DEFINE_FINI		0
     224  # define MIN_NEEDED_FROM	4
     225  # define MIN_NEEDED_TO		1
     226  # define FROM_DIRECTION		1
     227  # define FROM_LOOP		ICONV_VX_NAME (internal_ascii_loop)
     228  # define TO_LOOP		ICONV_VX_NAME (internal_ascii_loop) /* This is not used.  */
     229  # define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ascii)
     230  # define ONE_DIRECTION		1
     231  
     232  # define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
     233  # define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
     234  # define LOOPFCT		FROM_LOOP
     235  # define BODY_ORIG_ERROR						\
     236    UNICODE_TAG_HANDLER (*((const uint32_t *) inptr), 4);			\
     237    STANDARD_TO_LOOP_ERR_HANDLER (4);
     238  
     239  # define BODY_ORIG							\
     240    {									\
     241      if (__glibc_unlikely (*((const uint32_t *) inptr) > 0x7f))		\
     242        {									\
     243  	BODY_ORIG_ERROR							\
     244        }									\
     245      else								\
     246        {									\
     247  	/* It's an one byte sequence.  */				\
     248  	*outptr++ = *((const uint32_t *) inptr);			\
     249  	inptr += sizeof (uint32_t);					\
     250        }									\
     251    }
     252  # define BODY								\
     253    {									\
     254      size_t len = (inend - inptr) / 4;					\
     255      if (len > outend - outptr)						\
     256        len = outend - outptr;						\
     257      size_t loop_count, tmp, tmp2;					\
     258      __asm__ volatile (".machine push\n\t"				\
     259  		      ".machine \"z13\"\n\t"				\
     260  		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
     261  		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
     262  		      /* Setup to check for ch > 0x7f.  */		\
     263  		      "    vzero %%v21\n\t"				\
     264  		      "    srlg %[R_LI],%[R_LEN],4\n\t"			\
     265  		      "    vleih %%v21,8192,0\n\t"  /* element 0:   >  */ \
     266  		      "    vleih %%v21,-8192,2\n\t" /* element 1: =<>  */ \
     267  		      "    vleif %%v20,127,0\n\t"   /* element 0: 127  */ \
     268  		      "    lghi %[R_TMP],0\n\t"				\
     269  		      "    clgije %[R_LI],0,1f\n\t"			\
     270  		      "0:\n\t"						\
     271  		      "    vlm %%v16,%%v19,0(%[R_IN])\n\t"		\
     272  		      /* Shorten to byte values.  */			\
     273  		      "    vpkf %%v23,%%v16,%%v17\n\t"			\
     274  		      "    vpkf %%v24,%%v18,%%v19\n\t"			\
     275  		      "    vpkh %%v23,%%v23,%%v24\n\t"			\
     276  		      /* Checking for values > 0x7f.  */		\
     277  		      "    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"		\
     278  		      "    jno 10f\n\t"					\
     279  		      "    vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
     280  		      "    jno 11f\n\t"					\
     281  		      "    vstrcfs %%v22,%%v18,%%v20,%%v21\n\t"		\
     282  		      "    jno 12f\n\t"					\
     283  		      "    vstrcfs %%v22,%%v19,%%v20,%%v21\n\t"		\
     284  		      "    jno 13f\n\t"					\
     285  		      /* Store 16bytes to outptr.  */			\
     286  		      "    vst %%v23,0(%[R_OUT])\n\t"			\
     287  		      "    la %[R_IN],64(%[R_IN])\n\t"			\
     288  		      "    la %[R_OUT],16(%[R_OUT])\n\t"		\
     289  		      "    brctg %[R_LI],0b\n\t"			\
     290  		      "    lghi %[R_LI],15\n\t"				\
     291  		      "    ngr %[R_LEN],%[R_LI]\n\t"			\
     292  		      "    je 20f\n\t" /* Jump away if no remaining bytes.  */ \
     293  		      /* Handle remaining bytes.  */			\
     294  		      "1: sllg %[R_LI],%[R_LEN],2\n\t"			\
     295  		      "    aghi %[R_LI],-1\n\t"				\
     296  		      "    jl 20f\n\t" /* Jump away if no remaining bytes.  */ \
     297  		      /* Load remaining 1...63 bytes.  */		\
     298  		      "    vll %%v16,%[R_LI],0(%[R_IN])\n\t"		\
     299  		      "    ahi %[R_LI],-16\n\t"				\
     300  		      "    jl 2f\n\t"					\
     301  		      "    vll %%v17,%[R_LI],16(%[R_IN])\n\t"		\
     302  		      "    ahi %[R_LI],-16\n\t"				\
     303  		      "    jl 2f\n\t"					\
     304  		      "    vll %%v18,%[R_LI],32(%[R_IN])\n\t"		\
     305  		      "    ahi %[R_LI],-16\n\t"				\
     306  		      "    jl 2f\n\t"					\
     307  		      "    vll %%v19,%[R_LI],48(%[R_IN])\n\t"		\
     308  		      "2:\n\t"						\
     309  		      /* Shorten to byte values.  */			\
     310  		      "    vpkf %%v23,%%v16,%%v17\n\t"			\
     311  		      "    vpkf %%v24,%%v18,%%v19\n\t"			\
     312  		      "    vpkh %%v23,%%v23,%%v24\n\t"			\
     313  		      "    sllg %[R_LI],%[R_LEN],2\n\t"			\
     314  		      "    aghi %[R_LI],-16\n\t"			\
     315  		      "    jl 3f\n\t" /* v16 is not fully loaded.  */	\
     316  		      "    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"		\
     317  		      "    jno 10f\n\t"					\
     318  		      "    aghi %[R_LI],-16\n\t"			\
     319  		      "    jl 4f\n\t" /* v17 is not fully loaded.  */	\
     320  		      "    vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
     321  		      "    jno 11f\n\t"					\
     322  		      "    aghi %[R_LI],-16\n\t"			\
     323  		      "    jl 5f\n\t" /* v18 is not fully loaded.  */	\
     324  		      "    vstrcfs %%v22,%%v18,%%v20,%%v21\n\t"		\
     325  		      "    jno 12f\n\t"					\
     326  		      "    aghi %[R_LI],-16\n\t"			\
     327  		      /* v19 is not fully loaded. */			\
     328  		      "    lghi %[R_TMP],12\n\t"			\
     329  		      "    vstrcfs %%v22,%%v19,%%v20,%%v21\n\t"		\
     330  		      "6: vlgvb %[R_I],%%v22,7\n\t"			\
     331  		      "    aghi %[R_LI],16\n\t"				\
     332  		      "    clrjl %[R_I],%[R_LI],14f\n\t"		\
     333  		      "    lgr %[R_I],%[R_LEN]\n\t"			\
     334  		      "    lghi %[R_LEN],0\n\t"				\
     335  		      "    j 15f\n\t"					\
     336  		      "3: vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"		\
     337  		      "    j 6b\n\t"					\
     338  		      "4: vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
     339  		      "    lghi %[R_TMP],4\n\t"				\
     340  		      "    j 6b\n\t"					\
     341  		      "5: vstrcfs %%v22,%%v17,%%v20,%%v21\n\t"		\
     342  		      "    lghi %[R_TMP],8\n\t"				\
     343  		      "    j 6b\n\t"					\
     344  		      /* Found a value > 0x7f.  */			\
     345  		      "13: ahi %[R_TMP],4\n\t"				\
     346  		      "12: ahi %[R_TMP],4\n\t"				\
     347  		      "11: ahi %[R_TMP],4\n\t"				\
     348  		      "10: vlgvb %[R_I],%%v22,7\n\t"			\
     349  		      "14: srlg %[R_I],%[R_I],2\n\t"			\
     350  		      "    agr %[R_I],%[R_TMP]\n\t"			\
     351  		      "    je 20f\n\t"					\
     352  		      /* Store characters before invalid one...  */	\
     353  		      "15: aghi %[R_I],-1\n\t"				\
     354  		      "    vstl %%v23,%[R_I],0(%[R_OUT])\n\t"		\
     355  		      /* ... and update pointers.  */			\
     356  		      "    la %[R_OUT],1(%[R_I],%[R_OUT])\n\t"		\
     357  		      "    sllg %[R_I],%[R_I],2\n\t"			\
     358  		      "    la %[R_IN],4(%[R_I],%[R_IN])\n\t"		\
     359  		      "20:\n\t"						\
     360  		      ".machine pop"					\
     361  		      : /* outputs */ [R_OUT] "+a" (outptr)		\
     362  			, [R_IN] "+a" (inptr)				\
     363  			, [R_LEN] "+d" (len)				\
     364  			, [R_LI] "=d" (loop_count)			\
     365  			, [R_I] "=a" (tmp2)				\
     366  			, [R_TMP] "=d" (tmp)				\
     367  		      : /* inputs */					\
     368  		      : /* clobber list*/ "memory", "cc"		\
     369  			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
     370  			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
     371  			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
     372  			ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v23")	\
     373  			ASM_CLOBBER_VR ("v24")				\
     374  		      );						\
     375      if (len > 0)							\
     376        {									\
     377  	/* Found an invalid character > 0x7f at next character.  */	\
     378  	BODY_ORIG_ERROR							\
     379        }									\
     380    }
     381  # define LOOP_NEED_FLAGS
     382  # include <iconv/loop.c>
     383  # include <iconv/skeleton.c>
     384  # undef BODY_ORIG
     385  # undef BODY_ORIG_ERROR
     386  ICONV_VX_IFUNC (__gconv_transform_internal_ascii)
     387  
     388  
     389  /* Convert from internal UCS4 to UCS4 little endian form.  */
     390  # define DEFINE_INIT		0
     391  # define DEFINE_FINI		0
     392  # define MIN_NEEDED_FROM	4
     393  # define MIN_NEEDED_TO		4
     394  # define FROM_DIRECTION		1
     395  # define FROM_LOOP		ICONV_VX_NAME (internal_ucs4le_loop)
     396  # define TO_LOOP		ICONV_VX_NAME (internal_ucs4le_loop) /* This is not used.  */
     397  # define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ucs4le)
     398  # define ONE_DIRECTION		0
     399  
     400  static inline int
     401  __attribute ((always_inline))
     402  ICONV_VX_NAME (internal_ucs4le_loop) (struct __gconv_step *step,
     403  				      struct __gconv_step_data *step_data,
     404  				      const unsigned char **inptrp,
     405  				      const unsigned char *inend,
     406  				      unsigned char **outptrp,
     407  				      const unsigned char *outend,
     408  				      size_t *irreversible)
     409  {
     410    const unsigned char *inptr = *inptrp;
     411    unsigned char *outptr = *outptrp;
     412    int result;
     413    size_t len = MIN (inend - inptr, outend - outptr) / 4;
     414    size_t loop_count;
     415    __asm__ volatile (".machine push\n\t"
     416  		    ".machine \"z13\"\n\t"
     417  		    ".machinemode \"zarch_nohighgprs\"\n\t"
     418  		    CONVERT_32BIT_SIZE_T ([R_LEN])
     419  		    "    bras %[R_LI],1f\n\t"
     420  		    /* Vector permute mask:  */
     421  		    "    .long 0x03020100,0x7060504,0x0B0A0908,0x0F0E0D0C\n\t"
     422  		    "1:  vl %%v20,0(%[R_LI])\n\t"
     423  		    /* Process 64byte (16char) blocks.  */
     424  		    "    srlg %[R_LI],%[R_LEN],4\n\t"
     425  		    "    clgije %[R_LI],0,10f\n\t"
     426  		    "0:  vlm %%v16,%%v19,0(%[R_IN])\n\t"
     427  		    "    vperm %%v16,%%v16,%%v16,%%v20\n\t"
     428  		    "    vperm %%v17,%%v17,%%v17,%%v20\n\t"
     429  		    "    vperm %%v18,%%v18,%%v18,%%v20\n\t"
     430  		    "    vperm %%v19,%%v19,%%v19,%%v20\n\t"
     431  		    "    vstm %%v16,%%v19,0(%[R_OUT])\n\t"
     432  		    "    la %[R_IN],64(%[R_IN])\n\t"
     433  		    "    la %[R_OUT],64(%[R_OUT])\n\t"
     434  		    "    brctg %[R_LI],0b\n\t"
     435  		    "    llgfr %[R_LEN],%[R_LEN]\n\t"
     436  		    "    nilf %[R_LEN],15\n\t"
     437  		    /* Process 16byte (4char) blocks.  */
     438  		    "10: srlg %[R_LI],%[R_LEN],2\n\t"
     439  		    "    clgije %[R_LI],0,20f\n\t"
     440  		    "11: vl %%v16,0(%[R_IN])\n\t"
     441  		    "    vperm %%v16,%%v16,%%v16,%%v20\n\t"
     442  		    "    vst %%v16,0(%[R_OUT])\n\t"
     443  		    "    la %[R_IN],16(%[R_IN])\n\t"
     444  		    "    la %[R_OUT],16(%[R_OUT])\n\t"
     445  		    "    brctg %[R_LI],11b\n\t"
     446  		    "    nill %[R_LEN],3\n\t"
     447  		    /* Process <16bytes.  */
     448  		    "20: sll %[R_LEN],2\n\t"
     449  		    "    ahi %[R_LEN],-1\n\t"
     450  		    "    jl 30f\n\t"
     451  		    "    vll %%v16,%[R_LEN],0(%[R_IN])\n\t"
     452  		    "    vperm %%v16,%%v16,%%v16,%%v20\n\t"
     453  		    "    vstl %%v16,%[R_LEN],0(%[R_OUT])\n\t"
     454  		    "    la %[R_IN],1(%[R_LEN],%[R_IN])\n\t"
     455  		    "    la %[R_OUT],1(%[R_LEN],%[R_OUT])\n\t"
     456  		    "30: \n\t"
     457  		    ".machine pop"
     458  		    : /* outputs */ [R_OUT] "+a" (outptr)
     459  		      , [R_IN] "+a" (inptr)
     460  		      , [R_LI] "=a" (loop_count)
     461  		      , [R_LEN] "+a" (len)
     462  		    : /* inputs */
     463  		    : /* clobber list*/ "memory", "cc"
     464  		      ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")
     465  		      ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")
     466  		      ASM_CLOBBER_VR ("v20")
     467  		    );
     468    *inptrp = inptr;
     469    *outptrp = outptr;
     470  
     471    /* Determine the status.  */
     472    if (*inptrp == inend)
     473      result = __GCONV_EMPTY_INPUT;
     474    else if (*outptrp + 4 > outend)
     475      result = __GCONV_FULL_OUTPUT;
     476    else
     477      result = __GCONV_INCOMPLETE_INPUT;
     478  
     479    return result;
     480  }
     481  
     482  ICONV_VX_SINGLE (internal_ucs4le_loop)
     483  # include <iconv/skeleton.c>
     484  ICONV_VX_IFUNC (__gconv_transform_internal_ucs4le)
     485  
     486  
     487  /* Transform from UCS4 to the internal, UCS4-like format.  Unlike
     488     for the other direction we have to check for correct values here.  */
     489  # define DEFINE_INIT		0
     490  # define DEFINE_FINI		0
     491  # define MIN_NEEDED_FROM	4
     492  # define MIN_NEEDED_TO		4
     493  # define FROM_DIRECTION		1
     494  # define FROM_LOOP		ICONV_VX_NAME (ucs4_internal_loop)
     495  # define TO_LOOP		ICONV_VX_NAME (ucs4_internal_loop) /* This is not used.  */
     496  # define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs4_internal)
     497  # define ONE_DIRECTION		0
     498  
     499  
     500  static inline int
     501  __attribute ((always_inline))
     502  ICONV_VX_NAME (ucs4_internal_loop) (struct __gconv_step *step,
     503  				    struct __gconv_step_data *step_data,
     504  				    const unsigned char **inptrp,
     505  				    const unsigned char *inend,
     506  				    unsigned char **outptrp,
     507  				    const unsigned char *outend,
     508  				    size_t *irreversible)
     509  {
     510    int flags = step_data->__flags;
     511    const unsigned char *inptr = *inptrp;
     512    unsigned char *outptr = *outptrp;
     513    int result;
     514    size_t len, loop_count;
     515    do
     516      {
     517        len = MIN (inend - inptr, outend - outptr) / 4;
     518        __asm__ volatile (".machine push\n\t"
     519  			".machine \"z13\"\n\t"
     520  			".machinemode \"zarch_nohighgprs\"\n\t"
     521  			CONVERT_32BIT_SIZE_T ([R_LEN])
     522  			/* Setup to check for ch > 0x7fffffff.  */
     523  			"    larl %[R_LI],9f\n\t"
     524  			"    vlm %%v20,%%v21,0(%[R_LI])\n\t"
     525  			"    srlg %[R_LI],%[R_LEN],2\n\t"
     526  			"    clgije %[R_LI],0,1f\n\t"
     527  			/* Process 16byte (4char) blocks.  */
     528  			"0:  vl %%v16,0(%[R_IN])\n\t"
     529  			"    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"
     530  			"    jno 10f\n\t"
     531  			"    vst %%v16,0(%[R_OUT])\n\t"
     532  			"    la %[R_IN],16(%[R_IN])\n\t"
     533  			"    la %[R_OUT],16(%[R_OUT])\n\t"
     534  			"    brctg %[R_LI],0b\n\t"
     535  			"    llgfr %[R_LEN],%[R_LEN]\n\t"
     536  			"    nilf %[R_LEN],3\n\t"
     537  			/* Process <16bytes.  */
     538  			"1:  sll %[R_LEN],2\n\t"
     539  			"    ahik %[R_LI],%[R_LEN],-1\n\t"
     540  			"    jl 20f\n\t" /* No further bytes available.  */
     541  			"    vll %%v16,%[R_LI],0(%[R_IN])\n\t"
     542  			"    vstrcfs %%v22,%%v16,%%v20,%%v21\n\t"
     543  			"    vlgvb %[R_LI],%%v22,7\n\t"
     544  			"    clr %[R_LI],%[R_LEN]\n\t"
     545  			"    locgrhe %[R_LI],%[R_LEN]\n\t"
     546  			"    locghihe %[R_LEN],0\n\t"
     547  			"    j 11f\n\t"
     548  			/* v20: Vector string range compare values.  */
     549  			"9:  .long 0x7fffffff,0x0,0x0,0x0\n\t"
     550  			/* v21: Vector string range compare control-bits.
     551  			   element 0: >; element 1: =<> (always true)  */
     552  			"    .long 0x20000000,0xE0000000,0x0,0x0\n\t"
     553  			/* Found a value > 0x7fffffff.  */
     554  			"10: vlgvb %[R_LI],%%v22,7\n\t"
     555  			/* Store characters before invalid one.  */
     556  			"11: aghi %[R_LI],-1\n\t"
     557  			"    jl 20f\n\t"
     558  			"    vstl %%v16,%[R_LI],0(%[R_OUT])\n\t"
     559  			"    la %[R_IN],1(%[R_LI],%[R_IN])\n\t"
     560  			"    la %[R_OUT],1(%[R_LI],%[R_OUT])\n\t"
     561  			"20:\n\t"
     562  			".machine pop"
     563  			: /* outputs */ [R_OUT] "+a" (outptr)
     564  			  , [R_IN] "+a" (inptr)
     565  			  , [R_LI] "=a" (loop_count)
     566  			  , [R_LEN] "+d" (len)
     567  			: /* inputs */
     568  			: /* clobber list*/ "memory", "cc"
     569  			  ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v20")
     570  			  ASM_CLOBBER_VR ("v21") ASM_CLOBBER_VR ("v22")
     571  			);
     572        if (len > 0)
     573  	{
     574  	  /* The value is too large.  We don't try transliteration here since
     575  	     this is not an error because of the lack of possibilities to
     576  	     represent the result.  This is a genuine bug in the input since
     577  	     UCS4 does not allow such values.  */
     578  	  if (irreversible == NULL)
     579  	    /* We are transliterating, don't try to correct anything.  */
     580  	    return __GCONV_ILLEGAL_INPUT;
     581  
     582  	  if (flags & __GCONV_IGNORE_ERRORS)
     583  	    {
     584  	      /* Just ignore this character.  */
     585  	      ++*irreversible;
     586  	      inptr += 4;
     587  	      continue;
     588  	    }
     589  
     590  	  *inptrp = inptr;
     591  	  *outptrp = outptr;
     592  	  return __GCONV_ILLEGAL_INPUT;
     593  	}
     594      }
     595    while (len > 0);
     596  
     597    *inptrp = inptr;
     598    *outptrp = outptr;
     599  
     600    /* Determine the status.  */
     601    if (*inptrp == inend)
     602      result = __GCONV_EMPTY_INPUT;
     603    else if (*outptrp + 4 > outend)
     604      result = __GCONV_FULL_OUTPUT;
     605    else
     606      result = __GCONV_INCOMPLETE_INPUT;
     607  
     608    return result;
     609  }
     610  
     611  ICONV_VX_SINGLE (ucs4_internal_loop)
     612  # include <iconv/skeleton.c>
     613  ICONV_VX_IFUNC (__gconv_transform_ucs4_internal)
     614  
     615  
     616  /* Transform from UCS4-LE to the internal encoding.  */
     617  # define DEFINE_INIT		0
     618  # define DEFINE_FINI		0
     619  # define MIN_NEEDED_FROM	4
     620  # define MIN_NEEDED_TO		4
     621  # define FROM_DIRECTION		1
     622  # define FROM_LOOP		ICONV_VX_NAME (ucs4le_internal_loop)
     623  # define TO_LOOP		ICONV_VX_NAME (ucs4le_internal_loop) /* This is not used.  */
     624  # define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs4le_internal)
     625  # define ONE_DIRECTION		0
     626  
     627  static inline int
     628  __attribute ((always_inline))
     629  ICONV_VX_NAME (ucs4le_internal_loop) (struct __gconv_step *step,
     630  				      struct __gconv_step_data *step_data,
     631  				      const unsigned char **inptrp,
     632  				      const unsigned char *inend,
     633  				      unsigned char **outptrp,
     634  				      const unsigned char *outend,
     635  				      size_t *irreversible)
     636  {
     637    int flags = step_data->__flags;
     638    const unsigned char *inptr = *inptrp;
     639    unsigned char *outptr = *outptrp;
     640    int result;
     641    size_t len, loop_count;
     642    do
     643      {
     644        len = MIN (inend - inptr, outend - outptr) / 4;
     645        __asm__ volatile (".machine push\n\t"
     646  			".machine \"z13\"\n\t"
     647  			".machinemode \"zarch_nohighgprs\"\n\t"
     648  			CONVERT_32BIT_SIZE_T ([R_LEN])
     649  			/* Setup to check for ch > 0x7fffffff.  */
     650  			"    larl %[R_LI],9f\n\t"
     651  			"    vlm %%v20,%%v22,0(%[R_LI])\n\t"
     652  			"    srlg %[R_LI],%[R_LEN],2\n\t"
     653  			"    clgije %[R_LI],0,1f\n\t"
     654  			/* Process 16byte (4char) blocks.  */
     655  			"0:  vl %%v16,0(%[R_IN])\n\t"
     656  			"    vperm %%v16,%%v16,%%v16,%%v22\n\t"
     657  			"    vstrcfs %%v23,%%v16,%%v20,%%v21\n\t"
     658  			"    jno 10f\n\t"
     659  			"    vst %%v16,0(%[R_OUT])\n\t"
     660  			"    la %[R_IN],16(%[R_IN])\n\t"
     661  			"    la %[R_OUT],16(%[R_OUT])\n\t"
     662  			"    brctg %[R_LI],0b\n\t"
     663  			"    llgfr %[R_LEN],%[R_LEN]\n\t"
     664  			"    nilf %[R_LEN],3\n\t"
     665  			/* Process <16bytes.  */
     666  			"1:  sll %[R_LEN],2\n\t"
     667  			"    ahik %[R_LI],%[R_LEN],-1\n\t"
     668  			"    jl 20f\n\t" /* No further bytes available.  */
     669  			"    vll %%v16,%[R_LI],0(%[R_IN])\n\t"
     670  			"    vperm %%v16,%%v16,%%v16,%%v22\n\t"
     671  			"    vstrcfs %%v23,%%v16,%%v20,%%v21\n\t"
     672  			"    vlgvb %[R_LI],%%v23,7\n\t"
     673  			"    clr %[R_LI],%[R_LEN]\n\t"
     674  			"    locgrhe %[R_LI],%[R_LEN]\n\t"
     675  			"    locghihe %[R_LEN],0\n\t"
     676  			"    j 11f\n\t"
     677  			/* v20: Vector string range compare values.  */
     678  			"9: .long 0x7fffffff,0x0,0x0,0x0\n\t"
     679  			/* v21: Vector string range compare control-bits.
     680  			   element 0: >; element 1: =<> (always true)  */
     681  			"    .long 0x20000000,0xE0000000,0x0,0x0\n\t"
     682  			/* v22: Vector permute mask.  */
     683  			"    .long 0x03020100,0x7060504,0x0B0A0908,0x0F0E0D0C\n\t"
     684  			/* Found a value > 0x7fffffff.  */
     685  			"10: vlgvb %[R_LI],%%v23,7\n\t"
     686  			/* Store characters before invalid one.  */
     687  			"11: aghi %[R_LI],-1\n\t"
     688  			"    jl 20f\n\t"
     689  			"    vstl %%v16,%[R_LI],0(%[R_OUT])\n\t"
     690  			"    la %[R_IN],1(%[R_LI],%[R_IN])\n\t"
     691  			"    la %[R_OUT],1(%[R_LI],%[R_OUT])\n\t"
     692  			"20:\n\t"
     693  			".machine pop"
     694  			: /* outputs */ [R_OUT] "+a" (outptr)
     695  			  , [R_IN] "+a" (inptr)
     696  			  , [R_LI] "=a" (loop_count)
     697  			  , [R_LEN] "+d" (len)
     698  			: /* inputs */
     699  			: /* clobber list*/ "memory", "cc"
     700  			  ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v20")
     701  			  ASM_CLOBBER_VR ("v21") ASM_CLOBBER_VR ("v22")
     702  			  ASM_CLOBBER_VR ("v23")
     703  			);
     704        if (len > 0)
     705  	{
     706  	  /* The value is too large.  We don't try transliteration here since
     707  	     this is not an error because of the lack of possibilities to
     708  	     represent the result.  This is a genuine bug in the input since
     709  	     UCS4 does not allow such values.  */
     710  	  if (irreversible == NULL)
     711  	    /* We are transliterating, don't try to correct anything.  */
     712  	    return __GCONV_ILLEGAL_INPUT;
     713  
     714  	  if (flags & __GCONV_IGNORE_ERRORS)
     715  	    {
     716  	      /* Just ignore this character.  */
     717  	      ++*irreversible;
     718  	      inptr += 4;
     719  	      continue;
     720  	    }
     721  
     722  	  *inptrp = inptr;
     723  	  *outptrp = outptr;
     724  	  return __GCONV_ILLEGAL_INPUT;
     725  	}
     726      }
     727    while (len > 0);
     728  
     729    *inptrp = inptr;
     730    *outptrp = outptr;
     731  
     732    /* Determine the status.  */
     733    if (*inptrp == inend)
     734      result = __GCONV_EMPTY_INPUT;
     735    else if (*inptrp + 4 > inend)
     736      result = __GCONV_INCOMPLETE_INPUT;
     737    else
     738      {
     739        assert (*outptrp + 4 > outend);
     740        result = __GCONV_FULL_OUTPUT;
     741      }
     742  
     743    return result;
     744  }
     745  ICONV_VX_SINGLE (ucs4le_internal_loop)
     746  # include <iconv/skeleton.c>
     747  ICONV_VX_IFUNC (__gconv_transform_ucs4le_internal)
     748  
     749  /* Convert from UCS2 to the internal (UCS4-like) format.  */
     750  # define DEFINE_INIT		0
     751  # define DEFINE_FINI		0
     752  # define MIN_NEEDED_FROM	2
     753  # define MIN_NEEDED_TO		4
     754  # define FROM_DIRECTION		1
     755  # define FROM_LOOP		ICONV_VX_NAME (ucs2_internal_loop)
     756  # define TO_LOOP		ICONV_VX_NAME (ucs2_internal_loop) /* This is not used.  */
     757  # define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs2_internal)
     758  # define ONE_DIRECTION		1
     759  
     760  # define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
     761  # define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
     762  # define LOOPFCT		FROM_LOOP
     763  # define BODY_ORIG_ERROR						\
     764    /* Surrogate characters in UCS-2 input are not valid.  Reject		\
     765       them.  (Catching this here is not security relevant.)  */		\
     766    STANDARD_FROM_LOOP_ERR_HANDLER (2);
     767  # define BODY_ORIG							\
     768    {									\
     769      uint16_t u1 = get16 (inptr);					\
     770  									\
     771      if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			\
     772        {									\
     773  	BODY_ORIG_ERROR							\
     774        }									\
     775  									\
     776      *((uint32_t *) outptr) = u1;					\
     777      outptr += sizeof (uint32_t);					\
     778      inptr += 2;								\
     779    }
     780  # define BODY								\
     781    {									\
     782      size_t len, tmp, tmp2;						\
     783      len = MIN ((inend - inptr) / 2, (outend - outptr) / 4);		\
     784      __asm__ volatile (".machine push\n\t"				\
     785  		      ".machine \"z13\"\n\t"				\
     786  		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
     787  		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
     788  		      /* Setup to check for ch >= 0xd800 && ch < 0xe000.  */ \
     789  		      "    larl %[R_TMP],9f\n\t"			\
     790  		      "    vlm %%v20,%%v21,0(%[R_TMP])\n\t"		\
     791  		      "    srlg %[R_TMP],%[R_LEN],3\n\t"		\
     792  		      "    clgije %[R_TMP],0,1f\n\t"			\
     793  		      /* Process 16byte (8char) blocks.  */		\
     794  		      "0:  vl %%v16,0(%[R_IN])\n\t"			\
     795  		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
     796  		      /* Enlarge UCS2 to UCS4.  */			\
     797  		      "    vuplhh %%v17,%%v16\n\t"			\
     798  		      "    vupllh %%v18,%%v16\n\t"			\
     799  		      "    jno 10f\n\t"					\
     800  		      /* Store 32bytes to buf_out.  */			\
     801  		      "    vstm %%v17,%%v18,0(%[R_OUT])\n\t"		\
     802  		      "    la %[R_IN],16(%[R_IN])\n\t"			\
     803  		      "    la %[R_OUT],32(%[R_OUT])\n\t"		\
     804  		      "    brctg %[R_TMP],0b\n\t"			\
     805  		      "    llgfr %[R_LEN],%[R_LEN]\n\t"			\
     806  		      "    nilf %[R_LEN],7\n\t"				\
     807  		      /* Process <16bytes.  */				\
     808  		      "1:  sll %[R_LEN],1\n\t"				\
     809  		      "    ahik %[R_TMP],%[R_LEN],-1\n\t"		\
     810  		      "    jl 20f\n\t" /* No further bytes available.  */ \
     811  		      "    vll %%v16,%[R_TMP],0(%[R_IN])\n\t"		\
     812  		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
     813  		      /* Enlarge UCS2 to UCS4.  */			\
     814  		      "    vuplhh %%v17,%%v16\n\t"			\
     815  		      "    vupllh %%v18,%%v16\n\t"			\
     816  		      "    vlgvb %[R_TMP],%%v19,7\n\t"			\
     817  		      "    clr %[R_TMP],%[R_LEN]\n\t"			\
     818  		      "    locgrhe %[R_TMP],%[R_LEN]\n\t"		\
     819  		      "    locghihe %[R_LEN],0\n\t"			\
     820  		      "    j 11f\n\t"					\
     821  		      /* v20: Vector string range compare values.  */	\
     822  		      "9:  .short 0xd800,0xe000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
     823  		      /* v21: Vector string range compare control-bits.	\
     824  			 element 0: =>; element 1: <  */		\
     825  		      "    .short 0xa000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
     826  		      /* Found an element: ch >= 0xd800 && ch < 0xe000  */ \
     827  		      "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
     828  		      "11: la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
     829  		      "    sll %[R_TMP],1\n\t"				\
     830  		      "    lgr %[R_TMP2],%[R_TMP]\n\t"			\
     831  		      "    ahi %[R_TMP],-1\n\t"				\
     832  		      "    jl 20f\n\t"					\
     833  		      "    vstl %%v17,%[R_TMP],0(%[R_OUT])\n\t"		\
     834  		      "    ahi %[R_TMP],-16\n\t"			\
     835  		      "    jl 19f\n\t"					\
     836  		      "    vstl %%v18,%[R_TMP],16(%[R_OUT])\n\t"	\
     837  		      "19: la %[R_OUT],0(%[R_TMP2],%[R_OUT])\n\t"	\
     838  		      "20: \n\t"					\
     839  		      ".machine pop"					\
     840  		      : /* outputs */ [R_OUT] "+a" (outptr)		\
     841  			, [R_IN] "+a" (inptr)				\
     842  			, [R_TMP] "=a" (tmp)				\
     843  			, [R_TMP2] "=a" (tmp2)				\
     844  			, [R_LEN] "+d" (len)				\
     845  		      : /* inputs */					\
     846  		      : /* clobber list*/ "memory", "cc"		\
     847  			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
     848  			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
     849  			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
     850  		      );						\
     851      if (len > 0)							\
     852        {									\
     853  	/* Found an invalid character at next input-char.  */		\
     854  	BODY_ORIG_ERROR							\
     855        }									\
     856    }
     857  
     858  # define LOOP_NEED_FLAGS
     859  # include <iconv/loop.c>
     860  # include <iconv/skeleton.c>
     861  # undef BODY_ORIG
     862  # undef BODY_ORIG_ERROR
     863  ICONV_VX_IFUNC (__gconv_transform_ucs2_internal)
     864  
     865  /* Convert from UCS2 in other endianness to the internal (UCS4-like) format. */
     866  # define DEFINE_INIT		0
     867  # define DEFINE_FINI		0
     868  # define MIN_NEEDED_FROM	2
     869  # define MIN_NEEDED_TO		4
     870  # define FROM_DIRECTION		1
     871  # define FROM_LOOP		ICONV_VX_NAME (ucs2reverse_internal_loop)
     872  # define TO_LOOP		ICONV_VX_NAME (ucs2reverse_internal_loop) /* This is not used.*/
     873  # define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_ucs2reverse_internal)
     874  # define ONE_DIRECTION		1
     875  
     876  # define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
     877  # define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
     878  # define LOOPFCT		FROM_LOOP
     879  # define BODY_ORIG_ERROR						\
     880    /* Surrogate characters in UCS-2 input are not valid.  Reject		\
     881       them.  (Catching this here is not security relevant.)  */		\
     882    if (! ignore_errors_p ())						\
     883      {									\
     884        result = __GCONV_ILLEGAL_INPUT;					\
     885        break;								\
     886      }									\
     887    inptr += 2;								\
     888    ++*irreversible;							\
     889    continue;
     890  
     891  # define BODY_ORIG \
     892    {									\
     893      uint16_t u1 = bswap_16 (get16 (inptr));				\
     894  									\
     895      if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			\
     896        {									\
     897  	BODY_ORIG_ERROR							\
     898        }									\
     899  									\
     900      *((uint32_t *) outptr) = u1;					\
     901      outptr += sizeof (uint32_t);					\
     902      inptr += 2;								\
     903    }
     904  # define BODY								\
     905    {									\
     906      size_t len, tmp, tmp2;						\
     907      len = MIN ((inend - inptr) / 2, (outend - outptr) / 4);		\
     908      __asm__ volatile (".machine push\n\t"				\
     909  		      ".machine \"z13\"\n\t"				\
     910  		      ".machinemode \"zarch_nohighgprs\"\n\t"		\
     911  		      CONVERT_32BIT_SIZE_T ([R_LEN])			\
     912  		      /* Setup to check for ch >= 0xd800 && ch < 0xe000.  */ \
     913  		      "    larl %[R_TMP],9f\n\t"			\
     914  		      "    vlm %%v20,%%v22,0(%[R_TMP])\n\t"		\
     915  		      "    srlg %[R_TMP],%[R_LEN],3\n\t"		\
     916  		      "    clgije %[R_TMP],0,1f\n\t"			\
     917  		      /* Process 16byte (8char) blocks.  */		\
     918  		      "0:  vl %%v16,0(%[R_IN])\n\t"			\
     919  		      "    vperm %%v16,%%v16,%%v16,%%v22\n\t"		\
     920  		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
     921  		      /* Enlarge UCS2 to UCS4.  */			\
     922  		      "    vuplhh %%v17,%%v16\n\t"			\
     923  		      "    vupllh %%v18,%%v16\n\t"			\
     924  		      "    jno 10f\n\t"					\
     925  		      /* Store 32bytes to buf_out.  */			\
     926  		      "    vstm %%v17,%%v18,0(%[R_OUT])\n\t"		\
     927  		      "    la %[R_IN],16(%[R_IN])\n\t"			\
     928  		      "    la %[R_OUT],32(%[R_OUT])\n\t"		\
     929  		      "    brctg %[R_TMP],0b\n\t"			\
     930  		      "    llgfr %[R_LEN],%[R_LEN]\n\t"			\
     931  		      "    nilf %[R_LEN],7\n\t"				\
     932  		      /* Process <16bytes.  */				\
     933  		      "1:  sll %[R_LEN],1\n\t"				\
     934  		      "    ahik %[R_TMP],%[R_LEN],-1\n\t"		\
     935  		      "    jl 20f\n\t" /* No further bytes available.  */ \
     936  		      "    vll %%v16,%[R_TMP],0(%[R_IN])\n\t"		\
     937  		      "    vperm %%v16,%%v16,%%v16,%%v22\n\t"		\
     938  		      "    vstrchs %%v19,%%v16,%%v20,%%v21\n\t"		\
     939  		      /* Enlarge UCS2 to UCS4.  */			\
     940  		      "    vuplhh %%v17,%%v16\n\t"			\
     941  		      "    vupllh %%v18,%%v16\n\t"			\
     942  		      "    vlgvb %[R_TMP],%%v19,7\n\t"			\
     943  		      "    clr %[R_TMP],%[R_LEN]\n\t"			\
     944  		      "    locgrhe %[R_TMP],%[R_LEN]\n\t"		\
     945  		      "    locghihe %[R_LEN],0\n\t"			\
     946  		      "    j 11f\n\t"					\
     947  		      /* v20: Vector string range compare values.  */	\
     948  		      "9:  .short 0xd800,0xe000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
     949  		      /* v21: Vector string range compare control-bits.	\
     950  			 element 0: =>; element 1: <  */		\
     951  		      "    .short 0xa000,0x4000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
     952  		      /* v22: Vector permute mask.  */			\
     953  		      "    .short 0x0100,0x0302,0x0504,0x0706\n\t"	\
     954  		      "    .short 0x0908,0x0b0a,0x0d0c,0x0f0e\n\t"	\
     955  		      /* Found an element: ch >= 0xd800 && ch < 0xe000  */ \
     956  		      "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
     957  		      "11: la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
     958  		      "    sll %[R_TMP],1\n\t"				\
     959  		      "    lgr %[R_TMP2],%[R_TMP]\n\t"			\
     960  		      "    ahi %[R_TMP],-1\n\t"				\
     961  		      "    jl 20f\n\t"					\
     962  		      "    vstl %%v17,%[R_TMP],0(%[R_OUT])\n\t"		\
     963  		      "    ahi %[R_TMP],-16\n\t"			\
     964  		      "    jl 19f\n\t"					\
     965  		      "    vstl %%v18,%[R_TMP],16(%[R_OUT])\n\t"	\
     966  		      "19: la %[R_OUT],0(%[R_TMP2],%[R_OUT])\n\t"	\
     967  		      "20: \n\t"					\
     968  		      ".machine pop"					\
     969  		      : /* outputs */ [R_OUT] "+a" (outptr)		\
     970  			, [R_IN] "+a" (inptr)				\
     971  			, [R_TMP] "=a" (tmp)				\
     972  			, [R_TMP2] "=a" (tmp2)				\
     973  			, [R_LEN] "+d" (len)				\
     974  		      : /* inputs */					\
     975  		      : /* clobber list*/ "memory", "cc"		\
     976  			ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
     977  			ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
     978  			ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21")	\
     979  			ASM_CLOBBER_VR ("v22")				\
     980  		      );						\
     981      if (len > 0)							\
     982        {									\
     983  	/* Found an invalid character at next input-char.  */		\
     984  	BODY_ORIG_ERROR							\
     985        }									\
     986    }
     987  # define LOOP_NEED_FLAGS
     988  # include <iconv/loop.c>
     989  # include <iconv/skeleton.c>
     990  # undef BODY_ORIG
     991  # undef BODY_ORIG_ERROR
     992  ICONV_VX_IFUNC (__gconv_transform_ucs2reverse_internal)
     993  
     994  /* Convert from the internal (UCS4-like) format to UCS2.  */
     995  #define DEFINE_INIT		0
     996  #define DEFINE_FINI		0
     997  #define MIN_NEEDED_FROM		4
     998  #define MIN_NEEDED_TO		2
     999  #define FROM_DIRECTION		1
    1000  #define FROM_LOOP		ICONV_VX_NAME (internal_ucs2_loop)
    1001  #define TO_LOOP			ICONV_VX_NAME (internal_ucs2_loop) /* This is not used.  */
    1002  #define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ucs2)
    1003  #define ONE_DIRECTION		1
    1004  
    1005  #define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
    1006  #define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
    1007  #define LOOPFCT			FROM_LOOP
    1008  #define BODY_ORIG							\
    1009    {									\
    1010      uint32_t val = *((const uint32_t *) inptr);				\
    1011  									\
    1012      if (__glibc_unlikely (val >= 0x10000))				\
    1013        {									\
    1014  	UNICODE_TAG_HANDLER (val, 4);					\
    1015  	STANDARD_TO_LOOP_ERR_HANDLER (4);				\
    1016        }									\
    1017      else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		\
    1018        {									\
    1019  	/* Surrogate characters in UCS-4 input are not valid.		\
    1020  	   We must catch this, because the UCS-2 output might be	\
    1021  	   interpreted as UTF-16 by other programs.  If we let		\
    1022  	   surrogates pass through, attackers could make a security	\
    1023  	   hole exploit by synthesizing any desired plane 1-16		\
    1024  	   character.  */						\
    1025  	result = __GCONV_ILLEGAL_INPUT;					\
    1026  	if (! ignore_errors_p ())					\
    1027  	  break;							\
    1028  	inptr += 4;							\
    1029  	++*irreversible;						\
    1030  	continue;							\
    1031        }									\
    1032      else								\
    1033        {									\
    1034  	put16 (outptr, val);						\
    1035  	outptr += sizeof (uint16_t);					\
    1036  	inptr += 4;							\
    1037        }									\
    1038    }
    1039  # define BODY								\
    1040    {									\
    1041      if (__builtin_expect (inend - inptr < 32, 1)			\
    1042  	|| outend - outptr < 16)					\
    1043        /* Convert remaining bytes with c code.  */			\
    1044        BODY_ORIG								\
    1045      else								\
    1046        {									\
    1047  	/* Convert in 32 byte blocks.  */				\
    1048  	size_t loop_count = (inend - inptr) / 32;			\
    1049  	size_t tmp, tmp2;						\
    1050  	if (loop_count > (outend - outptr) / 16)			\
    1051  	  loop_count = (outend - outptr) / 16;				\
    1052  	__asm__ volatile (".machine push\n\t"				\
    1053  			  ".machine \"z13\"\n\t"			\
    1054  			  ".machinemode \"zarch_nohighgprs\"\n\t"	\
    1055  			  CONVERT_32BIT_SIZE_T ([R_LI])			\
    1056  			  "    larl %[R_I],3f\n\t"			\
    1057  			  "    vlm %%v20,%%v23,0(%[R_I])\n\t"		\
    1058  			  "0:  \n\t"					\
    1059  			  "    vlm %%v16,%%v17,0(%[R_IN])\n\t"		\
    1060  			  /* Shorten UCS4 to UCS2.  */			\
    1061  			  "    vpkf %%v18,%%v16,%%v17\n\t"		\
    1062  			  "    vstrcfs %%v19,%%v16,%%v20,%%v21\n\t"	\
    1063  			  "    jno 11f\n\t"				\
    1064  			  "1:  vstrcfs %%v19,%%v17,%%v20,%%v21\n\t"	\
    1065  			  "    jno 10f\n\t"				\
    1066  			  /* Store 16bytes to buf_out.  */		\
    1067  			  "2:  vst %%v18,0(%[R_OUT])\n\t"		\
    1068  			  "    la %[R_IN],32(%[R_IN])\n\t"		\
    1069  			  "    la %[R_OUT],16(%[R_OUT])\n\t"		\
    1070  			  "    brctg %[R_LI],0b\n\t"			\
    1071  			  "    j 20f\n\t"				\
    1072  			  /* Setup to check for ch >= 0xd800. (v20, v21)  */ \
    1073  			  "3:  .long 0xd800,0xd800,0x0,0x0\n\t"		\
    1074  			  "    .long 0xa0000000,0xa0000000,0x0,0x0\n\t"	\
    1075  			  /* Setup to check for ch >= 0xe000		\
    1076  			     && ch < 0x10000. (v22,v23)  */		\
    1077  			  "    .long 0xe000,0x10000,0x0,0x0\n\t"	\
    1078  			  "    .long 0xa0000000,0x40000000,0x0,0x0\n\t"	\
    1079  			  /* v16 contains only valid chars. Check in v17: \
    1080  			     ch >= 0xe000 && ch <= 0xffff.  */		\
    1081  			  "10: vstrcfs %%v19,%%v17,%%v22,%%v23,8\n\t"	\
    1082  			  "    jo 2b\n\t" /* All ch's in this range, proceed.   */ \
    1083  			  "    lghi %[R_TMP],16\n\t"			\
    1084  			  "    j 12f\n\t"				\
    1085  			  /* Maybe v16 contains invalid chars.		\
    1086  			     Check ch >= 0xe000 && ch <= 0xffff.  */	\
    1087  			  "11: vstrcfs %%v19,%%v16,%%v22,%%v23,8\n\t"	\
    1088  			  "    jo 1b\n\t" /* All ch's in this range, proceed.   */ \
    1089  			  "    lghi %[R_TMP],0\n\t"			\
    1090  			  "12: vlgvb %[R_I],%%v19,7\n\t"		\
    1091  			  "    agr %[R_I],%[R_TMP]\n\t"			\
    1092  			  "    la %[R_IN],0(%[R_I],%[R_IN])\n\t"	\
    1093  			  "    srl %[R_I],1\n\t"			\
    1094  			  "    ahi %[R_I],-1\n\t"			\
    1095  			  "    jl 20f\n\t"				\
    1096  			  "    vstl %%v18,%[R_I],0(%[R_OUT])\n\t"	\
    1097  			  "    la %[R_OUT],1(%[R_I],%[R_OUT])\n\t"	\
    1098  			  "20:\n\t"					\
    1099  			  ".machine pop"				\
    1100  			  : /* outputs */ [R_OUT] "+a" (outptr)		\
    1101  			    , [R_IN] "+a" (inptr)			\
    1102  			    , [R_LI] "+d" (loop_count)			\
    1103  			    , [R_I] "=a" (tmp2)				\
    1104  			    , [R_TMP] "=d" (tmp)			\
    1105  			  : /* inputs */				\
    1106  			  : /* clobber list*/ "memory", "cc"		\
    1107  			    ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17") \
    1108  			    ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19") \
    1109  			    ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21") \
    1110  			    ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v23") \
    1111  			  );						\
    1112  	if (loop_count > 0)						\
    1113  	  {								\
    1114  	    /* Found an invalid character at next character.  */	\
    1115  	    BODY_ORIG							\
    1116  	  }								\
    1117        }									\
    1118    }
    1119  #define LOOP_NEED_FLAGS
    1120  #include <iconv/loop.c>
    1121  #include <iconv/skeleton.c>
    1122  # undef BODY_ORIG
    1123  ICONV_VX_IFUNC (__gconv_transform_internal_ucs2)
    1124  
    1125  /* Convert from the internal (UCS4-like) format to UCS2 in other endianness. */
    1126  #define DEFINE_INIT		0
    1127  #define DEFINE_FINI		0
    1128  #define MIN_NEEDED_FROM		4
    1129  #define MIN_NEEDED_TO		2
    1130  #define FROM_DIRECTION		1
    1131  #define FROM_LOOP		ICONV_VX_NAME (internal_ucs2reverse_loop)
    1132  #define TO_LOOP			ICONV_VX_NAME (internal_ucs2reverse_loop)/* This is not used.*/
    1133  #define FUNCTION_NAME		ICONV_VX_NAME (__gconv_transform_internal_ucs2reverse)
    1134  #define ONE_DIRECTION		1
    1135  
    1136  #define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
    1137  #define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
    1138  #define LOOPFCT			FROM_LOOP
    1139  #define BODY_ORIG							\
    1140    {									\
    1141      uint32_t val = *((const uint32_t *) inptr);				\
    1142      if (__glibc_unlikely (val >= 0x10000))				\
    1143        {									\
    1144  	UNICODE_TAG_HANDLER (val, 4);					\
    1145  	STANDARD_TO_LOOP_ERR_HANDLER (4);				\
    1146        }									\
    1147      else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		\
    1148        {									\
    1149  	/* Surrogate characters in UCS-4 input are not valid.		\
    1150  	   We must catch this, because the UCS-2 output might be	\
    1151  	   interpreted as UTF-16 by other programs.  If we let		\
    1152  	   surrogates pass through, attackers could make a security	\
    1153  	   hole exploit by synthesizing any desired plane 1-16		\
    1154  	   character.  */						\
    1155  	if (! ignore_errors_p ())					\
    1156  	  {								\
    1157  	    result = __GCONV_ILLEGAL_INPUT;				\
    1158  	    break;							\
    1159  	  }								\
    1160  	inptr += 4;							\
    1161  	++*irreversible;						\
    1162  	continue;							\
    1163        }									\
    1164      else								\
    1165        {									\
    1166  	put16 (outptr, bswap_16 (val));					\
    1167  	outptr += sizeof (uint16_t);					\
    1168  	inptr += 4;							\
    1169        }									\
    1170    }
    1171  # define BODY								\
    1172    {									\
    1173      if (__builtin_expect (inend - inptr < 32, 1)			\
    1174  	|| outend - outptr < 16)					\
    1175        /* Convert remaining bytes with c code.  */			\
    1176        BODY_ORIG								\
    1177      else								\
    1178        {									\
    1179  	/* Convert in 32 byte blocks.  */				\
    1180  	size_t loop_count = (inend - inptr) / 32;			\
    1181  	size_t tmp, tmp2;						\
    1182  	if (loop_count > (outend - outptr) / 16)			\
    1183  	  loop_count = (outend - outptr) / 16;				\
    1184  	__asm__ volatile (".machine push\n\t"				\
    1185  			  ".machine \"z13\"\n\t"			\
    1186  			  ".machinemode \"zarch_nohighgprs\"\n\t"	\
    1187  			  CONVERT_32BIT_SIZE_T ([R_LI])			\
    1188  			  "    larl %[R_I],3f\n\t"			\
    1189  			  "    vlm %%v20,%%v24,0(%[R_I])\n\t"		\
    1190  			  "0:  \n\t"					\
    1191  			  "    vlm %%v16,%%v17,0(%[R_IN])\n\t"		\
    1192  			  /* Shorten UCS4 to UCS2 and byteswap.  */	\
    1193  			  "    vpkf %%v18,%%v16,%%v17\n\t"		\
    1194  			  "    vperm %%v18,%%v18,%%v18,%%v24\n\t"	\
    1195  			  "    vstrcfs %%v19,%%v16,%%v20,%%v21\n\t"	\
    1196  			  "    jno 11f\n\t"				\
    1197  			  "1:  vstrcfs %%v19,%%v17,%%v20,%%v21\n\t"	\
    1198  			  "    jno 10f\n\t"				\
    1199  			  /* Store 16bytes to buf_out.  */		\
    1200  			  "2: vst %%v18,0(%[R_OUT])\n\t"		\
    1201  			  "    la %[R_IN],32(%[R_IN])\n\t"		\
    1202  			  "    la %[R_OUT],16(%[R_OUT])\n\t"		\
    1203  			  "    brctg %[R_LI],0b\n\t"			\
    1204  			  "    j 20f\n\t"				\
    1205  			  /* Setup to check for ch >= 0xd800. (v20, v21)  */ \
    1206  			  "3: .long 0xd800,0xd800,0x0,0x0\n\t"		\
    1207  			  "    .long 0xa0000000,0xa0000000,0x0,0x0\n\t"	\
    1208  			  /* Setup to check for ch >= 0xe000		\
    1209  			     && ch < 0x10000. (v22,v23)  */		\
    1210  			  "    .long 0xe000,0x10000,0x0,0x0\n\t"	\
    1211  			  "    .long 0xa0000000,0x40000000,0x0,0x0\n\t"	\
    1212  			  /* Vector permute mask (v24)  */		\
    1213  			  "    .short 0x0100,0x0302,0x0504,0x0706\n\t"	\
    1214  			  "    .short 0x0908,0x0b0a,0x0d0c,0x0f0e\n\t"	\
    1215  			  /* v16 contains only valid chars. Check in v17: \
    1216  			     ch >= 0xe000 && ch <= 0xffff.  */		\
    1217  			  "10: vstrcfs %%v19,%%v17,%%v22,%%v23,8\n\t"	\
    1218  			  "    jo 2b\n\t" /* All ch's in this range, proceed.  */ \
    1219  			  "    lghi %[R_TMP],16\n\t"			\
    1220  			  "    j 12f\n\t"				\
    1221  			  /* Maybe v16 contains invalid chars.		\
    1222  			     Check ch >= 0xe000 && ch <= 0xffff.  */	\
    1223  			  "11: vstrcfs %%v19,%%v16,%%v22,%%v23,8\n\t"	\
    1224  			  "    jo 1b\n\t" /* All ch's in this range, proceed.  */ \
    1225  			  "    lghi %[R_TMP],0\n\t"			\
    1226  			  "12: vlgvb %[R_I],%%v19,7\n\t"		\
    1227  			  "    agr %[R_I],%[R_TMP]\n\t"			\
    1228  			  "    la %[R_IN],0(%[R_I],%[R_IN])\n\t"	\
    1229  			  "    srl %[R_I],1\n\t"			\
    1230  			  "    ahi %[R_I],-1\n\t"			\
    1231  			  "    jl 20f\n\t"				\
    1232  			  "    vstl %%v18,%[R_I],0(%[R_OUT])\n\t"	\
    1233  			  "    la %[R_OUT],1(%[R_I],%[R_OUT])\n\t"	\
    1234  			  "20:\n\t"					\
    1235  			  ".machine pop"				\
    1236  			  : /* outputs */ [R_OUT] "+a" (outptr)		\
    1237  			    , [R_IN] "+a" (inptr)			\
    1238  			    , [R_LI] "+d" (loop_count)			\
    1239  			    , [R_I] "=a" (tmp2)				\
    1240  			    , [R_TMP] "=d" (tmp)			\
    1241  			  : /* inputs */				\
    1242  			  : /* clobber list*/ "memory", "cc"		\
    1243  			    ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17") \
    1244  			    ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19") \
    1245  			    ASM_CLOBBER_VR ("v20") ASM_CLOBBER_VR ("v21") \
    1246  			    ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v23") \
    1247  			    ASM_CLOBBER_VR ("v24")			\
    1248  			  );						\
    1249  	if (loop_count > 0)						\
    1250  	  {								\
    1251  	    /* Found an invalid character at next character.  */	\
    1252  	    BODY_ORIG							\
    1253  	  }								\
    1254        }									\
    1255    }
    1256  #define LOOP_NEED_FLAGS
    1257  #include <iconv/loop.c>
    1258  #include <iconv/skeleton.c>
    1259  # undef BODY_ORIG
    1260  ICONV_VX_IFUNC (__gconv_transform_internal_ucs2reverse)
    1261  
    1262  
    1263  #else
    1264  /* Generate the internal transformations without ifunc if build environment
    1265     lacks vector support. Instead simply include the common version.  */
    1266  # include <iconv/gconv_simple.c>
    1267  #endif /* !defined HAVE_S390_VX_ASM_SUPPORT */