1 /* Simple transformations functions - s390 version.
2 Copyright (C) 2016-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
19 #if defined HAVE_S390_VX_ASM_SUPPORT
20 # include <ifunc-resolve.h>
22 # if defined HAVE_S390_VX_GCC_SUPPORT
23 # define ASM_CLOBBER_VR(NR) , NR
25 # define ASM_CLOBBER_VR(NR)
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)
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) \
42 # define ICONV_VX_SINGLE(NAME) \
43 static __typeof (NAME##_single) __##NAME##_vx_single __attribute__((alias(#NAME "_single")));
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)
67 # include <iconv/gconv_simple.c>
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
79 /* Now define the functions with vector support. */
80 # if defined __s390x__
81 # define CONVERT_32BIT_SIZE_T(REG)
83 # define CONVERT_32BIT_SIZE_T(REG) "llgfr %" #REG ",%" #REG "\n\t"
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
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);
109 if (__glibc_unlikely (*inptr > '\x7f')) \
115 /* It's an one byte sequence. */ \
116 *((uint32_t *) outptr) = *inptr++; \
117 outptr += sizeof (uint32_t); \
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" \
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" \
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" \
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" \
179 " vupllh %%v20,%%v17\n\t" \
180 " vstl %%v20,%[R_LI],16(%[R_OUT])\n\t" \
181 " ahi %[R_LI],-16\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" \
188 " vupllh %%v22,%%v18\n\t" \
189 " vstl %%v22,%[R_LI],48(%[R_OUT])\n\t" \
191 " la %[R_OUT],1(%[R_TMP],%[R_OUT])\n\t" \
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) \
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") \
209 /* Found an invalid character at the next input byte. */ \
214 # define LOOP_NEED_FLAGS
215 # include <iconv/loop.c>
216 # include <iconv/skeleton.c>
218 # undef BODY_ORIG_ERROR
219 ICONV_VX_IFUNC (__gconv_transform_ascii_internal
)
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
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);
241 if (__glibc_unlikely (*((const uint32_t *) inptr) > 0x7f)) \
247 /* It's an one byte sequence. */ \
248 *outptr++ = *((const uint32_t *) inptr); \
249 inptr += sizeof (uint32_t); \
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. */ \
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" \
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" \
279 " vstrcfs %%v22,%%v17,%%v20,%%v21\n\t" \
281 " vstrcfs %%v22,%%v18,%%v20,%%v21\n\t" \
283 " vstrcfs %%v22,%%v19,%%v20,%%v21\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" \
301 " vll %%v17,%[R_LI],16(%[R_IN])\n\t" \
302 " ahi %[R_LI],-16\n\t" \
304 " vll %%v18,%[R_LI],32(%[R_IN])\n\t" \
305 " ahi %[R_LI],-16\n\t" \
307 " vll %%v19,%[R_LI],48(%[R_IN])\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" \
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" \
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" \
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" \
336 "3: vstrcfs %%v22,%%v16,%%v20,%%v21\n\t" \
338 "4: vstrcfs %%v22,%%v17,%%v20,%%v21\n\t" \
339 " lghi %[R_TMP],4\n\t" \
341 "5: vstrcfs %%v22,%%v17,%%v20,%%v21\n\t" \
342 " lghi %[R_TMP],8\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" \
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" \
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) \
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") \
377 /* Found an invalid character > 0x7f at next character. */ \
381 # define LOOP_NEED_FLAGS
382 # include <iconv/loop.c>
383 # include <iconv/skeleton.c>
385 # undef BODY_ORIG_ERROR
386 ICONV_VX_IFUNC (__gconv_transform_internal_ascii
)
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
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
)
410 const unsigned char *inptr
= *inptrp
;
411 unsigned char *outptr
= *outptrp
;
413 size_t len
= MIN (inend
- inptr
, outend
- outptr
) / 4;
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"
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"
458 : /* outputs */ [R_OUT
] "+a" (outptr
)
459 , [R_IN
] "+a" (inptr
)
460 , [R_LI
] "=a" (loop_count
)
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")
471 /* Determine the status. */
472 if (*inptrp
== inend
)
473 result
= __GCONV_EMPTY_INPUT
;
474 else if (*outptrp
+ 4 > outend
)
475 result
= __GCONV_FULL_OUTPUT
;
477 result
= __GCONV_INCOMPLETE_INPUT
;
482 ICONV_VX_SINGLE (internal_ucs4le_loop
)
483 # include <iconv/skeleton.c>
484 ICONV_VX_IFUNC (__gconv_transform_internal_ucs4le
)
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
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
)
510 int flags
= step_data
->__flags
;
511 const unsigned char *inptr
= *inptrp
;
512 unsigned char *outptr
= *outptrp
;
514 size_t len
, loop_count
;
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"
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"
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"
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"
563 : /* outputs */ [R_OUT
] "+a" (outptr
)
564 , [R_IN
] "+a" (inptr
)
565 , [R_LI
] "=a" (loop_count
)
568 : /* clobber list*/ "memory", "cc"
569 ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v20")
570 ASM_CLOBBER_VR ("v21") ASM_CLOBBER_VR ("v22")
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
;
582 if (flags
& __GCONV_IGNORE_ERRORS
)
584 /* Just ignore this character. */
592 return __GCONV_ILLEGAL_INPUT
;
600 /* Determine the status. */
601 if (*inptrp
== inend
)
602 result
= __GCONV_EMPTY_INPUT
;
603 else if (*outptrp
+ 4 > outend
)
604 result
= __GCONV_FULL_OUTPUT
;
606 result
= __GCONV_INCOMPLETE_INPUT
;
611 ICONV_VX_SINGLE (ucs4_internal_loop
)
612 # include <iconv/skeleton.c>
613 ICONV_VX_IFUNC (__gconv_transform_ucs4_internal
)
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
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
)
637 int flags
= step_data
->__flags
;
638 const unsigned char *inptr
= *inptrp
;
639 unsigned char *outptr
= *outptrp
;
641 size_t len
, loop_count
;
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"
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"
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"
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"
694 : /* outputs */ [R_OUT
] "+a" (outptr
)
695 , [R_IN
] "+a" (inptr
)
696 , [R_LI
] "=a" (loop_count
)
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")
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
;
714 if (flags
& __GCONV_IGNORE_ERRORS
)
716 /* Just ignore this character. */
724 return __GCONV_ILLEGAL_INPUT
;
732 /* Determine the status. */
733 if (*inptrp
== inend
)
734 result
= __GCONV_EMPTY_INPUT
;
735 else if (*inptrp
+ 4 > inend
)
736 result
= __GCONV_INCOMPLETE_INPUT
;
739 assert (*outptrp
+ 4 > outend
);
740 result
= __GCONV_FULL_OUTPUT
;
745 ICONV_VX_SINGLE (ucs4le_internal_loop
)
746 # include <iconv/skeleton.c>
747 ICONV_VX_IFUNC (__gconv_transform_ucs4le_internal
)
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
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);
769 uint16_t u1 = get16 (inptr); \
771 if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000)) \
776 *((uint32_t *) outptr) = u1; \
777 outptr += sizeof (uint32_t); \
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" \
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" \
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" \
833 " vstl %%v17,%[R_TMP],0(%[R_OUT])\n\t" \
834 " ahi %[R_TMP],-16\n\t" \
836 " vstl %%v18,%[R_TMP],16(%[R_OUT])\n\t" \
837 "19: la %[R_OUT],0(%[R_TMP2],%[R_OUT])\n\t" \
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) \
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") \
853 /* Found an invalid character at next input-char. */ \
858 # define LOOP_NEED_FLAGS
859 # include <iconv/loop.c>
860 # include <iconv/skeleton.c>
862 # undef BODY_ORIG_ERROR
863 ICONV_VX_IFUNC (__gconv_transform_ucs2_internal
)
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
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 ()) \
884 result = __GCONV_ILLEGAL_INPUT; \
893 uint16_t u1 = bswap_16 (get16 (inptr)); \
895 if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000)) \
900 *((uint32_t *) outptr) = u1; \
901 outptr += sizeof (uint32_t); \
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" \
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" \
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" \
962 " vstl %%v17,%[R_TMP],0(%[R_OUT])\n\t" \
963 " ahi %[R_TMP],-16\n\t" \
965 " vstl %%v18,%[R_TMP],16(%[R_OUT])\n\t" \
966 "19: la %[R_OUT],0(%[R_TMP2],%[R_OUT])\n\t" \
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) \
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") \
983 /* Found an invalid character at next input-char. */ \
987 # define LOOP_NEED_FLAGS
988 # include <iconv/loop.c>
989 # include <iconv/skeleton.c>
991 # undef BODY_ORIG_ERROR
992 ICONV_VX_IFUNC (__gconv_transform_ucs2reverse_internal
)
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
1005 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
1006 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
1007 #define LOOPFCT FROM_LOOP
1010 uint32_t val = *((const uint32_t *) inptr); \
1012 if (__glibc_unlikely (val >= 0x10000)) \
1014 UNICODE_TAG_HANDLER (val, 4); \
1015 STANDARD_TO_LOOP_ERR_HANDLER (4); \
1017 else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000)) \
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 \
1025 result = __GCONV_ILLEGAL_INPUT; \
1026 if (! ignore_errors_p ()) \
1034 put16 (outptr, val); \
1035 outptr += sizeof (uint16_t); \
1041 if (__builtin_expect (inend - inptr < 32, 1) \
1042 || outend - outptr < 16) \
1043 /* Convert remaining bytes with c code. */ \
1047 /* Convert in 32 byte blocks. */ \
1048 size_t loop_count = (inend - inptr) / 32; \
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" \
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" \
1064 "1: vstrcfs %%v19,%%v17,%%v20,%%v21\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" \
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" \
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" \
1096 " vstl %%v18,%[R_I],0(%[R_OUT])\n\t" \
1097 " la %[R_OUT],1(%[R_I],%[R_OUT])\n\t" \
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) \
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") \
1112 if (loop_count > 0) \
1114 /* Found an invalid character at next character. */ \
1119 #define LOOP_NEED_FLAGS
1120 #include <iconv/loop.c>
1121 #include <iconv/skeleton.c>
1123 ICONV_VX_IFUNC (__gconv_transform_internal_ucs2
)
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
1136 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
1137 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
1138 #define LOOPFCT FROM_LOOP
1141 uint32_t val = *((const uint32_t *) inptr); \
1142 if (__glibc_unlikely (val >= 0x10000)) \
1144 UNICODE_TAG_HANDLER (val, 4); \
1145 STANDARD_TO_LOOP_ERR_HANDLER (4); \
1147 else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000)) \
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 \
1155 if (! ignore_errors_p ()) \
1157 result = __GCONV_ILLEGAL_INPUT; \
1166 put16 (outptr, bswap_16 (val)); \
1167 outptr += sizeof (uint16_t); \
1173 if (__builtin_expect (inend - inptr < 32, 1) \
1174 || outend - outptr < 16) \
1175 /* Convert remaining bytes with c code. */ \
1179 /* Convert in 32 byte blocks. */ \
1180 size_t loop_count = (inend - inptr) / 32; \
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" \
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" \
1197 "1: vstrcfs %%v19,%%v17,%%v20,%%v21\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" \
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" \
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" \
1232 " vstl %%v18,%[R_I],0(%[R_OUT])\n\t" \
1233 " la %[R_OUT],1(%[R_I],%[R_OUT])\n\t" \
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) \
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") \
1249 if (loop_count > 0) \
1251 /* Found an invalid character at next character. */ \
1256 #define LOOP_NEED_FLAGS
1257 #include <iconv/loop.c>
1258 #include <iconv/skeleton.c>
1260 ICONV_VX_IFUNC (__gconv_transform_internal_ucs2reverse
)
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 */