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