1/*
2 * RISC-V translation routines for the RV64D Standard Extension.
3 *
4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
5 * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
6 *                    Bastian Koppelmann, kbastian@mail.uni-paderborn.de
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2 or later, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define REQUIRE_ZDINX_OR_D(ctx) do { \
22    if (!ctx->cfg_ptr->ext_zdinx) { \
23        REQUIRE_EXT(ctx, RVD); \
24    } \
25} while (0)
26
27#define REQUIRE_EVEN(ctx, reg) do { \
28    if (ctx->cfg_ptr->ext_zdinx && (get_xl(ctx) == MXL_RV32) && \
29        ((reg) & 0x1)) { \
30        return false; \
31    } \
32} while (0)
33
34#define REQUIRE_ZCD(ctx) do { \
35    if (!ctx->cfg_ptr->ext_zcd) {  \
36        return false;     \
37    } \
38} while (0)
39
40static bool trans_fld(DisasContext *ctx, arg_fld *a)
41{
42    TCGv addr;
43
44    REQUIRE_FPU;
45    REQUIRE_EXT(ctx, RVD);
46
47    decode_save_opc(ctx);
48    addr = get_address(ctx, a->rs1, a->imm);
49    tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ);
50
51    mark_fs_dirty(ctx);
52    return true;
53}
54
55static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
56{
57    TCGv addr;
58
59    REQUIRE_FPU;
60    REQUIRE_EXT(ctx, RVD);
61
62    decode_save_opc(ctx);
63    addr = get_address(ctx, a->rs1, a->imm);
64    tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ);
65    return true;
66}
67
68static bool trans_c_fld(DisasContext *ctx, arg_fld *a)
69{
70    REQUIRE_ZCD(ctx);
71    return trans_fld(ctx, a);
72}
73
74static bool trans_c_fsd(DisasContext *ctx, arg_fsd *a)
75{
76    REQUIRE_ZCD(ctx);
77    return trans_fsd(ctx, a);
78}
79
80static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
81{
82    REQUIRE_FPU;
83    REQUIRE_ZDINX_OR_D(ctx);
84    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
85
86    TCGv_i64 dest = dest_fpr(ctx, a->rd);
87    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
88    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
89    TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
90
91    gen_set_rm(ctx, a->rm);
92    gen_helper_fmadd_d(dest, cpu_env, src1, src2, src3);
93    gen_set_fpr_d(ctx, a->rd, dest);
94    mark_fs_dirty(ctx);
95    return true;
96}
97
98static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
99{
100    REQUIRE_FPU;
101    REQUIRE_ZDINX_OR_D(ctx);
102    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
103
104    TCGv_i64 dest = dest_fpr(ctx, a->rd);
105    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
106    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
107    TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
108
109    gen_set_rm(ctx, a->rm);
110    gen_helper_fmsub_d(dest, cpu_env, src1, src2, src3);
111    gen_set_fpr_d(ctx, a->rd, dest);
112    mark_fs_dirty(ctx);
113    return true;
114}
115
116static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
117{
118    REQUIRE_FPU;
119    REQUIRE_ZDINX_OR_D(ctx);
120    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
121
122    TCGv_i64 dest = dest_fpr(ctx, a->rd);
123    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
124    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
125    TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
126
127    gen_set_rm(ctx, a->rm);
128    gen_helper_fnmsub_d(dest, cpu_env, src1, src2, src3);
129    gen_set_fpr_d(ctx, a->rd, dest);
130    mark_fs_dirty(ctx);
131    return true;
132}
133
134static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
135{
136    REQUIRE_FPU;
137    REQUIRE_ZDINX_OR_D(ctx);
138    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2 | a->rs3);
139
140    TCGv_i64 dest = dest_fpr(ctx, a->rd);
141    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
142    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
143    TCGv_i64 src3 = get_fpr_d(ctx, a->rs3);
144
145    gen_set_rm(ctx, a->rm);
146    gen_helper_fnmadd_d(dest, cpu_env, src1, src2, src3);
147    gen_set_fpr_d(ctx, a->rd, dest);
148    mark_fs_dirty(ctx);
149    return true;
150}
151
152static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
153{
154    REQUIRE_FPU;
155    REQUIRE_ZDINX_OR_D(ctx);
156    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
157
158    TCGv_i64 dest = dest_fpr(ctx, a->rd);
159    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
160    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
161
162    gen_set_rm(ctx, a->rm);
163    gen_helper_fadd_d(dest, cpu_env, src1, src2);
164    gen_set_fpr_d(ctx, a->rd, dest);
165    mark_fs_dirty(ctx);
166    return true;
167}
168
169static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
170{
171    REQUIRE_FPU;
172    REQUIRE_ZDINX_OR_D(ctx);
173    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
174
175    TCGv_i64 dest = dest_fpr(ctx, a->rd);
176    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
177    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
178
179    gen_set_rm(ctx, a->rm);
180    gen_helper_fsub_d(dest, cpu_env, src1, src2);
181    gen_set_fpr_d(ctx, a->rd, dest);
182    mark_fs_dirty(ctx);
183    return true;
184}
185
186static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
187{
188    REQUIRE_FPU;
189    REQUIRE_ZDINX_OR_D(ctx);
190    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
191
192    TCGv_i64 dest = dest_fpr(ctx, a->rd);
193    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
194    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
195
196    gen_set_rm(ctx, a->rm);
197    gen_helper_fmul_d(dest, cpu_env, src1, src2);
198    gen_set_fpr_d(ctx, a->rd, dest);
199    mark_fs_dirty(ctx);
200    return true;
201}
202
203static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
204{
205    REQUIRE_FPU;
206    REQUIRE_ZDINX_OR_D(ctx);
207    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
208
209    TCGv_i64 dest = dest_fpr(ctx, a->rd);
210    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
211    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
212
213    gen_set_rm(ctx, a->rm);
214    gen_helper_fdiv_d(dest, cpu_env, src1, src2);
215    gen_set_fpr_d(ctx, a->rd, dest);
216    mark_fs_dirty(ctx);
217    return true;
218}
219
220static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
221{
222    REQUIRE_FPU;
223    REQUIRE_ZDINX_OR_D(ctx);
224    REQUIRE_EVEN(ctx, a->rd | a->rs1);
225
226    TCGv_i64 dest = dest_fpr(ctx, a->rd);
227    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
228
229    gen_set_rm(ctx, a->rm);
230    gen_helper_fsqrt_d(dest, cpu_env, src1);
231    gen_set_fpr_d(ctx, a->rd, dest);
232    mark_fs_dirty(ctx);
233    return true;
234}
235
236static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
237{
238    REQUIRE_FPU;
239    REQUIRE_ZDINX_OR_D(ctx);
240    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
241
242    TCGv_i64 dest = dest_fpr(ctx, a->rd);
243    if (a->rs1 == a->rs2) { /* FMOV */
244        dest = get_fpr_d(ctx, a->rs1);
245    } else {
246        TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
247        TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
248        tcg_gen_deposit_i64(dest, src2, src1, 0, 63);
249    }
250    gen_set_fpr_d(ctx, a->rd, dest);
251    mark_fs_dirty(ctx);
252    return true;
253}
254
255static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
256{
257    REQUIRE_FPU;
258    REQUIRE_ZDINX_OR_D(ctx);
259    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
260
261    TCGv_i64 dest = dest_fpr(ctx, a->rd);
262    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
263
264    if (a->rs1 == a->rs2) { /* FNEG */
265        tcg_gen_xori_i64(dest, src1, INT64_MIN);
266    } else {
267        TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
268        TCGv_i64 t0 = tcg_temp_new_i64();
269        tcg_gen_not_i64(t0, src2);
270        tcg_gen_deposit_i64(dest, t0, src1, 0, 63);
271    }
272    gen_set_fpr_d(ctx, a->rd, dest);
273    mark_fs_dirty(ctx);
274    return true;
275}
276
277static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
278{
279    REQUIRE_FPU;
280    REQUIRE_ZDINX_OR_D(ctx);
281    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
282
283    TCGv_i64 dest = dest_fpr(ctx, a->rd);
284    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
285
286    if (a->rs1 == a->rs2) { /* FABS */
287        tcg_gen_andi_i64(dest, src1, ~INT64_MIN);
288    } else {
289        TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
290        TCGv_i64 t0 = tcg_temp_new_i64();
291        tcg_gen_andi_i64(t0, src2, INT64_MIN);
292        tcg_gen_xor_i64(dest, src1, t0);
293    }
294    gen_set_fpr_d(ctx, a->rd, dest);
295    mark_fs_dirty(ctx);
296    return true;
297}
298
299static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
300{
301    REQUIRE_FPU;
302    REQUIRE_ZDINX_OR_D(ctx);
303    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
304
305    TCGv_i64 dest = dest_fpr(ctx, a->rd);
306    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
307    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
308
309    gen_helper_fmin_d(dest, cpu_env, src1, src2);
310    gen_set_fpr_d(ctx, a->rd, dest);
311    mark_fs_dirty(ctx);
312    return true;
313}
314
315static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
316{
317    REQUIRE_FPU;
318    REQUIRE_ZDINX_OR_D(ctx);
319    REQUIRE_EVEN(ctx, a->rd | a->rs1 | a->rs2);
320
321    TCGv_i64 dest = dest_fpr(ctx, a->rd);
322    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
323    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
324
325    gen_helper_fmax_d(dest, cpu_env, src1, src2);
326    gen_set_fpr_d(ctx, a->rd, dest);
327    mark_fs_dirty(ctx);
328    return true;
329}
330
331static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
332{
333    REQUIRE_FPU;
334    REQUIRE_ZDINX_OR_D(ctx);
335    REQUIRE_EVEN(ctx, a->rs1);
336
337    TCGv_i64 dest = dest_fpr(ctx, a->rd);
338    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
339
340    gen_set_rm(ctx, a->rm);
341    gen_helper_fcvt_s_d(dest, cpu_env, src1);
342    gen_set_fpr_hs(ctx, a->rd, dest);
343    mark_fs_dirty(ctx);
344    return true;
345}
346
347static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
348{
349    REQUIRE_FPU;
350    REQUIRE_ZDINX_OR_D(ctx);
351    REQUIRE_EVEN(ctx, a->rd);
352
353    TCGv_i64 dest = dest_fpr(ctx, a->rd);
354    TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1);
355
356    gen_set_rm(ctx, a->rm);
357    gen_helper_fcvt_d_s(dest, cpu_env, src1);
358    gen_set_fpr_d(ctx, a->rd, dest);
359    mark_fs_dirty(ctx);
360    return true;
361}
362
363static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
364{
365    REQUIRE_FPU;
366    REQUIRE_ZDINX_OR_D(ctx);
367    REQUIRE_EVEN(ctx, a->rs1 | a->rs2);
368
369    TCGv dest = dest_gpr(ctx, a->rd);
370    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
371    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
372
373    gen_helper_feq_d(dest, cpu_env, src1, src2);
374    gen_set_gpr(ctx, a->rd, dest);
375    return true;
376}
377
378static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
379{
380    REQUIRE_FPU;
381    REQUIRE_ZDINX_OR_D(ctx);
382    REQUIRE_EVEN(ctx, a->rs1 | a->rs2);
383
384    TCGv dest = dest_gpr(ctx, a->rd);
385    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
386    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
387
388    gen_helper_flt_d(dest, cpu_env, src1, src2);
389    gen_set_gpr(ctx, a->rd, dest);
390    return true;
391}
392
393static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
394{
395    REQUIRE_FPU;
396    REQUIRE_ZDINX_OR_D(ctx);
397    REQUIRE_EVEN(ctx, a->rs1 | a->rs2);
398
399    TCGv dest = dest_gpr(ctx, a->rd);
400    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
401    TCGv_i64 src2 = get_fpr_d(ctx, a->rs2);
402
403    gen_helper_fle_d(dest, cpu_env, src1, src2);
404    gen_set_gpr(ctx, a->rd, dest);
405    return true;
406}
407
408static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
409{
410    REQUIRE_FPU;
411    REQUIRE_ZDINX_OR_D(ctx);
412    REQUIRE_EVEN(ctx, a->rs1);
413
414    TCGv dest = dest_gpr(ctx, a->rd);
415    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
416
417    gen_helper_fclass_d(dest, src1);
418    gen_set_gpr(ctx, a->rd, dest);
419    return true;
420}
421
422static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
423{
424    REQUIRE_FPU;
425    REQUIRE_ZDINX_OR_D(ctx);
426    REQUIRE_EVEN(ctx, a->rs1);
427
428    TCGv dest = dest_gpr(ctx, a->rd);
429    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
430
431    gen_set_rm(ctx, a->rm);
432    gen_helper_fcvt_w_d(dest, cpu_env, src1);
433    gen_set_gpr(ctx, a->rd, dest);
434    return true;
435}
436
437static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
438{
439    REQUIRE_FPU;
440    REQUIRE_ZDINX_OR_D(ctx);
441    REQUIRE_EVEN(ctx, a->rs1);
442
443    TCGv dest = dest_gpr(ctx, a->rd);
444    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
445
446    gen_set_rm(ctx, a->rm);
447    gen_helper_fcvt_wu_d(dest, cpu_env, src1);
448    gen_set_gpr(ctx, a->rd, dest);
449    return true;
450}
451
452static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
453{
454    REQUIRE_FPU;
455    REQUIRE_ZDINX_OR_D(ctx);
456    REQUIRE_EVEN(ctx, a->rd);
457
458    TCGv_i64 dest = dest_fpr(ctx, a->rd);
459    TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
460
461    gen_set_rm(ctx, a->rm);
462    gen_helper_fcvt_d_w(dest, cpu_env, src);
463    gen_set_fpr_d(ctx, a->rd, dest);
464
465    mark_fs_dirty(ctx);
466    return true;
467}
468
469static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
470{
471    REQUIRE_FPU;
472    REQUIRE_ZDINX_OR_D(ctx);
473    REQUIRE_EVEN(ctx, a->rd);
474
475    TCGv_i64 dest = dest_fpr(ctx, a->rd);
476    TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
477
478    gen_set_rm(ctx, a->rm);
479    gen_helper_fcvt_d_wu(dest, cpu_env, src);
480    gen_set_fpr_d(ctx, a->rd, dest);
481
482    mark_fs_dirty(ctx);
483    return true;
484}
485
486static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
487{
488    REQUIRE_64BIT(ctx);
489    REQUIRE_FPU;
490    REQUIRE_ZDINX_OR_D(ctx);
491    REQUIRE_EVEN(ctx, a->rs1);
492
493    TCGv dest = dest_gpr(ctx, a->rd);
494    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
495
496    gen_set_rm(ctx, a->rm);
497    gen_helper_fcvt_l_d(dest, cpu_env, src1);
498    gen_set_gpr(ctx, a->rd, dest);
499    return true;
500}
501
502static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
503{
504    REQUIRE_64BIT(ctx);
505    REQUIRE_FPU;
506    REQUIRE_ZDINX_OR_D(ctx);
507    REQUIRE_EVEN(ctx, a->rs1);
508
509    TCGv dest = dest_gpr(ctx, a->rd);
510    TCGv_i64 src1 = get_fpr_d(ctx, a->rs1);
511
512    gen_set_rm(ctx, a->rm);
513    gen_helper_fcvt_lu_d(dest, cpu_env, src1);
514    gen_set_gpr(ctx, a->rd, dest);
515    return true;
516}
517
518static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
519{
520    REQUIRE_64BIT(ctx);
521    REQUIRE_FPU;
522    REQUIRE_EXT(ctx, RVD);
523
524#ifdef TARGET_RISCV64
525    gen_set_gpr(ctx, a->rd, cpu_fpr[a->rs1]);
526    return true;
527#else
528    qemu_build_not_reached();
529#endif
530}
531
532static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
533{
534    REQUIRE_64BIT(ctx);
535    REQUIRE_FPU;
536    REQUIRE_ZDINX_OR_D(ctx);
537    REQUIRE_EVEN(ctx, a->rd);
538
539    TCGv_i64 dest = dest_fpr(ctx, a->rd);
540    TCGv src = get_gpr(ctx, a->rs1, EXT_SIGN);
541
542    gen_set_rm(ctx, a->rm);
543    gen_helper_fcvt_d_l(dest, cpu_env, src);
544    gen_set_fpr_d(ctx, a->rd, dest);
545
546    mark_fs_dirty(ctx);
547    return true;
548}
549
550static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
551{
552    REQUIRE_64BIT(ctx);
553    REQUIRE_FPU;
554    REQUIRE_ZDINX_OR_D(ctx);
555    REQUIRE_EVEN(ctx, a->rd);
556
557    TCGv_i64 dest = dest_fpr(ctx, a->rd);
558    TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO);
559
560    gen_set_rm(ctx, a->rm);
561    gen_helper_fcvt_d_lu(dest, cpu_env, src);
562    gen_set_fpr_d(ctx, a->rd, dest);
563
564    mark_fs_dirty(ctx);
565    return true;
566}
567
568static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
569{
570    REQUIRE_64BIT(ctx);
571    REQUIRE_FPU;
572    REQUIRE_EXT(ctx, RVD);
573
574#ifdef TARGET_RISCV64
575    tcg_gen_mov_tl(cpu_fpr[a->rd], get_gpr(ctx, a->rs1, EXT_NONE));
576    mark_fs_dirty(ctx);
577    return true;
578#else
579    qemu_build_not_reached();
580#endif
581}
582