Blame sysdeps/s390/utf16-utf32-z9.c

Packit 6c4009
/* Conversion between UTF-16 and UTF-32 BE/internal.
Packit 6c4009
Packit 6c4009
   This module uses the Z9-109 variants of the Convert Unicode
Packit 6c4009
   instructions.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
Packit 6c4009
   Author: Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
Packit 6c4009
   Based on the work by Ulrich Drepper  <drepper@cygnus.com>, 1997.
Packit 6c4009
Packit 6c4009
   Thanks to Daniel Appich who covered the relevant performance work
Packit 6c4009
   in his diploma thesis.
Packit 6c4009
Packit 6c4009
   This 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
   This 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
#include <dlfcn.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <gconv.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
/* Select which versions should be defined depending on support
Packit 6c4009
   for multiarch, vector and used minimum architecture level.  */
Packit 6c4009
#define HAVE_FROM_C		1
Packit 6c4009
#define FROM_LOOP_DEFAULT	FROM_LOOP_C
Packit 6c4009
#define HAVE_TO_C		1
Packit 6c4009
#define TO_LOOP_DEFAULT		TO_LOOP_C
Packit 6c4009
Packit 6c4009
#if defined HAVE_S390_VX_ASM_SUPPORT && defined USE_MULTIARCH
Packit 6c4009
# define HAVE_FROM_VX		1
Packit 6c4009
# define HAVE_FROM_VX_CU	1
Packit 6c4009
# define HAVE_TO_VX		1
Packit 6c4009
# define HAVE_TO_VX_CU		1
Packit 6c4009
#else
Packit 6c4009
# define HAVE_FROM_VX		0
Packit 6c4009
# define HAVE_FROM_VX_CU	0
Packit 6c4009
# define HAVE_TO_VX		0
Packit 6c4009
# define HAVE_TO_VX_CU		0
Packit 6c4009
#endif
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
#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
/* UTF-32 big endian byte order mark.  */
Packit 6c4009
#define BOM_UTF32               0x0000feffu
Packit 6c4009
Packit 6c4009
/* UTF-16 big endian byte order mark.  */
Packit 6c4009
#define BOM_UTF16               0xfeff
Packit 6c4009
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		2
Packit 6c4009
#define MAX_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_LOOP		FROM_LOOP_DEFAULT
Packit 6c4009
#define TO_LOOP			TO_LOOP_DEFAULT
Packit 6c4009
#define FROM_DIRECTION		(dir == from_utf16)
Packit 6c4009
#define ONE_DIRECTION           0
Packit 6c4009
Packit 6c4009
/* Direction of the transformation.  */
Packit 6c4009
enum direction
Packit 6c4009
{
Packit 6c4009
  illegal_dir,
Packit 6c4009
  to_utf16,
Packit 6c4009
  from_utf16
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
struct utf16_data
Packit 6c4009
{
Packit 6c4009
  enum direction dir;
Packit 6c4009
  int emit_bom;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
extern int gconv_init (struct __gconv_step *step);
Packit 6c4009
int
Packit 6c4009
gconv_init (struct __gconv_step *step)
Packit 6c4009
{
Packit 6c4009
  /* Determine which direction.  */
Packit 6c4009
  struct utf16_data *new_data;
Packit 6c4009
  enum direction dir = illegal_dir;
Packit 6c4009
  int emit_bom;
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
  emit_bom = (__strcasecmp (step->__to_name, "UTF-32//") == 0
Packit 6c4009
	      || __strcasecmp (step->__to_name, "UTF-16//") == 0);
Packit 6c4009
Packit 6c4009
  if (__strcasecmp (step->__from_name, "UTF-16BE//") == 0
Packit 6c4009
      && (__strcasecmp (step->__to_name, "UTF-32//") == 0
Packit 6c4009
	  || __strcasecmp (step->__to_name, "UTF-32BE//") == 0
Packit 6c4009
	  || __strcasecmp (step->__to_name, "INTERNAL") == 0))
Packit 6c4009
    {
Packit 6c4009
      dir = from_utf16;
Packit 6c4009
    }
Packit 6c4009
  else if ((__strcasecmp (step->__to_name, "UTF-16//") == 0
Packit 6c4009
	    || __strcasecmp (step->__to_name, "UTF-16BE//") == 0)
Packit 6c4009
	   && (__strcasecmp (step->__from_name, "UTF-32BE//") == 0
Packit 6c4009
	       || __strcasecmp (step->__from_name, "INTERNAL") == 0))
Packit 6c4009
    {
Packit 6c4009
      dir = to_utf16;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  result = __GCONV_NOCONV;
Packit 6c4009
  if (dir != illegal_dir)
Packit 6c4009
    {
Packit 6c4009
      new_data = (struct utf16_data *) malloc (sizeof (struct utf16_data));
Packit 6c4009
Packit 6c4009
      result = __GCONV_NOMEM;
Packit 6c4009
      if (new_data != NULL)
Packit 6c4009
	{
Packit 6c4009
	  new_data->dir = dir;
Packit 6c4009
	  new_data->emit_bom = emit_bom;
Packit 6c4009
	  step->__data = new_data;
Packit 6c4009
Packit 6c4009
	  if (dir == from_utf16)
Packit 6c4009
	    {
Packit 6c4009
	      step->__min_needed_from = MIN_NEEDED_FROM;
Packit 6c4009
	      step->__max_needed_from = MIN_NEEDED_FROM;
Packit 6c4009
	      step->__min_needed_to = MIN_NEEDED_TO;
Packit 6c4009
	      step->__max_needed_to = MIN_NEEDED_TO;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      step->__min_needed_from = MIN_NEEDED_TO;
Packit 6c4009
	      step->__max_needed_from = MIN_NEEDED_TO;
Packit 6c4009
	      step->__min_needed_to = MIN_NEEDED_FROM;
Packit 6c4009
	      step->__max_needed_to = MIN_NEEDED_FROM;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  step->__stateful = 0;
Packit 6c4009
Packit 6c4009
	  result = __GCONV_OK;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
extern void gconv_end (struct __gconv_step *data);
Packit 6c4009
void
Packit 6c4009
gconv_end (struct __gconv_step *data)
Packit 6c4009
{
Packit 6c4009
  free (data->__data);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define PREPARE_LOOP							\
Packit 6c4009
  enum direction dir = ((struct utf16_data *) step->__data)->dir;	\
Packit 6c4009
  int emit_bom = ((struct utf16_data *) step->__data)->emit_bom;	\
Packit 6c4009
									\
Packit 6c4009
  if (emit_bom && !data->__internal_use					\
Packit 6c4009
      && data->__invocation_counter == 0)				\
Packit 6c4009
    {									\
Packit 6c4009
      if (dir == to_utf16)						\
Packit 6c4009
	{								\
Packit 6c4009
	  /* Emit the UTF-16 Byte Order Mark.  */			\
Packit 6c4009
	  if (__glibc_unlikely (outbuf + 2 > outend))			\
Packit 6c4009
	    return __GCONV_FULL_OUTPUT;					\
Packit 6c4009
									\
Packit 6c4009
	  put16u (outbuf, BOM_UTF16);					\
Packit 6c4009
	  outbuf += 2;							\
Packit 6c4009
	}								\
Packit 6c4009
      else								\
Packit 6c4009
	{								\
Packit 6c4009
	  /* Emit the UTF-32 Byte Order Mark.  */			\
Packit 6c4009
	  if (__glibc_unlikely (outbuf + 4 > outend))			\
Packit 6c4009
	    return __GCONV_FULL_OUTPUT;					\
Packit 6c4009
									\
Packit 6c4009
	  put32u (outbuf, BOM_UTF32);					\
Packit 6c4009
	  outbuf += 4;							\
Packit 6c4009
	}								\
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
/* Conversion function from UTF-16 to UTF-32 internal/BE.  */
Packit 6c4009
Packit 6c4009
#if HAVE_FROM_C == 1
Packit 6c4009
/* The software routine is copied from utf-16.c (minus bytes
Packit 6c4009
   swapping).  */
Packit 6c4009
# define BODY_FROM_C							\
Packit 6c4009
  {									\
Packit 6c4009
    uint16_t u1 = get16 (inptr);					\
Packit 6c4009
									\
Packit 6c4009
    if (__builtin_expect (u1 < 0xd800, 1) || u1 > 0xdfff)		\
Packit 6c4009
      {									\
Packit 6c4009
	/* No surrogate.  */						\
Packit 6c4009
	put32 (outptr, u1);						\
Packit 6c4009
	inptr += 2;							\
Packit 6c4009
      }									\
Packit 6c4009
    else								\
Packit 6c4009
      {									\
Packit 6c4009
	/* An isolated low-surrogate was found.  This has to be         \
Packit 6c4009
	   considered ill-formed.  */					\
Packit 6c4009
	if (__glibc_unlikely (u1 >= 0xdc00))				\
Packit 6c4009
	  {								\
Packit 6c4009
	    STANDARD_FROM_LOOP_ERR_HANDLER (2);				\
Packit 6c4009
	  }								\
Packit 6c4009
	/* It's a surrogate character.  At least the first word says	\
Packit 6c4009
	   it is.  */							\
Packit 6c4009
	if (__glibc_unlikely (inptr + 4 > inend))			\
Packit 6c4009
	  {								\
Packit 6c4009
	    /* We don't have enough input for another complete input	\
Packit 6c4009
	       character.  */						\
Packit 6c4009
	    result = __GCONV_INCOMPLETE_INPUT;				\
Packit 6c4009
	    break;							\
Packit 6c4009
	  }								\
Packit 6c4009
									\
Packit 6c4009
	inptr += 2;							\
Packit 6c4009
	uint16_t u2 = get16 (inptr);					\
Packit 6c4009
	if (__builtin_expect (u2 < 0xdc00, 0)				\
Packit 6c4009
	    || __builtin_expect (u2 > 0xdfff, 0))			\
Packit 6c4009
	  {								\
Packit 6c4009
	    /* This is no valid second word for a surrogate.  */	\
Packit 6c4009
	    inptr -= 2;							\
Packit 6c4009
	    STANDARD_FROM_LOOP_ERR_HANDLER (2);				\
Packit 6c4009
	  }								\
Packit 6c4009
									\
Packit 6c4009
	put32 (outptr, ((u1 - 0xd7c0) << 10) + (u2 - 0xdc00));		\
Packit 6c4009
	inptr += 2;							\
Packit 6c4009
      }									\
Packit 6c4009
    outptr += 4;							\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Generate loop-function with software routing.  */
Packit 6c4009
# define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
# define MAX_NEEDED_INPUT	MAX_NEEDED_FROM
Packit 6c4009
# define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
# define FROM_LOOP_C		__from_utf16_loop_c
Packit 6c4009
# define LOOPFCT		FROM_LOOP_C
Packit 6c4009
# define LOOP_NEED_FLAGS
Packit 6c4009
# define BODY			BODY_FROM_C
Packit 6c4009
# include <iconv/loop.c>
Packit 6c4009
#else
Packit 6c4009
# define FROM_LOOP_C		NULL
Packit 6c4009
#endif /* HAVE_FROM_C != 1  */
Packit 6c4009
Packit 6c4009
#if HAVE_FROM_VX == 1
Packit 6c4009
# define BODY_FROM_VX							\
Packit 6c4009
  {									\
Packit 6c4009
    size_t inlen = inend - inptr;					\
Packit 6c4009
    size_t outlen = outend - outptr;					\
Packit 6c4009
    unsigned long tmp, tmp2, tmp3;					\
Packit 6c4009
    asm volatile (".machine push\n\t"					\
Packit 6c4009
		  ".machine \"z13\"\n\t"				\
Packit 6c4009
		  ".machinemode \"zarch_nohighgprs\"\n\t"		\
Packit 6c4009
		  /* Setup to check for surrogates.  */			\
Packit 6c4009
		  "    larl %[R_TMP],9f\n\t"				\
Packit 6c4009
		  "    vlm %%v30,%%v31,0(%[R_TMP])\n\t"			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_INLEN])			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_OUTLEN])			\
Packit 6c4009
		  /* Loop which handles UTF-16 chars <0xd800, >0xdfff.  */ \
Packit 6c4009
		  "0:  clgijl %[R_INLEN],16,2f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],32,2f\n\t"			\
Packit 6c4009
		  "1:  vl %%v16,0(%[R_IN])\n\t"				\
Packit 6c4009
		  /* Check for surrogate chars.  */			\
Packit 6c4009
		  "    vstrchs %%v19,%%v16,%%v30,%%v31\n\t"		\
Packit 6c4009
		  "    jno 10f\n\t"					\
Packit 6c4009
		  /* Enlarge to UTF-32.  */				\
Packit 6c4009
		  "    vuplhh %%v17,%%v16\n\t"				\
Packit 6c4009
		  "    la %[R_IN],16(%[R_IN])\n\t"			\
Packit 6c4009
		  "    vupllh %%v18,%%v16\n\t"				\
Packit 6c4009
		  "    aghi %[R_INLEN],-16\n\t"				\
Packit 6c4009
		  /* Store 32 bytes to buf_out.  */			\
Packit 6c4009
		  "    vstm %%v17,%%v18,0(%[R_OUT])\n\t"		\
Packit 6c4009
		  "    aghi %[R_OUTLEN],-32\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],32(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    clgijl %[R_INLEN],16,2f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],32,2f\n\t"			\
Packit 6c4009
		  "    j 1b\n\t"					\
Packit 6c4009
		  /* Setup to check for ch >= 0xd800 && ch <= 0xdfff. (v30, v31)  */ \
Packit 6c4009
		  "9:  .short 0xd800,0xdfff,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
Packit 6c4009
		  "    .short 0xa000,0xc000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
Packit 6c4009
		  /* At least one uint16_t is in range of surrogates.	\
Packit 6c4009
		     Store the preceding chars.  */			\
Packit 6c4009
		  "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
Packit 6c4009
		  "    vuplhh %%v17,%%v16\n\t"				\
Packit 6c4009
		  "    sllg %[R_TMP3],%[R_TMP],1\n\t" /* Number of out bytes.  */ \
Packit 6c4009
		  "    ahik %[R_TMP2],%[R_TMP3],-1\n\t" /* Highest index to store.  */ \
Packit 6c4009
		  "    jl 12f\n\t"					\
Packit 6c4009
		  "    vstl %%v17,%[R_TMP2],0(%[R_OUT])\n\t"		\
Packit 6c4009
		  "    vupllh %%v18,%%v16\n\t"				\
Packit 6c4009
		  "    ahi %[R_TMP2],-16\n\t"				\
Packit 6c4009
		  "    jl 11f\n\t"					\
Packit 6c4009
		  "    vstl %%v18,%[R_TMP2],16(%[R_OUT])\n\t"		\
Packit 6c4009
		  "11: \n\t" /* Update pointers.  */			\
Packit 6c4009
		  "    la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
Packit 6c4009
		  "    slgr %[R_INLEN],%[R_TMP]\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],0(%[R_TMP3],%[R_OUT])\n\t"		\
Packit 6c4009
		  "    slgr %[R_OUTLEN],%[R_TMP3]\n\t"			\
Packit 6c4009
		  /* Calculate remaining uint16_t values in loaded vrs.  */ \
Packit 6c4009
		  "12: lghi %[R_TMP2],16\n\t"				\
Packit 6c4009
		  "    slgr %[R_TMP2],%[R_TMP]\n\t"			\
Packit 6c4009
		  "    srl %[R_TMP2],1\n\t"				\
Packit 6c4009
		  "    llh %[R_TMP],0(%[R_IN])\n\t"			\
Packit 6c4009
		  "    aghi %[R_OUTLEN],-4\n\t"				\
Packit 6c4009
		  "    j 16f\n\t"					\
Packit 6c4009
		  /* Handle remaining bytes.  */			\
Packit 6c4009
		  "2:  \n\t"						\
Packit 6c4009
		  /* Zero, one or more bytes available?  */		\
Packit 6c4009
		  "    clgfi %[R_INLEN],1\n\t"				\
Packit 6c4009
		  "    je 97f\n\t" /* Only one byte available.  */	\
Packit 6c4009
		  "    jl 99f\n\t" /* End if no bytes available.  */	\
Packit 6c4009
		  /* Calculate remaining uint16_t values in inptr.  */	\
Packit 6c4009
		  "    srlg %[R_TMP2],%[R_INLEN],1\n\t"			\
Packit 6c4009
		  /* Handle remaining uint16_t values.  */		\
Packit 6c4009
		  "13: llh %[R_TMP],0(%[R_IN])\n\t"			\
Packit 6c4009
		  "    slgfi %[R_OUTLEN],4\n\t"				\
Packit 6c4009
		  "    jl 96f \n\t"					\
Packit 6c4009
		  "    clfi %[R_TMP],0xd800\n\t"			\
Packit 6c4009
		  "    jhe 15f\n\t"					\
Packit 6c4009
		  "14: st %[R_TMP],0(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    la %[R_IN],2(%[R_IN])\n\t"			\
Packit 6c4009
		  "    aghi %[R_INLEN],-2\n\t"				\
Packit 6c4009
		  "    la %[R_OUT],4(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    brctg %[R_TMP2],13b\n\t"				\
Packit 6c4009
		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
Packit 6c4009
		  /* Handle UTF-16 surrogate pair.  */			\
Packit 6c4009
		  "15: clfi %[R_TMP],0xdfff\n\t"			\
Packit 6c4009
		  "    jh 14b\n\t" /* Jump away if ch > 0xdfff.  */	\
Packit 6c4009
		  "16: clfi %[R_TMP],0xdc00\n\t"			\
Packit 6c4009
		  "    jhe 98f\n\t" /* Jump away in case of low-surrogate.  */ \
Packit 6c4009
		  "    slgfi %[R_INLEN],4\n\t"				\
Packit 6c4009
		  "    jl 97f\n\t" /* Big enough input?  */		\
Packit 6c4009
		  "    llh %[R_TMP3],2(%[R_IN])\n\t" /* Load low surrogate.  */ \
Packit 6c4009
		  "    slfi %[R_TMP],0xd7c0\n\t"			\
Packit 6c4009
		  "    sll %[R_TMP],10\n\t"				\
Packit 6c4009
		  "    risbgn %[R_TMP],%[R_TMP3],54,63,0\n\t" /* Insert klmnopqrst.  */ \
Packit 6c4009
		  "    nilf %[R_TMP3],0xfc00\n\t"			\
Packit 6c4009
		  "    clfi %[R_TMP3],0xdc00\n\t" /* Check if it starts with 0xdc00.  */ \
Packit 6c4009
		  "    jne 98f\n\t"					\
Packit 6c4009
		  "    st %[R_TMP],0(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    la %[R_IN],4(%[R_IN])\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],4(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    aghi %[R_TMP2],-2\n\t"				\
Packit 6c4009
		  "    jh 13b\n\t" /* Handle remaining uint16_t values.  */ \
Packit 6c4009
		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
Packit 6c4009
		  "96: \n\t" /* Return full output.  */			\
Packit 6c4009
		  "    lghi %[R_RES],%[RES_OUT_FULL]\n\t"		\
Packit 6c4009
		  "    j 99f\n\t"					\
Packit 6c4009
		  "97: \n\t" /* Return incomplete input.  */		\
Packit 6c4009
		  "    lghi %[R_RES],%[RES_IN_FULL]\n\t"		\
Packit 6c4009
		  "    j 99f\n\t"					\
Packit 6c4009
		  "98:\n\t" /* Return Illegal character.  */		\
Packit 6c4009
		  "    lghi %[R_RES],%[RES_IN_ILL]\n\t"			\
Packit 6c4009
		  "99:\n\t"						\
Packit 6c4009
		  ".machine pop"					\
Packit 6c4009
		  : /* outputs */ [R_IN] "+a" (inptr)			\
Packit 6c4009
		    , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (outptr)	\
Packit 6c4009
		    , [R_OUTLEN] "+d" (outlen), [R_TMP] "=a" (tmp)	\
Packit 6c4009
		    , [R_TMP2] "=d" (tmp2), [R_TMP3] "=a" (tmp3)	\
Packit 6c4009
		    , [R_RES] "+d" (result)				\
Packit 6c4009
		  : /* inputs */					\
Packit 6c4009
		    [RES_OUT_FULL] "i" (__GCONV_FULL_OUTPUT)		\
Packit 6c4009
		    , [RES_IN_ILL] "i" (__GCONV_ILLEGAL_INPUT)		\
Packit 6c4009
		    , [RES_IN_FULL] "i" (__GCONV_INCOMPLETE_INPUT)	\
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 ("v30") ASM_CLOBBER_VR ("v31")	\
Packit 6c4009
		  );							\
Packit 6c4009
    if (__glibc_likely (inptr == inend)					\
Packit 6c4009
	|| result != __GCONV_ILLEGAL_INPUT)				\
Packit 6c4009
      break;								\
Packit 6c4009
									\
Packit 6c4009
    STANDARD_FROM_LOOP_ERR_HANDLER (2);					\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
/* Generate loop-function with hardware vector instructions.  */
Packit 6c4009
# define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
# define MAX_NEEDED_INPUT	MAX_NEEDED_FROM
Packit 6c4009
# define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
# define FROM_LOOP_VX		__from_utf16_loop_vx
Packit 6c4009
# define LOOPFCT		FROM_LOOP_VX
Packit 6c4009
# define LOOP_NEED_FLAGS
Packit 6c4009
# define BODY			BODY_FROM_VX
Packit 6c4009
# include <iconv/loop.c>
Packit 6c4009
#else
Packit 6c4009
# define FROM_LOOP_VX		NULL
Packit 6c4009
#endif /* HAVE_FROM_VX != 1  */
Packit 6c4009
Packit 6c4009
#if HAVE_FROM_VX_CU == 1
Packit 6c4009
#define BODY_FROM_VX_CU							\
Packit 6c4009
  {									\
Packit 6c4009
    register const unsigned char* pInput asm ("8") = inptr;		\
Packit 6c4009
    register size_t inlen asm ("9") = inend - inptr;			\
Packit 6c4009
    register unsigned char* pOutput asm ("10") = outptr;		\
Packit 6c4009
    register size_t outlen asm ("11") = outend - outptr;		\
Packit 6c4009
    unsigned long tmp, tmp2, tmp3;					\
Packit 6c4009
    asm volatile (".machine push\n\t"					\
Packit 6c4009
		  ".machine \"z13\"\n\t"				\
Packit 6c4009
		  ".machinemode \"zarch_nohighgprs\"\n\t"		\
Packit 6c4009
		  /* Setup to check for surrogates.  */			\
Packit 6c4009
		  "    larl %[R_TMP],9f\n\t"				\
Packit 6c4009
		  "    vlm %%v30,%%v31,0(%[R_TMP])\n\t"			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_INLEN])			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_OUTLEN])			\
Packit 6c4009
		  /* Loop which handles UTF-16 chars <0xd800, >0xdfff.  */ \
Packit 6c4009
		  "0:  clgijl %[R_INLEN],16,20f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],32,20f\n\t"			\
Packit 6c4009
		  "1:  vl %%v16,0(%[R_IN])\n\t"				\
Packit 6c4009
		  /* Check for surrogate chars.  */			\
Packit 6c4009
		  "    vstrchs %%v19,%%v16,%%v30,%%v31\n\t"		\
Packit 6c4009
		  "    jno 10f\n\t"					\
Packit 6c4009
		  /* Enlarge to UTF-32.  */				\
Packit 6c4009
		  "    vuplhh %%v17,%%v16\n\t"				\
Packit 6c4009
		  "    la %[R_IN],16(%[R_IN])\n\t"			\
Packit 6c4009
		  "    vupllh %%v18,%%v16\n\t"				\
Packit 6c4009
		  "    aghi %[R_INLEN],-16\n\t"				\
Packit 6c4009
		  /* Store 32 bytes to buf_out.  */			\
Packit 6c4009
		  "    vstm %%v17,%%v18,0(%[R_OUT])\n\t"		\
Packit 6c4009
		  "    aghi %[R_OUTLEN],-32\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],32(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    clgijl %[R_INLEN],16,20f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],32,20f\n\t"			\
Packit 6c4009
		  "    j 1b\n\t"					\
Packit 6c4009
		  /* Setup to check for ch >= 0xd800 && ch <= 0xdfff. (v30, v31)  */ \
Packit 6c4009
		  "9:  .short 0xd800,0xdfff,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
Packit 6c4009
		  "    .short 0xa000,0xc000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
Packit 6c4009
		  /* At least one uint16_t is in range of surrogates.	\
Packit 6c4009
		     Store the preceding chars.  */			\
Packit 6c4009
		  "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
Packit 6c4009
		  "    vuplhh %%v17,%%v16\n\t"				\
Packit 6c4009
		  "    sllg %[R_TMP3],%[R_TMP],1\n\t" /* Number of out bytes.  */ \
Packit 6c4009
		  "    ahik %[R_TMP2],%[R_TMP3],-1\n\t" /* Highest index to store.  */ \
Packit 6c4009
		  "    jl 20f\n\t"					\
Packit 6c4009
		  "    vstl %%v17,%[R_TMP2],0(%[R_OUT])\n\t"		\
Packit 6c4009
		  "    vupllh %%v18,%%v16\n\t"				\
Packit 6c4009
		  "    ahi %[R_TMP2],-16\n\t"				\
Packit 6c4009
		  "    jl 11f\n\t"					\
Packit 6c4009
		  "    vstl %%v18,%[R_TMP2],16(%[R_OUT])\n\t"		\
Packit 6c4009
		  "11: \n\t" /* Update pointers.  */			\
Packit 6c4009
		  "    la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
Packit 6c4009
		  "    slgr %[R_INLEN],%[R_TMP]\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],0(%[R_TMP3],%[R_OUT])\n\t"		\
Packit 6c4009
		  "    slgr %[R_OUTLEN],%[R_TMP3]\n\t"			\
Packit 6c4009
		  /* Handles UTF16 surrogates with convert instruction.  */ \
Packit 6c4009
		  "20: cu24 %[R_OUT],%[R_IN],1\n\t"			\
Packit 6c4009
		  "    jo 0b\n\t" /* Try vector implemenation again.  */ \
Packit 6c4009
		  "    lochil %[R_RES],%[RES_OUT_FULL]\n\t" /* cc == 1.  */ \
Packit 6c4009
		  "    lochih %[R_RES],%[RES_IN_ILL]\n\t" /* cc == 2.  */ \
Packit 6c4009
		  ".machine pop"					\
Packit 6c4009
		  : /* outputs */ [R_IN] "+a" (pInput)			\
Packit 6c4009
		    , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (pOutput)	\
Packit 6c4009
		    , [R_OUTLEN] "+d" (outlen), [R_TMP] "=a" (tmp)	\
Packit 6c4009
		    , [R_TMP2] "=d" (tmp2), [R_TMP3] "=a" (tmp3)	\
Packit 6c4009
		    , [R_RES] "+d" (result)				\
Packit 6c4009
		  : /* inputs */					\
Packit 6c4009
		    [RES_OUT_FULL] "i" (__GCONV_FULL_OUTPUT)		\
Packit 6c4009
		    , [RES_IN_ILL] "i" (__GCONV_ILLEGAL_INPUT)		\
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 ("v30") ASM_CLOBBER_VR ("v31")	\
Packit 6c4009
		  );							\
Packit 6c4009
    inptr = pInput;							\
Packit 6c4009
    outptr = pOutput;							\
Packit 6c4009
									\
Packit 6c4009
    if (__glibc_likely (inlen == 0)					\
Packit 6c4009
	|| result == __GCONV_FULL_OUTPUT)				\
Packit 6c4009
      break;								\
Packit 6c4009
    if (inlen == 1)							\
Packit 6c4009
      {									\
Packit 6c4009
	/* Input does not contain a complete utf16 character.  */	\
Packit 6c4009
	result = __GCONV_INCOMPLETE_INPUT;				\
Packit 6c4009
	break;								\
Packit 6c4009
      }									\
Packit 6c4009
    else if (result != __GCONV_ILLEGAL_INPUT)				\
Packit 6c4009
      {									\
Packit 6c4009
	/* Input is >= 2 and < 4 bytes (as cu24 would have processed	\
Packit 6c4009
	   a possible next utf16 character) and not illegal.		\
Packit 6c4009
	   => we have a single high surrogate at end of input.  */	\
Packit 6c4009
	result = __GCONV_INCOMPLETE_INPUT;				\
Packit 6c4009
	break;								\
Packit 6c4009
      }									\
Packit 6c4009
									\
Packit 6c4009
    STANDARD_FROM_LOOP_ERR_HANDLER (2);					\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
/* Generate loop-function with hardware vector and utf-convert instructions.  */
Packit 6c4009
# define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
# define MAX_NEEDED_INPUT	MAX_NEEDED_FROM
Packit 6c4009
# define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
# define FROM_LOOP_VX_CU	__from_utf16_loop_vx_cu
Packit 6c4009
# define LOOPFCT		FROM_LOOP_VX_CU
Packit 6c4009
# define LOOP_NEED_FLAGS
Packit 6c4009
# define BODY			BODY_FROM_VX_CU
Packit 6c4009
# include <iconv/loop.c>
Packit 6c4009
#else
Packit 6c4009
# define FROM_LOOP_VX_CU	NULL
Packit 6c4009
#endif /* HAVE_FROM_VX_CU != 1  */
Packit 6c4009
Packit 6c4009
/* Conversion from UTF-32 internal/BE to UTF-16.  */
Packit 6c4009
Packit 6c4009
#if HAVE_TO_C == 1
Packit 6c4009
/* The software routine is copied from utf-16.c (minus bytes
Packit 6c4009
   swapping).  */
Packit 6c4009
# define BODY_TO_C							\
Packit 6c4009
  {									\
Packit 6c4009
    uint32_t c = get32 (inptr);						\
Packit 6c4009
									\
Packit 6c4009
    if (__builtin_expect (c <= 0xd7ff, 1)				\
Packit 6c4009
	|| (c > 0xdfff && c <= 0xffff))					\
Packit 6c4009
      {									\
Packit 6c4009
	/* Two UTF-16 chars.  */					\
Packit 6c4009
	put16 (outptr, c);						\
Packit 6c4009
      }									\
Packit 6c4009
    else if (__builtin_expect (c >= 0x10000, 1)				\
Packit 6c4009
	     && __builtin_expect (c <= 0x10ffff, 1))			\
Packit 6c4009
      {									\
Packit 6c4009
	/* Four UTF-16 chars.  */					\
Packit 6c4009
	uint16_t zabcd = ((c & 0x1f0000) >> 16) - 1;			\
Packit 6c4009
	uint16_t out;							\
Packit 6c4009
									\
Packit 6c4009
	/* Generate a surrogate character.  */				\
Packit 6c4009
	if (__glibc_unlikely (outptr + 4 > outend))			\
Packit 6c4009
	  {								\
Packit 6c4009
	    /* Overflow in the output buffer.  */			\
Packit 6c4009
	    result = __GCONV_FULL_OUTPUT;				\
Packit 6c4009
	    break;							\
Packit 6c4009
	  }								\
Packit 6c4009
									\
Packit 6c4009
	out = 0xd800;							\
Packit 6c4009
	out |= (zabcd & 0xff) << 6;					\
Packit 6c4009
	out |= (c >> 10) & 0x3f;					\
Packit 6c4009
	put16 (outptr, out);						\
Packit 6c4009
	outptr += 2;							\
Packit 6c4009
									\
Packit 6c4009
	out = 0xdc00;							\
Packit 6c4009
	out |= c & 0x3ff;						\
Packit 6c4009
	put16 (outptr, out);						\
Packit 6c4009
      }									\
Packit 6c4009
    else								\
Packit 6c4009
      {									\
Packit 6c4009
	STANDARD_TO_LOOP_ERR_HANDLER (4);				\
Packit 6c4009
      }									\
Packit 6c4009
    outptr += 2;							\
Packit 6c4009
    inptr += 4;								\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
/* Generate loop-function with software routing.  */
Packit 6c4009
# define MIN_NEEDED_INPUT	MIN_NEEDED_TO
Packit 6c4009
# define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
Packit 6c4009
# define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
Packit 6c4009
# define TO_LOOP_C		__to_utf16_loop_c
Packit 6c4009
# define LOOPFCT		TO_LOOP_C
Packit 6c4009
# define LOOP_NEED_FLAGS
Packit 6c4009
# define BODY			BODY_TO_C
Packit 6c4009
# include <iconv/loop.c>
Packit 6c4009
#else
Packit 6c4009
# define TO_LOOP_C		NULL
Packit 6c4009
#endif /* HAVE_TO_C != 1  */
Packit 6c4009
Packit 6c4009
#if HAVE_TO_VX == 1
Packit 6c4009
# define BODY_TO_VX							\
Packit 6c4009
  {									\
Packit 6c4009
    size_t inlen = inend - inptr;					\
Packit 6c4009
    size_t outlen = outend - outptr;					\
Packit 6c4009
    unsigned long tmp, tmp2, tmp3;					\
Packit 6c4009
    asm volatile (".machine push\n\t"					\
Packit 6c4009
		  ".machine \"z13\"\n\t"				\
Packit 6c4009
		  ".machinemode \"zarch_nohighgprs\"\n\t"		\
Packit 6c4009
		  /* Setup to check for surrogates.  */			\
Packit 6c4009
		  "    larl %[R_TMP],9f\n\t"				\
Packit 6c4009
		  "    vlm %%v30,%%v31,0(%[R_TMP])\n\t"			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_INLEN])			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_OUTLEN])			\
Packit 6c4009
		  /* Loop which handles UTF-32 chars			\
Packit 6c4009
		     ch < 0xd800 || (ch > 0xdfff && ch < 0x10000).  */	\
Packit 6c4009
		  "0:  clgijl %[R_INLEN],32,2f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],16,2f\n\t"			\
Packit 6c4009
		  "1:  vlm %%v16,%%v17,0(%[R_IN])\n\t"			\
Packit 6c4009
		  "    lghi %[R_TMP2],0\n\t"				\
Packit 6c4009
		  /* Shorten to UTF-16.  */				\
Packit 6c4009
		  "    vpkf %%v18,%%v16,%%v17\n\t"			\
Packit 6c4009
		  /* Check for surrogate chars.  */			\
Packit 6c4009
		  "    vstrcfs %%v19,%%v16,%%v30,%%v31\n\t"		\
Packit 6c4009
		  "    jno 10f\n\t"					\
Packit 6c4009
		  "    vstrcfs %%v19,%%v17,%%v30,%%v31\n\t"		\
Packit 6c4009
		  "    jno 11f\n\t"					\
Packit 6c4009
		  /* Store 16 bytes to buf_out.  */			\
Packit 6c4009
		  "    vst %%v18,0(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    la %[R_IN],32(%[R_IN])\n\t"			\
Packit 6c4009
		  "    aghi %[R_INLEN],-32\n\t"				\
Packit 6c4009
		  "    aghi %[R_OUTLEN],-16\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],16(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    clgijl %[R_INLEN],32,2f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],16,2f\n\t"			\
Packit 6c4009
		  "    j 1b\n\t"					\
Packit 6c4009
		  /* Calculate remaining uint32_t values in inptr.  */	\
Packit 6c4009
		  "2:  \n\t"						\
Packit 6c4009
		  "    clgije %[R_INLEN],0,99f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_INLEN],4,92f\n\t"			\
Packit 6c4009
		  "    srlg %[R_TMP2],%[R_INLEN],2\n\t"			\
Packit 6c4009
		  "    j 20f\n\t"					\
Packit 6c4009
		  /* Setup to check for ch >= 0xd800 && ch <= 0xdfff	\
Packit 6c4009
		     and check for ch >= 0x10000. (v30, v31)  */	\
Packit 6c4009
		  "9:  .long 0xd800,0xdfff,0x10000,0x10000\n\t"		\
Packit 6c4009
		  "    .long 0xa0000000,0xc0000000, 0xa0000000,0xa0000000\n\t" \
Packit 6c4009
		  /* At least on UTF32 char is in range of surrogates.	\
Packit 6c4009
		     Store the preceding characters.  */		\
Packit 6c4009
		  "11: ahi %[R_TMP2],16\n\t"				\
Packit 6c4009
		  "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
Packit 6c4009
		  "    agr %[R_TMP],%[R_TMP2]\n\t"			\
Packit 6c4009
		  "    srlg %[R_TMP3],%[R_TMP],1\n\t" /* Number of out bytes.  */ \
Packit 6c4009
		  "    ahik %[R_TMP2],%[R_TMP3],-1\n\t" /* Highest index to store.  */ \
Packit 6c4009
		  "    jl 12f\n\t"					\
Packit 6c4009
		  "    vstl %%v18,%[R_TMP2],0(%[R_OUT])\n\t"		\
Packit 6c4009
		  /* Update pointers.  */				\
Packit 6c4009
		  "    la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
Packit 6c4009
		  "    slgr %[R_INLEN],%[R_TMP]\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],0(%[R_TMP3],%[R_OUT])\n\t"		\
Packit 6c4009
		  "    slgr %[R_OUTLEN],%[R_TMP3]\n\t"			\
Packit 6c4009
		  /* Calculate remaining uint32_t values in vrs.  */	\
Packit 6c4009
		  "12: lghi %[R_TMP2],8\n\t"				\
Packit 6c4009
		  "    srlg %[R_TMP3],%[R_TMP3],1\n\t"			\
Packit 6c4009
		  "    slgr %[R_TMP2],%[R_TMP3]\n\t"			\
Packit 6c4009
		  /* Handle remaining UTF-32 characters.  */		\
Packit 6c4009
		  "20: l %[R_TMP],0(%[R_IN])\n\t"			\
Packit 6c4009
		  "    aghi %[R_INLEN],-4\n\t"				\
Packit 6c4009
		  /* Test if ch is 2byte UTF-16 char. */		\
Packit 6c4009
		  "    clfi %[R_TMP],0xffff\n\t"			\
Packit 6c4009
		  "    jh 21f\n\t"					\
Packit 6c4009
		  /* Handle 2 byte UTF16 char.  */			\
Packit 6c4009
		  "    lgr %[R_TMP3],%[R_TMP]\n\t"			\
Packit 6c4009
		  "    nilf %[R_TMP],0xf800\n\t"			\
Packit 6c4009
		  "    clfi %[R_TMP],0xd800\n\t"			\
Packit 6c4009
		  "    je 91f\n\t" /* Do not accept UTF-16 surrogates.  */ \
Packit 6c4009
		  "    slgfi %[R_OUTLEN],2\n\t"				\
Packit 6c4009
		  "    jl 90f \n\t"					\
Packit 6c4009
		  "    sth %[R_TMP3],0(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    la %[R_IN],4(%[R_IN])\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],2(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    brctg %[R_TMP2],20b\n\t"				\
Packit 6c4009
		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
Packit 6c4009
		  /* Test if ch is 4byte UTF-16 char. */		\
Packit 6c4009
		  "21: clfi %[R_TMP],0x10ffff\n\t"			\
Packit 6c4009
		  "    jh 91f\n\t" /* ch > 0x10ffff is not allowed!  */	\
Packit 6c4009
		  /* Handle 4 byte UTF16 char.  */			\
Packit 6c4009
		  "    slgfi %[R_OUTLEN],4\n\t"				\
Packit 6c4009
		  "    jl 90f \n\t"					\
Packit 6c4009
		  "    slfi %[R_TMP],0x10000\n\t" /* zabcd = uvwxy - 1.  */ \
Packit 6c4009
		  "    llilf %[R_TMP3],0xd800dc00\n\t"			\
Packit 6c4009
		  "    la %[R_IN],4(%[R_IN])\n\t"			\
Packit 6c4009
		  "    risbgn %[R_TMP3],%[R_TMP],38,47,6\n\t" /* High surrogate.  */ \
Packit 6c4009
		  "    risbgn %[R_TMP3],%[R_TMP],54,63,0\n\t" /* Low surrogate.  */ \
Packit 6c4009
		  "    st %[R_TMP3],0(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],4(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    brctg %[R_TMP2],20b\n\t"				\
Packit 6c4009
		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
Packit 6c4009
		  "92: lghi %[R_RES],%[RES_IN_FULL]\n\t"		\
Packit 6c4009
		  "    j 99f\n\t"					\
Packit 6c4009
		  "91: lghi %[R_RES],%[RES_IN_ILL]\n\t"			\
Packit 6c4009
		  "    j 99f\n\t"					\
Packit 6c4009
		  "90: lghi %[R_RES],%[RES_OUT_FULL]\n\t"		\
Packit 6c4009
		  "99: \n\t"						\
Packit 6c4009
		  ".machine pop"					\
Packit 6c4009
		  : /* outputs */ [R_IN] "+a" (inptr)			\
Packit 6c4009
		    , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (outptr)	\
Packit 6c4009
		    , [R_OUTLEN] "+d" (outlen), [R_TMP] "=a" (tmp)	\
Packit 6c4009
		    , [R_TMP2] "=d" (tmp2), [R_TMP3] "=a" (tmp3)	\
Packit 6c4009
		    , [R_RES] "+d" (result)				\
Packit 6c4009
		  : /* inputs */					\
Packit 6c4009
		    [RES_OUT_FULL] "i" (__GCONV_FULL_OUTPUT)		\
Packit 6c4009
		    , [RES_IN_ILL] "i" (__GCONV_ILLEGAL_INPUT)		\
Packit 6c4009
		    , [RES_IN_FULL] "i" (__GCONV_INCOMPLETE_INPUT)	\
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 ("v30") ASM_CLOBBER_VR ("v31")	\
Packit 6c4009
		  );							\
Packit 6c4009
    if (__glibc_likely (inptr == inend)					\
Packit 6c4009
	|| result != __GCONV_ILLEGAL_INPUT)				\
Packit 6c4009
      break;								\
Packit 6c4009
									\
Packit 6c4009
    STANDARD_TO_LOOP_ERR_HANDLER (4);					\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
/* Generate loop-function with hardware vector instructions.  */
Packit 6c4009
# define MIN_NEEDED_INPUT	MIN_NEEDED_TO
Packit 6c4009
# define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
Packit 6c4009
# define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
Packit 6c4009
# define TO_LOOP_VX		__to_utf16_loop_vx
Packit 6c4009
# define LOOPFCT		TO_LOOP_VX
Packit 6c4009
# define LOOP_NEED_FLAGS
Packit 6c4009
# define BODY			BODY_TO_VX
Packit 6c4009
# include <iconv/loop.c>
Packit 6c4009
#else
Packit 6c4009
# define TO_LOOP_VX		NULL
Packit 6c4009
#endif /* HAVE_TO_VX != 1  */
Packit 6c4009
Packit 6c4009
#if HAVE_TO_VX_CU == 1
Packit 6c4009
#define BODY_TO_VX_CU							\
Packit 6c4009
  {									\
Packit 6c4009
    register const unsigned char* pInput asm ("8") = inptr;		\
Packit 6c4009
    register size_t inlen asm ("9") = inend - inptr;			\
Packit 6c4009
    register unsigned char* pOutput asm ("10") = outptr;		\
Packit 6c4009
    register size_t outlen asm ("11") = outend - outptr;		\
Packit 6c4009
    unsigned long tmp, tmp2, tmp3;					\
Packit 6c4009
    asm volatile (".machine push\n\t"					\
Packit 6c4009
		  ".machine \"z13\"\n\t"				\
Packit 6c4009
		  ".machinemode \"zarch_nohighgprs\"\n\t"		\
Packit 6c4009
		  /* Setup to check for surrogates.  */			\
Packit 6c4009
		  "    larl %[R_TMP],9f\n\t"				\
Packit 6c4009
		  "    vlm %%v30,%%v31,0(%[R_TMP])\n\t"			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_INLEN])			\
Packit 6c4009
		  CONVERT_32BIT_SIZE_T ([R_OUTLEN])			\
Packit 6c4009
		  /* Loop which handles UTF-32 chars			\
Packit 6c4009
		     ch < 0xd800 || (ch > 0xdfff && ch < 0x10000).  */	\
Packit 6c4009
		  "0:  clgijl %[R_INLEN],32,20f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],16,20f\n\t"			\
Packit 6c4009
		  "1:  vlm %%v16,%%v17,0(%[R_IN])\n\t"			\
Packit 6c4009
		  "    lghi %[R_TMP2],0\n\t"				\
Packit 6c4009
		  /* Shorten to UTF-16.  */				\
Packit 6c4009
		  "    vpkf %%v18,%%v16,%%v17\n\t"			\
Packit 6c4009
		  /* Check for surrogate chars.  */			\
Packit 6c4009
		  "    vstrcfs %%v19,%%v16,%%v30,%%v31\n\t"		\
Packit 6c4009
		  "    jno 10f\n\t"					\
Packit 6c4009
		  "    vstrcfs %%v19,%%v17,%%v30,%%v31\n\t"		\
Packit 6c4009
		  "    jno 11f\n\t"					\
Packit 6c4009
		  /* Store 16 bytes to buf_out.  */			\
Packit 6c4009
		  "    vst %%v18,0(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    la %[R_IN],32(%[R_IN])\n\t"			\
Packit 6c4009
		  "    aghi %[R_INLEN],-32\n\t"				\
Packit 6c4009
		  "    aghi %[R_OUTLEN],-16\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],16(%[R_OUT])\n\t"			\
Packit 6c4009
		  "    clgijl %[R_INLEN],32,20f\n\t"			\
Packit 6c4009
		  "    clgijl %[R_OUTLEN],16,20f\n\t"			\
Packit 6c4009
		  "    j 1b\n\t"					\
Packit 6c4009
		  /* Setup to check for ch >= 0xd800 && ch <= 0xdfff	\
Packit 6c4009
		     and check for ch >= 0x10000. (v30, v31)  */	\
Packit 6c4009
		  "9:  .long 0xd800,0xdfff,0x10000,0x10000\n\t"		\
Packit 6c4009
		  "    .long 0xa0000000,0xc0000000, 0xa0000000,0xa0000000\n\t" \
Packit 6c4009
		  /* At least one UTF32 char is in range of surrogates.	\
Packit 6c4009
		     Store the preceding characters.  */		\
Packit 6c4009
		  "11: ahi %[R_TMP2],16\n\t"				\
Packit 6c4009
		  "10: vlgvb %[R_TMP],%%v19,7\n\t"			\
Packit 6c4009
		  "    agr %[R_TMP],%[R_TMP2]\n\t"			\
Packit 6c4009
		  "    srlg %[R_TMP3],%[R_TMP],1\n\t" /* Number of out bytes.  */ \
Packit 6c4009
		  "    ahik %[R_TMP2],%[R_TMP3],-1\n\t" /* Highest index to store.  */ \
Packit 6c4009
		  "    jl 20f\n\t"					\
Packit 6c4009
		  "    vstl %%v18,%[R_TMP2],0(%[R_OUT])\n\t"		\
Packit 6c4009
		  /* Update pointers.  */				\
Packit 6c4009
		  "    la %[R_IN],0(%[R_TMP],%[R_IN])\n\t"		\
Packit 6c4009
		  "    slgr %[R_INLEN],%[R_TMP]\n\t"			\
Packit 6c4009
		  "    la %[R_OUT],0(%[R_TMP3],%[R_OUT])\n\t"		\
Packit 6c4009
		  "    slgr %[R_OUTLEN],%[R_TMP3]\n\t"			\
Packit 6c4009
		  /* Handles UTF16 surrogates with convert instruction.  */ \
Packit 6c4009
		  "20: cu42 %[R_OUT],%[R_IN]\n\t"			\
Packit 6c4009
		  "    jo 0b\n\t" /* Try vector implemenation again.  */ \
Packit 6c4009
		  "    lochil %[R_RES],%[RES_OUT_FULL]\n\t" /* cc == 1.  */ \
Packit 6c4009
		  "    lochih %[R_RES],%[RES_IN_ILL]\n\t" /* cc == 2.  */ \
Packit 6c4009
		  ".machine pop"					\
Packit 6c4009
		  : /* outputs */ [R_IN] "+a" (pInput)			\
Packit 6c4009
		    , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (pOutput)	\
Packit 6c4009
		    , [R_OUTLEN] "+d" (outlen), [R_TMP] "=a" (tmp)	\
Packit 6c4009
		    , [R_TMP2] "=d" (tmp2), [R_TMP3] "=a" (tmp3)	\
Packit 6c4009
		    , [R_RES] "+d" (result)				\
Packit 6c4009
		  : /* inputs */					\
Packit 6c4009
		    [RES_OUT_FULL] "i" (__GCONV_FULL_OUTPUT)		\
Packit 6c4009
		    , [RES_IN_ILL] "i" (__GCONV_ILLEGAL_INPUT)		\
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 ("v30") ASM_CLOBBER_VR ("v31")	\
Packit 6c4009
		  );							\
Packit 6c4009
    inptr = pInput;							\
Packit 6c4009
    outptr = pOutput;							\
Packit 6c4009
									\
Packit 6c4009
    if (__glibc_likely (inlen == 0)					\
Packit 6c4009
	|| result == __GCONV_FULL_OUTPUT)				\
Packit 6c4009
      break;								\
Packit 6c4009
    if (inlen < 4)							\
Packit 6c4009
      {									\
Packit 6c4009
	result = __GCONV_INCOMPLETE_INPUT;				\
Packit 6c4009
	break;								\
Packit 6c4009
      }									\
Packit 6c4009
									\
Packit 6c4009
    STANDARD_TO_LOOP_ERR_HANDLER (4);					\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
/* Generate loop-function with hardware vector and utf-convert instructions.  */
Packit 6c4009
# define MIN_NEEDED_INPUT	MIN_NEEDED_TO
Packit 6c4009
# define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
Packit 6c4009
# define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
Packit 6c4009
# define TO_LOOP_VX_CU		__to_utf16_loop_vx_cu
Packit 6c4009
# define LOOPFCT		TO_LOOP_VX_CU
Packit 6c4009
# define LOOP_NEED_FLAGS
Packit 6c4009
# define BODY			BODY_TO_VX_CU
Packit 6c4009
# include <iconv/loop.c>
Packit 6c4009
#else
Packit 6c4009
# define TO_LOOP_VX_CU		NULL
Packit 6c4009
#endif /* HAVE_TO_VX_CU != 1  */
Packit 6c4009
Packit 6c4009
/* This file also exists in sysdeps/s390/multiarch/ which
Packit 6c4009
   generates ifunc resolvers for FROM/TO_LOOP functions
Packit 6c4009
   and includes iconv/skeleton.c afterwards.  */
Packit 6c4009
#if ! defined USE_MULTIARCH
Packit 6c4009
# include <iconv/skeleton.c>
Packit 6c4009
#endif