8ae002
From 1ae5597025b342ee8fec59e04970b44fc1361744 Mon Sep 17 00:00:00 2001
8ae002
From: Stefan Liebler <stli@linux.vnet.ibm.com>
8ae002
Date: Mon, 7 Nov 2016 17:17:51 +0100
8ae002
Subject: [PATCH 14/17] S390: Fix utf32 to utf8 handling of low surrogates
8ae002
 (disable cu41).
8ae002
8ae002
Upstream commit 52f8a48e24563daa807f94824ce9782b9a9eece9
8ae002
8ae002
According to the latest Unicode standard, a conversion from/to UTF-xx has
8ae002
to report an error if the character value is in range of an utf16 surrogate
8ae002
(0xd800..0xdfff). See https://sourceware.org/ml/libc-help/2015-12/msg00015.html.
8ae002
8ae002
Thus the cu41 instruction, which converts from utf32 to utf8,  has to be
8ae002
disabled because it does not report an error in case of a value in range of
8ae002
a low surrogate (0xdc00..0xdfff). The etf3eh variant is removed and the c,
8ae002
vector variant is adjusted to handle the value in range of an utf16 low
8ae002
surrogate correctly.
8ae002
8ae002
ChangeLog:
8ae002
8ae002
	* sysdeps/s390/utf8-utf32-z9.c: Disable cu41 instruction and report
8ae002
	an error in case of a value in range of an utf16 low surrogate.
8ae002
---
8ae002
 sysdeps/s390/utf8-utf32-z9.c | 188 ++++++++++++++++++++++++++-----------------
8ae002
 1 file changed, 115 insertions(+), 73 deletions(-)
8ae002
8ae002
diff --git a/sysdeps/s390/utf8-utf32-z9.c b/sysdeps/s390/utf8-utf32-z9.c
8ae002
index e39e0a7..efae745 100644
8ae002
--- a/sysdeps/s390/utf8-utf32-z9.c
8ae002
+++ b/sysdeps/s390/utf8-utf32-z9.c
8ae002
@@ -572,28 +572,6 @@ __from_utf8_loop_resolver (unsigned long int dl_hwcap)
8ae002
 
8ae002
 strong_alias (__from_utf8_loop_c_single, __from_utf8_loop_single)
8ae002
 
8ae002
-
8ae002
-/* Conversion from UTF-32 internal/BE to UTF-8.  */
8ae002
-#define BODY_TO_HW(ASM)							\
8ae002
-  {									\
8ae002
-    ASM;								\
8ae002
-    if (__glibc_likely (inptr == inend)					\
8ae002
-	|| result == __GCONV_FULL_OUTPUT)				\
8ae002
-      break;								\
8ae002
-    if (inptr + 4 > inend)						\
8ae002
-      {									\
8ae002
-	result = __GCONV_INCOMPLETE_INPUT;				\
8ae002
-	break;								\
8ae002
-      }									\
8ae002
-    STANDARD_TO_LOOP_ERR_HANDLER (4);					\
8ae002
-  }
8ae002
-
8ae002
-/* The hardware routine uses the S/390 cu41 instruction.  */
8ae002
-#define BODY_TO_ETF3EH BODY_TO_HW (HARDWARE_CONVERT ("cu41 %0, %1"))
8ae002
-
8ae002
-/* The hardware routine uses the S/390 vector and cu41 instructions.  */
8ae002
-#define BODY_TO_VX BODY_TO_HW (HW_TO_VX)
8ae002
-
8ae002
 /* The software routine mimics the S/390 cu41 instruction.  */
8ae002
 #define BODY_TO_C						\
8ae002
   {								\
8ae002
@@ -632,7 +610,7 @@ strong_alias (__from_utf8_loop_c_single, __from_utf8_loop_single)
8ae002
 	    result = __GCONV_FULL_OUTPUT;			\
8ae002
 	    break;						\
8ae002
 	  }							\
8ae002
-	if (wc >= 0xd800 && wc < 0xdc00)			\
8ae002
+	if (wc >= 0xd800 && wc <= 0xdfff)			\
8ae002
 	  {							\
8ae002
 	    /* Do not accept UTF-16 surrogates.   */		\
8ae002
 	    result = __GCONV_ILLEGAL_INPUT;			\
8ae002
@@ -679,13 +657,12 @@ strong_alias (__from_utf8_loop_c_single, __from_utf8_loop_single)
8ae002
     inptr += 4;							\
8ae002
   }
8ae002
 
8ae002
-#define HW_TO_VX							\
8ae002
+/* The hardware routine uses the S/390 vector instructions.  */
8ae002
+#define BODY_TO_VX							\
8ae002
   {									\
8ae002
-    register const unsigned char* pInput asm ("8") = inptr;		\
8ae002
-    register size_t inlen asm ("9") = inend - inptr;			\
8ae002
-    register unsigned char* pOutput asm ("10") = outptr;		\
8ae002
-    register size_t outlen asm("11") = outend - outptr;			\
8ae002
-    unsigned long tmp, tmp2;						\
8ae002
+    size_t inlen = inend - inptr;					\
8ae002
+    size_t outlen = outend - outptr;					\
8ae002
+    unsigned long tmp, tmp2, tmp3;					\
8ae002
     asm volatile (".machine push\n\t"					\
8ae002
 		  ".machine \"z13\"\n\t"				\
8ae002
 		  ".machinemode \"zarch_nohighgprs\"\n\t"		\
8ae002
@@ -696,10 +673,10 @@ strong_alias (__from_utf8_loop_c_single, __from_utf8_loop_single)
8ae002
 		  CONVERT_32BIT_SIZE_T ([R_INLEN])			\
8ae002
 		  CONVERT_32BIT_SIZE_T ([R_OUTLEN])			\
8ae002
 		  /* Loop which handles UTF-32 chars <=0x7f.  */	\
8ae002
-		  "0:  clgijl %[R_INLEN],64,20f\n\t"			\
8ae002
-		  "    clgijl %[R_OUTLEN],16,20f\n\t"			\
8ae002
+		  "0:  clgijl %[R_INLEN],64,2f\n\t"			\
8ae002
+		  "    clgijl %[R_OUTLEN],16,2f\n\t"			\
8ae002
 		  "1:  vlm %%v16,%%v19,0(%[R_IN])\n\t"			\
8ae002
-		  "    lghi %[R_TMP],0\n\t"				\
8ae002
+		  "    lghi %[R_TMP2],0\n\t"				\
8ae002
 		  /* Shorten to byte values.  */			\
8ae002
 		  "    vpkf %%v23,%%v16,%%v17\n\t"			\
8ae002
 		  "    vpkf %%v24,%%v18,%%v19\n\t"			\
8ae002
@@ -719,41 +696,116 @@ strong_alias (__from_utf8_loop_c_single, __from_utf8_loop_single)
8ae002
 		  "    aghi %[R_OUTLEN],-16\n\t"			\
8ae002
 		  "    la %[R_IN],64(%[R_IN])\n\t"			\
8ae002
 		  "    la %[R_OUT],16(%[R_OUT])\n\t"			\
8ae002
-		  "    clgijl %[R_INLEN],64,20f\n\t"			\
8ae002
-		  "    clgijl %[R_OUTLEN],16,20f\n\t"			\
8ae002
+		  "    clgijl %[R_INLEN],64,2f\n\t"			\
8ae002
+		  "    clgijl %[R_OUTLEN],16,2f\n\t"			\
8ae002
 		  "    j 1b\n\t"					\
8ae002
 		  /* Found a value > 0x7f.  */				\
8ae002
-		  "13: ahi %[R_TMP],4\n\t"				\
8ae002
-		  "12: ahi %[R_TMP],4\n\t"				\
8ae002
-		  "11: ahi %[R_TMP],4\n\t"				\
8ae002
-		  "10: vlgvb %[R_I],%%v22,7\n\t"			\
8ae002
-		  "    srlg %[R_I],%[R_I],2\n\t"			\
8ae002
-		  "    agr %[R_I],%[R_TMP]\n\t"				\
8ae002
-		  "    je 20f\n\t"					\
8ae002
+		  "13: ahi %[R_TMP2],4\n\t"				\
8ae002
+		  "12: ahi %[R_TMP2],4\n\t"				\
8ae002
+		  "11: ahi %[R_TMP2],4\n\t"				\
8ae002
+		  "10: vlgvb %[R_TMP],%%v22,7\n\t"			\
8ae002
+		  "    srlg %[R_TMP],%[R_TMP],2\n\t"			\
8ae002
+		  "    agr %[R_TMP],%[R_TMP2]\n\t"			\
8ae002
+		  "    je 16f\n\t"					\
8ae002
 		  /* Store characters before invalid one...  */		\
8ae002
-		  "    slgr %[R_OUTLEN],%[R_I]\n\t"			\
8ae002
-		  "15: aghi %[R_I],-1\n\t"				\
8ae002
-		  "    vstl %%v23,%[R_I],0(%[R_OUT])\n\t"		\
8ae002
+		  "    slgr %[R_OUTLEN],%[R_TMP]\n\t"			\
8ae002
+		  "15: aghi %[R_TMP],-1\n\t"				\
8ae002
+		  "    vstl %%v23,%[R_TMP],0(%[R_OUT])\n\t"		\
8ae002
 		  /* ... and update pointers.  */			\
8ae002
-		  "    aghi %[R_I],1\n\t"				\
8ae002
-		  "    la %[R_OUT],0(%[R_I],%[R_OUT])\n\t"		\
8ae002
-		  "    sllg %[R_I],%[R_I],2\n\t"			\
8ae002
-		  "    la %[R_IN],0(%[R_I],%[R_IN])\n\t"		\
8ae002
-		  "    slgr %[R_INLEN],%[R_I]\n\t"			\
8ae002
-		  /* Handle multibyte utf8-char with convert instruction. */ \
8ae002
-		  "20: cu41 %[R_OUT],%[R_IN]\n\t"			\
8ae002
-		  "    jo 0b\n\t" /* Try vector implemenation again.  */ \
8ae002
-		  "    lochil %[R_RES],%[RES_OUT_FULL]\n\t" /* cc == 1.  */ \
8ae002
-		  "    lochih %[R_RES],%[RES_IN_ILL]\n\t" /* cc == 2.  */ \
8ae002
+		  "    aghi %[R_TMP],1\n\t"				\
8ae002
+		  "    la %[R_OUT],0(%[R_TMP],%[R_OUT])\n\t"		\
8ae002
+		  "    sllg %[R_TMP2],%[R_TMP],2\n\t"			\
8ae002
+		  "    la %[R_IN],0(%[R_TMP2],%[R_IN])\n\t"		\
8ae002
+		  "    slgr %[R_INLEN],%[R_TMP2]\n\t"			\
8ae002
+		  /* Calculate remaining uint32_t values in loaded vrs.  */ \
8ae002
+		  "16: lghi %[R_TMP2],16\n\t"				\
8ae002
+		  "    sgr %[R_TMP2],%[R_TMP]\n\t"			\
8ae002
+		  "    l %[R_TMP],0(%[R_IN])\n\t"			\
8ae002
+		  "    aghi %[R_INLEN],-4\n\t"				\
8ae002
+		  "    j 22f\n\t"					\
8ae002
+		  /* Handle remaining bytes.  */			\
8ae002
+		  "2:  clgije %[R_INLEN],0,99f\n\t"			\
8ae002
+		  "    clgijl %[R_INLEN],4,92f\n\t"			\
8ae002
+		  /* Calculate remaining uint32_t values in inptr.  */	\
8ae002
+		  "    srlg %[R_TMP2],%[R_INLEN],2\n\t"			\
8ae002
+		  /* Handle multibyte utf8-char. */			\
8ae002
+		  "20: l %[R_TMP],0(%[R_IN])\n\t"			\
8ae002
+		  "    aghi %[R_INLEN],-4\n\t"				\
8ae002
+		  /* Test if ch is 1byte UTF-8 char. */			\
8ae002
+		  "21: clijh %[R_TMP],0x7f,22f\n\t"			\
8ae002
+		  /* Handle 1-byte UTF-8 char.  */			\
8ae002
+		  "31: slgfi %[R_OUTLEN],1\n\t"				\
8ae002
+		  "    jl 90f \n\t"					\
8ae002
+		  "    stc %[R_TMP],0(%[R_OUT])\n\t"			\
8ae002
+		  "    la %[R_IN],4(%[R_IN])\n\t"			\
8ae002
+		  "    la %[R_OUT],1(%[R_OUT])\n\t"			\
8ae002
+		  "    brctg %[R_TMP2],20b\n\t"				\
8ae002
+		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
8ae002
+		  /* Test if ch is 2byte UTF-8 char. */			\
8ae002
+		  "22: clfi %[R_TMP],0x7ff\n\t"				\
8ae002
+		  "    jh 23f\n\t"					\
8ae002
+		  /* Handle 2-byte UTF-8 char.  */			\
8ae002
+		  "32: slgfi %[R_OUTLEN],2\n\t"				\
8ae002
+		  "    jl 90f \n\t"					\
8ae002
+		  "    llill %[R_TMP3],0xc080\n\t"			\
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],51,55,2\n\t" /* 1. byte.   */ \
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],58,63,0\n\t" /* 2. byte.   */ \
8ae002
+		  "    sth %[R_TMP3],0(%[R_OUT])\n\t"			\
8ae002
+		  "    la %[R_IN],4(%[R_IN])\n\t"			\
8ae002
+		  "    la %[R_OUT],2(%[R_OUT])\n\t"			\
8ae002
+		  "    brctg %[R_TMP2],20b\n\t"				\
8ae002
+		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
8ae002
+		  /* Test if ch is 3-byte UTF-8 char.  */		\
8ae002
+		  "23: clfi %[R_TMP],0xffff\n\t"			\
8ae002
+		  "    jh 24f\n\t"					\
8ae002
+		  /* Handle 3-byte UTF-8 char.  */			\
8ae002
+		  "33: slgfi %[R_OUTLEN],3\n\t"				\
8ae002
+		  "    jl 90f \n\t"					\
8ae002
+		  "    llilf %[R_TMP3],0xe08080\n\t"			\
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],44,47,4\n\t" /* 1. byte.  */ \
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],50,55,2\n\t" /* 2. byte.  */ \
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],58,63,0\n\t" /* 3. byte.  */ \
8ae002
+		  /* Test if ch is a UTF-16 surrogate: ch & 0xf800 == 0xd800  */ \
8ae002
+		  "    nilf %[R_TMP],0xf800\n\t"			\
8ae002
+		  "    clfi %[R_TMP],0xd800\n\t"			\
8ae002
+		  "    je 91f\n\t" /* Do not accept UTF-16 surrogates.  */ \
8ae002
+		  "    stcm %[R_TMP3],7,0(%[R_OUT])\n\t"		\
8ae002
+		  "    la %[R_IN],4(%[R_IN])\n\t"			\
8ae002
+		  "    la %[R_OUT],3(%[R_OUT])\n\t"			\
8ae002
+		  "    brctg %[R_TMP2],20b\n\t"				\
8ae002
+		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
8ae002
+		  /* Test if ch is 4-byte UTF-8 char.  */		\
8ae002
+		  "24: clfi %[R_TMP],0x10ffff\n\t"			\
8ae002
+		  "    jh 91f\n\t" /* ch > 0x10ffff is not allowed!  */	\
8ae002
+		  /* Handle 4-byte UTF-8 char.  */			\
8ae002
+		  "34: slgfi %[R_OUTLEN],4\n\t"				\
8ae002
+		  "    jl 90f \n\t"					\
8ae002
+		  "    llilf %[R_TMP3],0xf0808080\n\t"			\
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],37,39,6\n\t" /* 1. byte.  */ \
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],42,47,4\n\t" /* 2. byte.  */ \
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],50,55,2\n\t" /* 3. byte.  */ \
8ae002
+		  "    risbgn %[R_TMP3],%[R_TMP],58,63,0\n\t" /* 4. byte.  */ \
8ae002
+		  "    st %[R_TMP3],0(%[R_OUT])\n\t"			\
8ae002
+		  "    la %[R_IN],4(%[R_IN])\n\t"			\
8ae002
+		  "    la %[R_OUT],4(%[R_OUT])\n\t"			\
8ae002
+		  "    brctg %[R_TMP2],20b\n\t"				\
8ae002
+		  "    j 0b\n\t" /* Switch to vx-loop.  */		\
8ae002
+		  "92: lghi %[R_RES],%[RES_IN_FULL]\n\t"		\
8ae002
+		  "    j 99f\n\t"					\
8ae002
+		  "91: lghi %[R_RES],%[RES_IN_ILL]\n\t"			\
8ae002
+		  "    j 99f\n\t"					\
8ae002
+		  "90: lghi %[R_RES],%[RES_OUT_FULL]\n\t"		\
8ae002
+		  "99: \n\t"						\
8ae002
 		  ".machine pop"					\
8ae002
-		  : /* outputs */ [R_IN] "+a" (pInput)			\
8ae002
-		    , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (pOutput)	\
8ae002
-		    , [R_OUTLEN] "+d" (outlen), [R_TMP] "=d" (tmp)	\
8ae002
-		    , [R_I] "=a" (tmp2)					\
8ae002
+		  : /* outputs */ [R_IN] "+a" (inptr)			\
8ae002
+		    , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (outptr)	\
8ae002
+		    , [R_OUTLEN] "+d" (outlen), [R_TMP] "=a" (tmp)	\
8ae002
+		    , [R_TMP2] "=a" (tmp2), [R_TMP3] "=d" (tmp3)	\
8ae002
 		    , [R_RES] "+d" (result)				\
8ae002
 		  : /* inputs */					\
8ae002
 		    [RES_OUT_FULL] "i" (__GCONV_FULL_OUTPUT)		\
8ae002
 		    , [RES_IN_ILL] "i" (__GCONV_ILLEGAL_INPUT)		\
8ae002
+		    , [RES_IN_FULL] "i" (__GCONV_INCOMPLETE_INPUT)	\
8ae002
 		  : /* clobber list */ "memory", "cc"			\
8ae002
 		    ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17")	\
8ae002
 		    ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19")	\
8ae002
@@ -761,8 +813,11 @@ strong_alias (__from_utf8_loop_c_single, __from_utf8_loop_single)
8ae002
 		    ASM_CLOBBER_VR ("v22") ASM_CLOBBER_VR ("v23")	\
8ae002
 		    ASM_CLOBBER_VR ("v24")				\
8ae002
 		  );							\
8ae002
-    inptr = pInput;							\
8ae002
-    outptr = pOutput;							\
8ae002
+    if (__glibc_likely (inptr == inend)					\
8ae002
+	|| result != __GCONV_ILLEGAL_INPUT)				\
8ae002
+      break;								\
8ae002
+									\
8ae002
+    STANDARD_TO_LOOP_ERR_HANDLER (4);					\
8ae002
   }
8ae002
 
8ae002
 /* Generate loop-function with software routing.  */
8ae002
@@ -774,15 +829,6 @@ strong_alias (__from_utf8_loop_c_single, __from_utf8_loop_single)
8ae002
 #define LOOP_NEED_FLAGS
8ae002
 #include <iconv/loop.c>
8ae002
 
8ae002
-/* Generate loop-function with hardware utf-convert instruction.  */
8ae002
-#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
8ae002
-#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
8ae002
-#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
8ae002
-#define LOOPFCT			__to_utf8_loop_etf3eh
8ae002
-#define LOOP_NEED_FLAGS
8ae002
-#define BODY			BODY_TO_ETF3EH
8ae002
-#include <iconv/loop.c>
8ae002
-
8ae002
 #if defined HAVE_S390_VX_ASM_SUPPORT
8ae002
 /* Generate loop-function with hardware vector and utf-convert instructions.  */
8ae002
 # define MIN_NEEDED_INPUT	MIN_NEEDED_TO
8ae002
@@ -807,10 +853,6 @@ __to_utf8_loop_resolver (unsigned long int dl_hwcap)
8ae002
     return __to_utf8_loop_vx;
8ae002
   else
8ae002
 #endif
8ae002
-  if (dl_hwcap & HWCAP_S390_ZARCH && dl_hwcap & HWCAP_S390_HIGH_GPRS
8ae002
-      && dl_hwcap & HWCAP_S390_ETF3EH)
8ae002
-    return __to_utf8_loop_etf3eh;
8ae002
-  else
8ae002
     return __to_utf8_loop_c;
8ae002
 }
8ae002
 
8ae002
-- 
8ae002
1.8.3.1
8ae002