]>
Commit | Line | Data |
---|---|---|
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 | |
218 | ICONV_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 | |
385 | ICONV_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 | ||
399 | static inline int | |
400 | __attribute ((always_inline)) | |
401 | ICONV_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 | ||
481 | ICONV_VX_SINGLE (internal_ucs4le_loop) | |
482 | # include <iconv/skeleton.c> | |
483 | ICONV_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 | ||
499 | static inline int | |
500 | __attribute ((always_inline)) | |
501 | ICONV_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 | ||
610 | ICONV_VX_SINGLE (ucs4_internal_loop) | |
611 | # include <iconv/skeleton.c> | |
612 | ICONV_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 | ||
626 | static inline int | |
627 | __attribute ((always_inline)) | |
628 | ICONV_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 | } | |
744 | ICONV_VX_SINGLE (ucs4le_internal_loop) | |
745 | # include <iconv/skeleton.c> | |
746 | ICONV_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 | |
862 | ICONV_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 | |
991 | ICONV_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 | |
1122 | ICONV_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 | |
1259 | ICONV_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 */ |