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