More NEWS entries / fixes for float_t / double_t changes.
[glibc.git] / sysdeps / s390 / utf16-utf32-z9.c
blob5d2ac4491d1cbad79c96a8f694b0c692ec28811e
1 /* Conversion between UTF-16 and UTF-32 BE/internal.
3 This module uses the Z9-109 variants of the Convert Unicode
4 instructions.
5 Copyright (C) 1997-2016 Free Software Foundation, Inc.
7 Author: Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
8 Based on the work by Ulrich Drepper <drepper@cygnus.com>, 1997.
10 Thanks to Daniel Appich who covered the relevant performance work
11 in his diploma thesis.
13 This is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2.1 of the License, or (at your option) any later version.
18 This is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public
24 License along with the GNU C Library; if not, see
25 <http://www.gnu.org/licenses/>. */
27 #include <dlfcn.h>
28 #include <stdint.h>
29 #include <unistd.h>
30 #include <dl-procinfo.h>
31 #include <gconv.h>
33 #if defined HAVE_S390_VX_GCC_SUPPORT
34 # define ASM_CLOBBER_VR(NR) , NR
35 #else
36 # define ASM_CLOBBER_VR(NR)
37 #endif
39 #if defined __s390x__
40 # define CONVERT_32BIT_SIZE_T(REG)
41 #else
42 # define CONVERT_32BIT_SIZE_T(REG) "llgfr %" #REG ",%" #REG "\n\t"
43 #endif
45 /* UTF-32 big endian byte order mark. */
46 #define BOM_UTF32 0x0000feffu
48 /* UTF-16 big endian byte order mark. */
49 #define BOM_UTF16 0xfeff
51 #define DEFINE_INIT 0
52 #define DEFINE_FINI 0
53 #define MIN_NEEDED_FROM 2
54 #define MAX_NEEDED_FROM 4
55 #define MIN_NEEDED_TO 4
56 #define FROM_LOOP __from_utf16_loop
57 #define TO_LOOP __to_utf16_loop
58 #define FROM_DIRECTION (dir == from_utf16)
59 #define ONE_DIRECTION 0
61 /* Direction of the transformation. */
62 enum direction
64 illegal_dir,
65 to_utf16,
66 from_utf16
69 struct utf16_data
71 enum direction dir;
72 int emit_bom;
76 extern int gconv_init (struct __gconv_step *step);
77 int
78 gconv_init (struct __gconv_step *step)
80 /* Determine which direction. */
81 struct utf16_data *new_data;
82 enum direction dir = illegal_dir;
83 int emit_bom;
84 int result;
86 emit_bom = (__strcasecmp (step->__to_name, "UTF-32//") == 0
87 || __strcasecmp (step->__to_name, "UTF-16//") == 0);
89 if (__strcasecmp (step->__from_name, "UTF-16BE//") == 0
90 && (__strcasecmp (step->__to_name, "UTF-32//") == 0
91 || __strcasecmp (step->__to_name, "UTF-32BE//") == 0
92 || __strcasecmp (step->__to_name, "INTERNAL") == 0))
94 dir = from_utf16;
96 else if ((__strcasecmp (step->__to_name, "UTF-16//") == 0
97 || __strcasecmp (step->__to_name, "UTF-16BE//") == 0)
98 && (__strcasecmp (step->__from_name, "UTF-32BE//") == 0
99 || __strcasecmp (step->__from_name, "INTERNAL") == 0))
101 dir = to_utf16;
104 result = __GCONV_NOCONV;
105 if (dir != illegal_dir)
107 new_data = (struct utf16_data *) malloc (sizeof (struct utf16_data));
109 result = __GCONV_NOMEM;
110 if (new_data != NULL)
112 new_data->dir = dir;
113 new_data->emit_bom = emit_bom;
114 step->__data = new_data;
116 if (dir == from_utf16)
118 step->__min_needed_from = MIN_NEEDED_FROM;
119 step->__max_needed_from = MIN_NEEDED_FROM;
120 step->__min_needed_to = MIN_NEEDED_TO;
121 step->__max_needed_to = MIN_NEEDED_TO;
123 else
125 step->__min_needed_from = MIN_NEEDED_TO;
126 step->__max_needed_from = MIN_NEEDED_TO;
127 step->__min_needed_to = MIN_NEEDED_FROM;
128 step->__max_needed_to = MIN_NEEDED_FROM;
131 step->__stateful = 0;
133 result = __GCONV_OK;
137 return result;
141 extern void gconv_end (struct __gconv_step *data);
142 void
143 gconv_end (struct __gconv_step *data)
145 free (data->__data);
148 #define PREPARE_LOOP \
149 enum direction dir = ((struct utf16_data *) step->__data)->dir; \
150 int emit_bom = ((struct utf16_data *) step->__data)->emit_bom; \
152 if (emit_bom && !data->__internal_use \
153 && data->__invocation_counter == 0) \
155 if (dir == to_utf16) \
157 /* Emit the UTF-16 Byte Order Mark. */ \
158 if (__glibc_unlikely (outbuf + 2 > outend)) \
159 return __GCONV_FULL_OUTPUT; \
161 put16u (outbuf, BOM_UTF16); \
162 outbuf += 2; \
164 else \
166 /* Emit the UTF-32 Byte Order Mark. */ \
167 if (__glibc_unlikely (outbuf + 4 > outend)) \
168 return __GCONV_FULL_OUTPUT; \
170 put32u (outbuf, BOM_UTF32); \
171 outbuf += 4; \
175 /* Conversion function from UTF-16 to UTF-32 internal/BE. */
177 /* The software routine is copied from utf-16.c (minus bytes
178 swapping). */
179 #define BODY_FROM_C \
181 uint16_t u1 = get16 (inptr); \
183 if (__builtin_expect (u1 < 0xd800, 1) || u1 > 0xdfff) \
185 /* No surrogate. */ \
186 put32 (outptr, u1); \
187 inptr += 2; \
189 else \
191 /* An isolated low-surrogate was found. This has to be \
192 considered ill-formed. */ \
193 if (__glibc_unlikely (u1 >= 0xdc00)) \
195 STANDARD_FROM_LOOP_ERR_HANDLER (2); \
197 /* It's a surrogate character. At least the first word says \
198 it is. */ \
199 if (__glibc_unlikely (inptr + 4 > inend)) \
201 /* We don't have enough input for another complete input \
202 character. */ \
203 result = __GCONV_INCOMPLETE_INPUT; \
204 break; \
207 inptr += 2; \
208 uint16_t u2 = get16 (inptr); \
209 if (__builtin_expect (u2 < 0xdc00, 0) \
210 || __builtin_expect (u2 > 0xdfff, 0)) \
212 /* This is no valid second word for a surrogate. */ \
213 inptr -= 2; \
214 STANDARD_FROM_LOOP_ERR_HANDLER (2); \
217 put32 (outptr, ((u1 - 0xd7c0) << 10) + (u2 - 0xdc00)); \
218 inptr += 2; \
220 outptr += 4; \
223 #define BODY_FROM_VX \
225 size_t inlen = inend - inptr; \
226 size_t outlen = outend - outptr; \
227 unsigned long tmp, tmp2, tmp3; \
228 asm volatile (".machine push\n\t" \
229 ".machine \"z13\"\n\t" \
230 ".machinemode \"zarch_nohighgprs\"\n\t" \
231 /* Setup to check for surrogates. */ \
232 " larl %[R_TMP],9f\n\t" \
233 " vlm %%v30,%%v31,0(%[R_TMP])\n\t" \
234 CONVERT_32BIT_SIZE_T ([R_INLEN]) \
235 CONVERT_32BIT_SIZE_T ([R_OUTLEN]) \
236 /* Loop which handles UTF-16 chars <0xd800, >0xdfff. */ \
237 "0: clgijl %[R_INLEN],16,2f\n\t" \
238 " clgijl %[R_OUTLEN],32,2f\n\t" \
239 "1: vl %%v16,0(%[R_IN])\n\t" \
240 /* Check for surrogate chars. */ \
241 " vstrchs %%v19,%%v16,%%v30,%%v31\n\t" \
242 " jno 10f\n\t" \
243 /* Enlarge to UTF-32. */ \
244 " vuplhh %%v17,%%v16\n\t" \
245 " la %[R_IN],16(%[R_IN])\n\t" \
246 " vupllh %%v18,%%v16\n\t" \
247 " aghi %[R_INLEN],-16\n\t" \
248 /* Store 32 bytes to buf_out. */ \
249 " vstm %%v17,%%v18,0(%[R_OUT])\n\t" \
250 " aghi %[R_OUTLEN],-32\n\t" \
251 " la %[R_OUT],32(%[R_OUT])\n\t" \
252 " clgijl %[R_INLEN],16,2f\n\t" \
253 " clgijl %[R_OUTLEN],32,2f\n\t" \
254 " j 1b\n\t" \
255 /* Setup to check for ch >= 0xd800 && ch <= 0xdfff. (v30, v31) */ \
256 "9: .short 0xd800,0xdfff,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
257 " .short 0xa000,0xc000,0x0,0x0,0x0,0x0,0x0,0x0\n\t" \
258 /* At least on uint16_t is in range of surrogates. \
259 Store the preceding chars. */ \
260 "10: vlgvb %[R_TMP],%%v19,7\n\t" \
261 " vuplhh %%v17,%%v16\n\t" \
262 " sllg %[R_TMP3],%[R_TMP],1\n\t" /* Number of out bytes. */ \
263 " ahik %[R_TMP2],%[R_TMP3],-1\n\t" /* Highest index to store. */ \
264 " jl 12f\n\t" \
265 " vstl %%v17,%[R_TMP2],0(%[R_OUT])\n\t" \
266 " vupllh %%v18,%%v16\n\t" \
267 " ahi %[R_TMP2],-16\n\t" \
268 " jl 11f\n\t" \
269 " vstl %%v18,%[R_TMP2],16(%[R_OUT])\n\t" \
270 "11: \n\t" /* Update pointers. */ \
271 " la %[R_IN],0(%[R_TMP],%[R_IN])\n\t" \
272 " slgr %[R_INLEN],%[R_TMP]\n\t" \
273 " la %[R_OUT],0(%[R_TMP3],%[R_OUT])\n\t" \
274 " slgr %[R_OUTLEN],%[R_TMP3]\n\t" \
275 /* Calculate remaining uint16_t values in loaded vrs. */ \
276 "12: lghi %[R_TMP2],16\n\t" \
277 " slgr %[R_TMP2],%[R_TMP]\n\t" \
278 " srl %[R_TMP2],1\n\t" \
279 " llh %[R_TMP],0(%[R_IN])\n\t" \
280 " aghi %[R_OUTLEN],-4\n\t" \
281 " j 16f\n\t" \
282 /* Handle remaining bytes. */ \
283 "2: \n\t" \
284 /* Zero, one or more bytes available? */ \
285 " clgfi %[R_INLEN],1\n\t" \
286 " je 97f\n\t" /* Only one byte available. */ \
287 " jl 99f\n\t" /* End if no bytes available. */ \
288 /* Calculate remaining uint16_t values in inptr. */ \
289 " srlg %[R_TMP2],%[R_INLEN],1\n\t" \
290 /* Handle remaining uint16_t values. */ \
291 "13: llh %[R_TMP],0(%[R_IN])\n\t" \
292 " slgfi %[R_OUTLEN],4\n\t" \
293 " jl 96f \n\t" \
294 " clfi %[R_TMP],0xd800\n\t" \
295 " jhe 15f\n\t" \
296 "14: st %[R_TMP],0(%[R_OUT])\n\t" \
297 " la %[R_IN],2(%[R_IN])\n\t" \
298 " aghi %[R_INLEN],-2\n\t" \
299 " la %[R_OUT],4(%[R_OUT])\n\t" \
300 " brctg %[R_TMP2],13b\n\t" \
301 " j 0b\n\t" /* Switch to vx-loop. */ \
302 /* Handle UTF-16 surrogate pair. */ \
303 "15: clfi %[R_TMP],0xdfff\n\t" \
304 " jh 14b\n\t" /* Jump away if ch > 0xdfff. */ \
305 "16: clfi %[R_TMP],0xdc00\n\t" \
306 " jhe 98f\n\t" /* Jump away in case of low-surrogate. */ \
307 " slgfi %[R_INLEN],4\n\t" \
308 " jl 97f\n\t" /* Big enough input? */ \
309 " llh %[R_TMP3],2(%[R_IN])\n\t" /* Load low surrogate. */ \
310 " slfi %[R_TMP],0xd7c0\n\t" \
311 " sll %[R_TMP],10\n\t" \
312 " risbgn %[R_TMP],%[R_TMP3],54,63,0\n\t" /* Insert klmnopqrst. */ \
313 " nilf %[R_TMP3],0xfc00\n\t" \
314 " clfi %[R_TMP3],0xdc00\n\t" /* Check if it starts with 0xdc00. */ \
315 " jne 98f\n\t" \
316 " st %[R_TMP],0(%[R_OUT])\n\t" \
317 " la %[R_IN],4(%[R_IN])\n\t" \
318 " la %[R_OUT],4(%[R_OUT])\n\t" \
319 " aghi %[R_TMP2],-2\n\t" \
320 " jh 13b\n\t" /* Handle remaining uint16_t values. */ \
321 " j 0b\n\t" /* Switch to vx-loop. */ \
322 "96: \n\t" /* Return full output. */ \
323 " lghi %[R_RES],%[RES_OUT_FULL]\n\t" \
324 " j 99f\n\t" \
325 "97: \n\t" /* Return incomplete input. */ \
326 " lghi %[R_RES],%[RES_IN_FULL]\n\t" \
327 " j 99f\n\t" \
328 "98:\n\t" /* Return Illegal character. */ \
329 " lghi %[R_RES],%[RES_IN_ILL]\n\t" \
330 "99:\n\t" \
331 ".machine pop" \
332 : /* outputs */ [R_IN] "+a" (inptr) \
333 , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (outptr) \
334 , [R_OUTLEN] "+d" (outlen), [R_TMP] "=a" (tmp) \
335 , [R_TMP2] "=d" (tmp2), [R_TMP3] "=a" (tmp3) \
336 , [R_RES] "+d" (result) \
337 : /* inputs */ \
338 [RES_OUT_FULL] "i" (__GCONV_FULL_OUTPUT) \
339 , [RES_IN_ILL] "i" (__GCONV_ILLEGAL_INPUT) \
340 , [RES_IN_FULL] "i" (__GCONV_INCOMPLETE_INPUT) \
341 : /* clobber list */ "memory", "cc" \
342 ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17") \
343 ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19") \
344 ASM_CLOBBER_VR ("v30") ASM_CLOBBER_VR ("v31") \
345 ); \
346 if (__glibc_likely (inptr == inend) \
347 || result != __GCONV_ILLEGAL_INPUT) \
348 break; \
350 STANDARD_FROM_LOOP_ERR_HANDLER (2); \
354 /* Generate loop-function with software routing. */
355 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
356 #define MAX_NEEDED_INPUT MAX_NEEDED_FROM
357 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
358 #if defined HAVE_S390_VX_ASM_SUPPORT
359 # define LOOPFCT __from_utf16_loop_c
360 # define LOOP_NEED_FLAGS
361 # define BODY BODY_FROM_C
362 # include <iconv/loop.c>
364 /* Generate loop-function with hardware vector instructions. */
365 # define MIN_NEEDED_INPUT MIN_NEEDED_FROM
366 # define MAX_NEEDED_INPUT MAX_NEEDED_FROM
367 # define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
368 # define LOOPFCT __from_utf16_loop_vx
369 # define LOOP_NEED_FLAGS
370 # define BODY BODY_FROM_VX
371 # include <iconv/loop.c>
373 /* Generate ifunc'ed loop function. */
374 __typeof(__from_utf16_loop_c)
375 __attribute__ ((ifunc ("__from_utf16_loop_resolver")))
376 __from_utf16_loop;
378 static void *
379 __from_utf16_loop_resolver (unsigned long int dl_hwcap)
381 if (dl_hwcap & HWCAP_S390_VX)
382 return __from_utf16_loop_vx;
383 else
384 return __from_utf16_loop_c;
387 strong_alias (__from_utf16_loop_c_single, __from_utf16_loop_single)
388 #else
389 # define LOOPFCT FROM_LOOP
390 # define LOOP_NEED_FLAGS
391 # define BODY BODY_FROM_C
392 # include <iconv/loop.c>
393 #endif
395 /* Conversion from UTF-32 internal/BE to UTF-16. */
397 /* The software routine is copied from utf-16.c (minus bytes
398 swapping). */
399 #define BODY_TO_C \
401 uint32_t c = get32 (inptr); \
403 if (__builtin_expect (c <= 0xd7ff, 1) \
404 || (c > 0xdfff && c <= 0xffff)) \
406 /* Two UTF-16 chars. */ \
407 put16 (outptr, c); \
409 else if (__builtin_expect (c >= 0x10000, 1) \
410 && __builtin_expect (c <= 0x10ffff, 1)) \
412 /* Four UTF-16 chars. */ \
413 uint16_t zabcd = ((c & 0x1f0000) >> 16) - 1; \
414 uint16_t out; \
416 /* Generate a surrogate character. */ \
417 if (__glibc_unlikely (outptr + 4 > outend)) \
419 /* Overflow in the output buffer. */ \
420 result = __GCONV_FULL_OUTPUT; \
421 break; \
424 out = 0xd800; \
425 out |= (zabcd & 0xff) << 6; \
426 out |= (c >> 10) & 0x3f; \
427 put16 (outptr, out); \
428 outptr += 2; \
430 out = 0xdc00; \
431 out |= c & 0x3ff; \
432 put16 (outptr, out); \
434 else \
436 STANDARD_TO_LOOP_ERR_HANDLER (4); \
438 outptr += 2; \
439 inptr += 4; \
442 #define BODY_TO_VX \
444 size_t inlen = inend - inptr; \
445 size_t outlen = outend - outptr; \
446 unsigned long tmp, tmp2, tmp3; \
447 asm volatile (".machine push\n\t" \
448 ".machine \"z13\"\n\t" \
449 ".machinemode \"zarch_nohighgprs\"\n\t" \
450 /* Setup to check for surrogates. */ \
451 " larl %[R_TMP],9f\n\t" \
452 " vlm %%v30,%%v31,0(%[R_TMP])\n\t" \
453 CONVERT_32BIT_SIZE_T ([R_INLEN]) \
454 CONVERT_32BIT_SIZE_T ([R_OUTLEN]) \
455 /* Loop which handles UTF-16 chars \
456 ch < 0xd800 || (ch > 0xdfff && ch < 0x10000). */ \
457 "0: clgijl %[R_INLEN],32,2f\n\t" \
458 " clgijl %[R_OUTLEN],16,2f\n\t" \
459 "1: vlm %%v16,%%v17,0(%[R_IN])\n\t" \
460 " lghi %[R_TMP2],0\n\t" \
461 /* Shorten to UTF-16. */ \
462 " vpkf %%v18,%%v16,%%v17\n\t" \
463 /* Check for surrogate chars. */ \
464 " vstrcfs %%v19,%%v16,%%v30,%%v31\n\t" \
465 " jno 10f\n\t" \
466 " vstrcfs %%v19,%%v17,%%v30,%%v31\n\t" \
467 " jno 11f\n\t" \
468 /* Store 16 bytes to buf_out. */ \
469 " vst %%v18,0(%[R_OUT])\n\t" \
470 " la %[R_IN],32(%[R_IN])\n\t" \
471 " aghi %[R_INLEN],-32\n\t" \
472 " aghi %[R_OUTLEN],-16\n\t" \
473 " la %[R_OUT],16(%[R_OUT])\n\t" \
474 " clgijl %[R_INLEN],32,2f\n\t" \
475 " clgijl %[R_OUTLEN],16,2f\n\t" \
476 " j 1b\n\t" \
477 /* Calculate remaining uint32_t values in inptr. */ \
478 "2: \n\t" \
479 " clgije %[R_INLEN],0,99f\n\t" \
480 " clgijl %[R_INLEN],4,92f\n\t" \
481 " srlg %[R_TMP2],%[R_INLEN],2\n\t" \
482 " j 20f\n\t" \
483 /* Setup to check for ch >= 0xd800 && ch <= 0xdfff \
484 and check for ch >= 0x10000. (v30, v31) */ \
485 "9: .long 0xd800,0xdfff,0x10000,0x10000\n\t" \
486 " .long 0xa0000000,0xc0000000, 0xa0000000,0xa0000000\n\t" \
487 /* At least on UTF32 char is in range of surrogates. \
488 Store the preceding characters. */ \
489 "11: ahi %[R_TMP2],16\n\t" \
490 "10: vlgvb %[R_TMP],%%v19,7\n\t" \
491 " agr %[R_TMP],%[R_TMP2]\n\t" \
492 " srlg %[R_TMP3],%[R_TMP],1\n\t" /* Number of out bytes. */ \
493 " ahik %[R_TMP2],%[R_TMP3],-1\n\t" /* Highest index to store. */ \
494 " jl 12f\n\t" \
495 " vstl %%v18,%[R_TMP2],0(%[R_OUT])\n\t" \
496 /* Update pointers. */ \
497 " la %[R_IN],0(%[R_TMP],%[R_IN])\n\t" \
498 " slgr %[R_INLEN],%[R_TMP]\n\t" \
499 " la %[R_OUT],0(%[R_TMP3],%[R_OUT])\n\t" \
500 " slgr %[R_OUTLEN],%[R_TMP3]\n\t" \
501 /* Calculate remaining uint32_t values in vrs. */ \
502 "12: lghi %[R_TMP2],8\n\t" \
503 " srlg %[R_TMP3],%[R_TMP3],1\n\t" \
504 " slgr %[R_TMP2],%[R_TMP3]\n\t" \
505 /* Handle remaining UTF-32 characters. */ \
506 "20: l %[R_TMP],0(%[R_IN])\n\t" \
507 " aghi %[R_INLEN],-4\n\t" \
508 /* Test if ch is 2byte UTF-16 char. */ \
509 " clfi %[R_TMP],0xffff\n\t" \
510 " jh 21f\n\t" \
511 /* Handle 2 byte UTF16 char. */ \
512 " lgr %[R_TMP3],%[R_TMP]\n\t" \
513 " nilf %[R_TMP],0xf800\n\t" \
514 " clfi %[R_TMP],0xd800\n\t" \
515 " je 91f\n\t" /* Do not accept UTF-16 surrogates. */ \
516 " slgfi %[R_OUTLEN],2\n\t" \
517 " jl 90f \n\t" \
518 " sth %[R_TMP3],0(%[R_OUT])\n\t" \
519 " la %[R_IN],4(%[R_IN])\n\t" \
520 " la %[R_OUT],2(%[R_OUT])\n\t" \
521 " brctg %[R_TMP2],20b\n\t" \
522 " j 0b\n\t" /* Switch to vx-loop. */ \
523 /* Test if ch is 4byte UTF-16 char. */ \
524 "21: clfi %[R_TMP],0x10ffff\n\t" \
525 " jh 91f\n\t" /* ch > 0x10ffff is not allowed! */ \
526 /* Handle 4 byte UTF16 char. */ \
527 " slgfi %[R_OUTLEN],4\n\t" \
528 " jl 90f \n\t" \
529 " slfi %[R_TMP],0x10000\n\t" /* zabcd = uvwxy - 1. */ \
530 " llilf %[R_TMP3],0xd800dc00\n\t" \
531 " la %[R_IN],4(%[R_IN])\n\t" \
532 " risbgn %[R_TMP3],%[R_TMP],38,47,6\n\t" /* High surrogate. */ \
533 " risbgn %[R_TMP3],%[R_TMP],54,63,0\n\t" /* Low surrogate. */ \
534 " st %[R_TMP3],0(%[R_OUT])\n\t" \
535 " la %[R_OUT],4(%[R_OUT])\n\t" \
536 " brctg %[R_TMP2],20b\n\t" \
537 " j 0b\n\t" /* Switch to vx-loop. */ \
538 "92: lghi %[R_RES],%[RES_IN_FULL]\n\t" \
539 " j 99f\n\t" \
540 "91: lghi %[R_RES],%[RES_IN_ILL]\n\t" \
541 " j 99f\n\t" \
542 "90: lghi %[R_RES],%[RES_OUT_FULL]\n\t" \
543 "99: \n\t" \
544 ".machine pop" \
545 : /* outputs */ [R_IN] "+a" (inptr) \
546 , [R_INLEN] "+d" (inlen), [R_OUT] "+a" (outptr) \
547 , [R_OUTLEN] "+d" (outlen), [R_TMP] "=a" (tmp) \
548 , [R_TMP2] "=d" (tmp2), [R_TMP3] "=a" (tmp3) \
549 , [R_RES] "+d" (result) \
550 : /* inputs */ \
551 [RES_OUT_FULL] "i" (__GCONV_FULL_OUTPUT) \
552 , [RES_IN_ILL] "i" (__GCONV_ILLEGAL_INPUT) \
553 , [RES_IN_FULL] "i" (__GCONV_INCOMPLETE_INPUT) \
554 : /* clobber list */ "memory", "cc" \
555 ASM_CLOBBER_VR ("v16") ASM_CLOBBER_VR ("v17") \
556 ASM_CLOBBER_VR ("v18") ASM_CLOBBER_VR ("v19") \
557 ASM_CLOBBER_VR ("v30") ASM_CLOBBER_VR ("v31") \
558 ); \
559 if (__glibc_likely (inptr == inend) \
560 || result != __GCONV_ILLEGAL_INPUT) \
561 break; \
563 STANDARD_TO_LOOP_ERR_HANDLER (4); \
566 /* Generate loop-function with software routing. */
567 #define MIN_NEEDED_INPUT MIN_NEEDED_TO
568 #define MIN_NEEDED_OUTPUT MIN_NEEDED_FROM
569 #define MAX_NEEDED_OUTPUT MAX_NEEDED_FROM
570 #define LOOPFCT __to_utf16_loop_c
571 #define LOOP_NEED_FLAGS
572 #define BODY BODY_TO_C
573 #include <iconv/loop.c>
575 #if defined HAVE_S390_VX_ASM_SUPPORT
576 /* Generate loop-function with hardware vector instructions. */
577 # define MIN_NEEDED_INPUT MIN_NEEDED_TO
578 # define MIN_NEEDED_OUTPUT MIN_NEEDED_FROM
579 # define MAX_NEEDED_OUTPUT MAX_NEEDED_FROM
580 # define LOOPFCT __to_utf16_loop_vx
581 # define LOOP_NEED_FLAGS
582 # define BODY BODY_TO_VX
583 # include <iconv/loop.c>
584 #endif
586 /* Generate ifunc'ed loop function. */
587 __typeof(__to_utf16_loop_c)
588 __attribute__ ((ifunc ("__to_utf16_loop_resolver")))
589 __to_utf16_loop;
591 static void *
592 __to_utf16_loop_resolver (unsigned long int dl_hwcap)
594 #if defined HAVE_S390_VX_ASM_SUPPORT
595 if (dl_hwcap & HWCAP_S390_VX)
596 return __to_utf16_loop_vx;
597 else
598 #endif
599 return __to_utf16_loop_c;
602 strong_alias (__to_utf16_loop_c_single, __to_utf16_loop_single)
605 #include <iconv/skeleton.c>