master
c 1,685 lines 51.3 KB
Raw
1 /*
2 * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "qemu/osdep.h"
19 #include "cpu.h"
20 #include "internal.h"
21 #include "tcg/tcg-op.h"
22 #include "tcg/tcg-op-gvec.h"
23 #include "exec/helper-gen.h"
24 #include "insn.h"
25 #include "opcodes.h"
26 #include "sys_macros.h"
27 #include "translate.h"
28 #define QEMU_GENERATE /* Used internally by macros.h */
29 #include "macros.h"
30 #include "mmvec/macros.h"
31 #undef QEMU_GENERATE
32 #include "gen_tcg.h"
33 #include "gen_tcg_hvx.h"
34 #ifndef CONFIG_USER_ONLY
35 #include "gen_tcg_sys.h"
36 #endif
37
38 #include "genptr.h"
39
40 static void gen_sabsdiff_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
41 {
42 TCGv_i32 t = tcg_temp_new_i32();
43
44 tcg_gen_sub_i32(t, a, b);
45 tcg_gen_sub_i32(d, b, a);
46 tcg_gen_movcond_i32(TCG_COND_LT, d, a, b, d, t);
47 }
48
49 static void gen_sabsdiff_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
50 {
51 TCGv_vec t = tcg_temp_new_vec_matching(d);
52
53 tcg_gen_smin_vec(vece, t, a, b);
54 tcg_gen_smax_vec(vece, d, a, b);
55 tcg_gen_sub_vec(vece, d, d, t);
56 }
57
58 void gen_gvec_sabsdiff(unsigned vece, uint32_t dofs, uint32_t aofs,
59 uint32_t bofs, uint32_t oprsz, uint32_t maxsz)
60 {
61 static const TCGOpcode vecop_list[] = {
62 INDEX_op_sub_vec, INDEX_op_smin_vec, INDEX_op_smax_vec, 0
63 };
64 static const GVecGen3 ops[4] = {
65 [MO_16] = { .fniv = gen_sabsdiff_vec,
66 .fno = gen_helper_gvec_sabsdiff_h,
67 .opt_opc = vecop_list,
68 .vece = MO_16 },
69 [MO_32] = { .fni4 = gen_sabsdiff_i32,
70 .fniv = gen_sabsdiff_vec,
71 .fno = gen_helper_gvec_sabsdiff_w,
72 .opt_opc = vecop_list,
73 .vece = MO_32 },
74 };
75
76 tcg_debug_assert(vece == MO_16 || vece == MO_32);
77 tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &ops[vece]);
78 }
79
80 static void gen_uabsdiff_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
81 {
82 TCGv_vec t = tcg_temp_new_vec_matching(d);
83
84 tcg_gen_umin_vec(vece, t, a, b);
85 tcg_gen_umax_vec(vece, d, a, b);
86 tcg_gen_sub_vec(vece, d, d, t);
87 }
88
89 void gen_gvec_uabsdiff(unsigned vece, uint32_t dofs, uint32_t aofs,
90 uint32_t bofs, uint32_t oprsz, uint32_t maxsz)
91 {
92 static const TCGOpcode vecop_list[] = {
93 INDEX_op_sub_vec, INDEX_op_umin_vec, INDEX_op_umax_vec, 0
94 };
95 static const GVecGen3 ops[4] = {
96 [MO_8] = { .fniv = gen_uabsdiff_vec,
97 .fno = gen_helper_gvec_uabsdiff_b,
98 .opt_opc = vecop_list,
99 .vece = MO_8 },
100 [MO_16] = { .fniv = gen_uabsdiff_vec,
101 .fno = gen_helper_gvec_uabsdiff_h,
102 .opt_opc = vecop_list,
103 .vece = MO_16 },
104 };
105
106 tcg_debug_assert(vece == MO_8 || vece == MO_16);
107 tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &ops[vece]);
108 }
109
110 TCGv gen_read_reg(TCGv result, int num)
111 {
112 tcg_gen_mov_tl(result, hex_gpr[num]);
113 return result;
114 }
115
116 TCGv gen_read_preg(TCGv pred, uint8_t num)
117 {
118 tcg_gen_mov_tl(pred, hex_pred[num]);
119 return pred;
120 }
121
122 #define IMMUTABLE (~0)
123
124 const target_ulong reg_immut_masks[TOTAL_PER_THREAD_REGS] = {
125 [HEX_REG_USR] = 0xc13000c0,
126 [HEX_REG_PC] = IMMUTABLE,
127 [HEX_REG_GP] = 0x3f,
128 [HEX_REG_UPCYCLELO] = IMMUTABLE,
129 [HEX_REG_UPCYCLEHI] = IMMUTABLE,
130 [HEX_REG_UTIMERLO] = IMMUTABLE,
131 [HEX_REG_UTIMERHI] = IMMUTABLE,
132 };
133
134 static inline void gen_masked_reg_write(TCGv new_val, TCGv cur_val,
135 target_ulong reg_mask)
136 {
137 if (reg_mask) {
138 TCGv tmp = tcg_temp_new();
139
140 /* new_val = (new_val & ~reg_mask) | (cur_val & reg_mask) */
141 tcg_gen_andi_tl(new_val, new_val, ~reg_mask);
142 tcg_gen_andi_tl(tmp, cur_val, reg_mask);
143 tcg_gen_or_tl(new_val, new_val, tmp);
144 }
145 }
146
147 TCGv get_result_gpr(DisasContext *ctx, int rnum)
148 {
149 if (ctx->need_commit) {
150 if (rnum == HEX_REG_USR) {
151 return hex_new_value_usr;
152 } else {
153 if (ctx->new_value[rnum] == NULL) {
154 ctx->new_value[rnum] = tcg_temp_new();
155 tcg_gen_movi_tl(ctx->new_value[rnum], 0);
156 }
157 return ctx->new_value[rnum];
158 }
159 } else {
160 return hex_gpr[rnum];
161 }
162 }
163
164 TCGv gen_unalias_gpr_src(TCGv src, TCGv dst)
165 {
166 if (src != dst) {
167 return src;
168 }
169
170 TCGv tmp = tcg_temp_new();
171 tcg_gen_mov_tl(tmp, src);
172 return tmp;
173 }
174
175 static TCGv_i64 get_result_gpr_pair(DisasContext *ctx, int rnum)
176 {
177 TCGv_i64 result = tcg_temp_new_i64();
178 tcg_gen_concat_i32_i64(result, get_result_gpr(ctx, rnum),
179 get_result_gpr(ctx, rnum + 1));
180 return result;
181 }
182
183 static void gen_write_reg_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
184 {
185 TCGv val32 = tcg_temp_new();
186
187 /* Low word */
188 tcg_gen_extrl_i64_i32(val32, val);
189 tcg_gen_mov_tl(get_result_gpr(ctx, rnum), val32);
190
191 /* High word */
192 tcg_gen_extrh_i64_i32(val32, val);
193 tcg_gen_mov_tl(get_result_gpr(ctx, rnum + 1), val32);
194 }
195
196 TCGv get_result_pred(DisasContext *ctx, int pnum)
197 {
198 if (ctx->need_commit) {
199 if (ctx->new_pred_value[pnum] == NULL) {
200 ctx->new_pred_value[pnum] = tcg_temp_new();
201 tcg_gen_movi_tl(ctx->new_pred_value[pnum], 0);
202 }
203 return ctx->new_pred_value[pnum];
204 } else {
205 return hex_pred[pnum];
206 }
207 }
208
209 #ifndef CONFIG_USER_ONLY
210 G_GNUC_UNUSED
211 static bool greg_writable(int rnum, bool pair)
212 {
213 if (pair) {
214 if (rnum < HEX_GREG_G3) {
215 return true;
216 }
217 qemu_log_mask(LOG_UNIMP,
218 "Warning: ignoring write to guest register pair G%d:%d\n",
219 rnum + 1, rnum);
220 } else {
221 if (rnum <= HEX_GREG_G3) {
222 return true;
223 }
224 qemu_log_mask(LOG_UNIMP,
225 "Warning: ignoring write to guest register G%d\n", rnum);
226 }
227 return false;
228 }
229
230 G_GNUC_UNUSED
231 static void check_greg_impl(int rnum, bool pair)
232 {
233 if (pair && (!greg_implemented(rnum) || !greg_implemented(rnum + 1))) {
234 qemu_log_mask(LOG_UNIMP,
235 "Warning: guest register pair G%d:%d is unimplemented or "
236 "reserved. Read will yield 0.\n",
237 rnum + 1, rnum);
238 } else if (!pair && !greg_implemented(rnum)) {
239 qemu_log_mask(LOG_UNIMP,
240 "Warning: guest register G%d is unimplemented or reserved."
241 " Read will yield 0.\n", rnum);
242 }
243 }
244
245 G_GNUC_UNUSED
246 static inline void gen_log_greg_write(DisasContext *ctx, int rnum, TCGv_i32 val)
247 {
248 tcg_gen_mov_i32(ctx->greg_new_value[rnum], val);
249 }
250
251 G_GNUC_UNUSED
252 static void gen_log_greg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
253 {
254 TCGv_i32 val32 = tcg_temp_new_i32();
255
256 /* Low word */
257 tcg_gen_extrl_i64_i32(val32, val);
258 gen_log_greg_write(ctx, rnum, val32);
259
260 /* High word */
261 tcg_gen_extrh_i64_i32(val32, val);
262 gen_log_greg_write(ctx, rnum + 1, val32);
263 }
264
265 static const uint32_t sreg_immut_masks[NUM_SREGS] = {
266 [HEX_SREG_STID] = 0xff00ff00,
267 [HEX_SREG_ELR] = 0x00000003,
268 [HEX_SREG_SSR] = 0x00008000,
269 [HEX_SREG_CCR] = 0x10e0ff24,
270 [HEX_SREG_HTID] = IMMUTABLE,
271 [HEX_SREG_IMASK] = 0xffff0000,
272 [HEX_SREG_GEVB] = 0x000000ff,
273 };
274
275 G_GNUC_UNUSED
276 static void gen_log_sreg_write(DisasContext *ctx, int rnum, TCGv_i32 val)
277 {
278 const uint32_t reg_mask = sreg_immut_masks[rnum];
279
280 if (reg_mask != IMMUTABLE) {
281 if (rnum < HEX_SREG_GLB_START) {
282 gen_masked_reg_write(val, hex_t_sreg[rnum], reg_mask);
283 if (ctx->need_commit || rnum == HEX_SREG_SSR) {
284 tcg_gen_mov_i32(ctx->t_sreg_new_value[rnum], val);
285 } else {
286 tcg_gen_mov_i32(hex_t_sreg[rnum], val);
287 }
288 } else {
289 gen_helper_sreg_write_masked(tcg_env, tcg_constant_i32(rnum), val);
290 }
291 }
292 }
293
294 G_GNUC_UNUSED
295 static void gen_log_sreg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
296 {
297 TCGv_i32 val32 = tcg_temp_new_i32();
298
299 /* Low word */
300 tcg_gen_extrl_i64_i32(val32, val);
301 gen_log_sreg_write(ctx, rnum, val32);
302
303 /* High word */
304 tcg_gen_extrh_i64_i32(val32, val);
305 gen_log_sreg_write(ctx, rnum + 1, val32);
306 }
307
308 G_GNUC_UNUSED
309 static void gen_read_sreg(TCGv_i32 dst, int reg_num)
310 {
311 if (reg_num >= HEX_SREG_GLB_START || reg_num == HEX_SREG_BADVA) {
312 gen_helper_sreg_read(dst, tcg_env, tcg_constant_i32(reg_num));
313 } else {
314 tcg_gen_mov_i32(dst, hex_t_sreg[reg_num]);
315 }
316 }
317
318 G_GNUC_UNUSED
319 static void gen_read_sreg_pair(TCGv_i64 dst, int reg_num)
320 {
321 if (reg_num < HEX_SREG_GLB_START) {
322 if (reg_num + 1 == HEX_SREG_BADVA) {
323 TCGv_i32 badva = tcg_temp_new_i32();
324 gen_helper_sreg_read(badva, tcg_env,
325 tcg_constant_i32(HEX_SREG_BADVA));
326 tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num], badva);
327 } else {
328 tcg_gen_concat_i32_i64(dst, hex_t_sreg[reg_num],
329 hex_t_sreg[reg_num + 1]);
330 }
331 } else {
332 gen_helper_sreg_read_pair(dst, tcg_env, tcg_constant_i32(reg_num));
333 }
334 }
335
336 G_GNUC_UNUSED
337 static void gen_read_greg(TCGv_i32 dst, int reg_num)
338 {
339 if (reg_num <= HEX_GREG_G3) {
340 tcg_gen_mov_i32(dst, hex_greg[reg_num]);
341 } else {
342 gen_helper_greg_read(dst, tcg_env, tcg_constant_i32(reg_num));
343 }
344 }
345
346 G_GNUC_UNUSED
347 static void gen_read_greg_pair(TCGv_i64 dst, int reg_num)
348 {
349 if (reg_num == HEX_GREG_G0 || reg_num == HEX_GREG_G2) {
350 tcg_gen_concat_i32_i64(dst, hex_greg[reg_num],
351 hex_greg[reg_num + 1]);
352 } else {
353 gen_helper_greg_read_pair(dst, tcg_env, tcg_constant_i32(reg_num));
354 }
355 }
356 #endif
357
358
359 void gen_pred_write(DisasContext *ctx, int pnum, TCGv val)
360 {
361 TCGv pred = get_result_pred(ctx, pnum);
362 TCGv base_val = tcg_temp_new();
363
364 tcg_gen_andi_tl(base_val, val, 0xff);
365
366 /*
367 * Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual
368 *
369 * Multiple writes to the same preg are and'ed together
370 * If this is the first predicate write in the packet, do a
371 * straight assignment. Otherwise, do an and.
372 */
373 if (!test_bit(pnum, ctx->pregs_written)) {
374 tcg_gen_mov_tl(pred, base_val);
375 } else {
376 tcg_gen_and_tl(pred, pred, base_val);
377 }
378 set_bit(pnum, ctx->pregs_written);
379 }
380
381 static inline void gen_read_p3_0(TCGv control_reg)
382 {
383 tcg_gen_movi_tl(control_reg, 0);
384 for (int i = 0; i < NUM_PREGS; i++) {
385 tcg_gen_deposit_tl(control_reg, control_reg, hex_pred[i], i * 8, 8);
386 }
387 }
388
389 /*
390 * Certain control registers require special handling on read
391 * HEX_REG_P3_0_ALIASED aliased to the predicate registers
392 * -> concat the 4 predicate registers together
393 * HEX_REG_PC actual value stored in DisasContext
394 * -> assign from ctx->base.pc_next
395 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext
396 * -> add current TB changes to existing reg value
397 */
398 static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num,
399 TCGv dest)
400 {
401 if (reg_num == HEX_REG_P3_0_ALIASED) {
402 gen_read_p3_0(dest);
403 } else if (reg_num == HEX_REG_PC) {
404 tcg_gen_movi_tl(dest, ctx->base.pc_next);
405 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
406 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_PKT_CNT],
407 ctx->num_packets);
408 } else if (reg_num == HEX_REG_QEMU_INSN_CNT) {
409 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_INSN_CNT],
410 ctx->num_insns);
411 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
412 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT],
413 ctx->num_hvx_insns);
414 } else {
415 tcg_gen_mov_tl(dest, hex_gpr[reg_num]);
416 }
417 }
418
419 static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num,
420 TCGv_i64 dest)
421 {
422 if (reg_num == HEX_REG_P3_0_ALIASED) {
423 TCGv p3_0 = tcg_temp_new();
424 gen_read_p3_0(p3_0);
425 tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]);
426 } else if (reg_num == HEX_REG_PC - 1) {
427 TCGv pc = tcg_constant_tl(ctx->base.pc_next);
428 tcg_gen_concat_i32_i64(dest, hex_gpr[reg_num], pc);
429 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
430 TCGv pkt_cnt = tcg_temp_new();
431 TCGv insn_cnt = tcg_temp_new();
432 tcg_gen_addi_tl(pkt_cnt, hex_gpr[HEX_REG_QEMU_PKT_CNT],
433 ctx->num_packets);
434 tcg_gen_addi_tl(insn_cnt, hex_gpr[HEX_REG_QEMU_INSN_CNT],
435 ctx->num_insns);
436 tcg_gen_concat_i32_i64(dest, pkt_cnt, insn_cnt);
437 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
438 TCGv hvx_cnt = tcg_temp_new();
439 tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT],
440 ctx->num_hvx_insns);
441 tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]);
442 } else {
443 tcg_gen_concat_i32_i64(dest,
444 hex_gpr[reg_num],
445 hex_gpr[reg_num + 1]);
446 }
447 }
448
449 static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg)
450 {
451 TCGv hex_p8 = tcg_temp_new();
452 for (int i = 0; i < NUM_PREGS; i++) {
453 tcg_gen_extract_tl(hex_p8, control_reg, i * 8, 8);
454 gen_pred_write(ctx, i, hex_p8);
455 }
456 }
457
458 /*
459 * Certain control registers require special handling on write
460 * HEX_REG_P3_0_ALIASED aliased to the predicate registers
461 * -> break the value across 4 predicate registers
462 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext
463 * -> clear the changes
464 */
465 static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
466 TCGv val)
467 {
468 if (reg_num == HEX_REG_P3_0_ALIASED) {
469 gen_write_p3_0(ctx, val);
470 } else {
471 const target_ulong reg_mask = reg_immut_masks[reg_num];
472 gen_masked_reg_write(val, hex_gpr[reg_num], reg_mask);
473 tcg_gen_mov_tl(get_result_gpr(ctx, reg_num), val);
474 if (reg_num == HEX_REG_QEMU_PKT_CNT) {
475 ctx->num_packets = 0;
476 }
477 if (reg_num == HEX_REG_QEMU_INSN_CNT) {
478 ctx->num_insns = 0;
479 }
480 if (reg_num == HEX_REG_QEMU_HVX_CNT) {
481 ctx->num_hvx_insns = 0;
482 }
483 }
484 }
485
486 static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
487 TCGv_i64 val)
488 {
489 TCGv val32 = tcg_temp_new();
490
491 /* Low word */
492 tcg_gen_extrl_i64_i32(val32, val);
493 gen_write_ctrl_reg(ctx, reg_num, val32);
494
495 /* High word */
496 tcg_gen_extrh_i64_i32(val32, val);
497 gen_write_ctrl_reg(ctx, reg_num + 1, val32);
498 }
499
500 TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
501 {
502 if (sign) {
503 tcg_gen_sextract_tl(result, src, N * 8, 8);
504 } else {
505 tcg_gen_extract_tl(result, src, N * 8, 8);
506 }
507 return result;
508 }
509
510 TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
511 {
512 TCGv_i64 res64 = tcg_temp_new_i64();
513 if (sign) {
514 tcg_gen_sextract_i64(res64, src, N * 8, 8);
515 } else {
516 tcg_gen_extract_i64(res64, src, N * 8, 8);
517 }
518 tcg_gen_extrl_i64_i32(result, res64);
519
520 return result;
521 }
522
523 TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
524 {
525 if (sign) {
526 tcg_gen_sextract_tl(result, src, N * 16, 16);
527 } else {
528 tcg_gen_extract_tl(result, src, N * 16, 16);
529 }
530 return result;
531 }
532
533 void gen_set_half(int N, TCGv result, TCGv src)
534 {
535 tcg_gen_deposit_tl(result, result, src, N * 16, 16);
536 }
537
538 void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
539 {
540 TCGv_i64 src64 = tcg_temp_new_i64();
541 tcg_gen_extu_i32_i64(src64, src);
542 tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
543 }
544
545 void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
546 {
547 TCGv_i64 src64 = tcg_temp_new_i64();
548 tcg_gen_extu_i32_i64(src64, src);
549 tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
550 }
551
552 static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
553 {
554 tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_LE | MO_UL | MO_ALIGN);
555 tcg_gen_mov_tl(hex_llsc_addr, vaddr);
556 tcg_gen_mov_tl(hex_llsc_val, dest);
557 }
558
559 static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index)
560 {
561 tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_LE | MO_UQ | MO_ALIGN);
562 tcg_gen_mov_tl(hex_llsc_addr, vaddr);
563 tcg_gen_mov_i64(hex_llsc_val_i64, dest);
564 }
565
566 static inline void gen_store_conditional4(DisasContext *ctx,
567 TCGv pred, TCGv vaddr, TCGv src)
568 {
569 TCGLabel *fail = gen_new_label();
570 TCGLabel *done = gen_new_label();
571 TCGv one, zero, tmp;
572
573 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
574
575 one = tcg_constant_tl(0xff);
576 zero = tcg_constant_tl(0);
577 tmp = tcg_temp_new();
578 tcg_gen_atomic_cmpxchg_tl(tmp, hex_llsc_addr, hex_llsc_val, src,
579 ctx->mem_idx, MO_32 | MO_ALIGN);
580 tcg_gen_movcond_tl(TCG_COND_EQ, pred, tmp, hex_llsc_val,
581 one, zero);
582 tcg_gen_br(done);
583
584 gen_set_label(fail);
585 tcg_gen_movi_tl(pred, 0);
586
587 gen_set_label(done);
588 tcg_gen_movi_tl(hex_llsc_addr, ~0);
589 }
590
591 static inline void gen_store_conditional8(DisasContext *ctx,
592 TCGv pred, TCGv vaddr, TCGv_i64 src)
593 {
594 TCGLabel *fail = gen_new_label();
595 TCGLabel *done = gen_new_label();
596 TCGv_i64 one, zero, tmp;
597
598 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
599
600 one = tcg_constant_i64(0xff);
601 zero = tcg_constant_i64(0);
602 tmp = tcg_temp_new_i64();
603 tcg_gen_atomic_cmpxchg_i64(tmp, hex_llsc_addr, hex_llsc_val_i64, src,
604 ctx->mem_idx, MO_64 | MO_ALIGN);
605 tcg_gen_movcond_i64(TCG_COND_EQ, tmp, tmp, hex_llsc_val_i64,
606 one, zero);
607 tcg_gen_extrl_i64_i32(pred, tmp);
608 tcg_gen_br(done);
609
610 gen_set_label(fail);
611 tcg_gen_movi_tl(pred, 0);
612
613 gen_set_label(done);
614 tcg_gen_movi_tl(hex_llsc_addr, ~0);
615 }
616
617 #ifndef CONFIG_HEXAGON_IDEF_PARSER
618 static TCGv gen_slotval(DisasContext *ctx)
619 {
620 int slotval =
621 (ctx->pkt.pkt_has_scalar_store_s1 & 1) | (ctx->insn->slot << 1);
622 return tcg_constant_tl(slotval);
623 }
624 #endif
625
626 void gen_store32(TCGv vaddr, TCGv src, uint32_t width, uint32_t slot)
627 {
628 tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
629 tcg_gen_movi_i32(hex_store_width[slot], width);
630 tcg_gen_mov_tl(hex_store_val32[slot], src);
631 }
632
633 void gen_store1(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot)
634 {
635 gen_store32(vaddr, src, 1, slot);
636 }
637
638 void gen_store1i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot)
639 {
640 TCGv tmp = tcg_constant_tl(src);
641 gen_store1(tcg_env, vaddr, tmp, slot);
642 }
643
644 void gen_store2(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot)
645 {
646 gen_store32(vaddr, src, 2, slot);
647 }
648
649 void gen_store2i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot)
650 {
651 TCGv tmp = tcg_constant_tl(src);
652 gen_store2(tcg_env, vaddr, tmp, slot);
653 }
654
655 void gen_store4(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot)
656 {
657 gen_store32(vaddr, src, 4, slot);
658 }
659
660 void gen_store4i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot)
661 {
662 TCGv tmp = tcg_constant_tl(src);
663 gen_store4(tcg_env, vaddr, tmp, slot);
664 }
665
666 void gen_store8(TCGv_env tcg_env, TCGv vaddr, TCGv_i64 src, uint32_t slot)
667 {
668 tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
669 tcg_gen_movi_i32(hex_store_width[slot], 8);
670 tcg_gen_mov_i64(hex_store_val64[slot], src);
671 }
672
673 void gen_store8i(TCGv_env tcg_env, TCGv vaddr, int64_t src, uint32_t slot)
674 {
675 TCGv_i64 tmp = tcg_constant_i64(src);
676 gen_store8(tcg_env, vaddr, tmp, slot);
677 }
678
679 TCGv gen_8bitsof(TCGv result, TCGv value)
680 {
681 TCGv zero = tcg_constant_tl(0);
682 TCGv ones = tcg_constant_tl(0xff);
683 tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
684
685 return result;
686 }
687
688 static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr,
689 TCGCond cond, TCGv pred)
690 {
691 TCGLabel *pred_false = NULL;
692 if (cond != TCG_COND_ALWAYS) {
693 pred_false = gen_new_label();
694 tcg_gen_brcondi_tl(cond, pred, 1, pred_false);
695 }
696
697 /*
698 * If gen_end_tb() will unconditionally overwrite PC with hex_next_PC
699 * (because this packet has a predicated COF that may not execute),
700 * write the branch target there instead of directly into the PC
701 * global, or the overwrite in gen_end_tb() would clobber it.
702 */
703 TCGv pc_wr = ctx->need_next_pc ? hex_next_PC : hex_gpr[HEX_REG_PC];
704
705 if (ctx->pkt.pkt_has_multi_cof) {
706 /* If there are multiple branches in a packet, ignore the second one */
707 tcg_gen_movcond_tl(TCG_COND_NE, pc_wr,
708 ctx->branch_taken, tcg_constant_tl(0),
709 pc_wr, addr);
710 tcg_gen_movi_tl(ctx->branch_taken, 1);
711 } else {
712 tcg_gen_mov_tl(pc_wr, addr);
713 }
714
715 if (cond != TCG_COND_ALWAYS) {
716 gen_set_label(pred_false);
717 }
718 }
719
720 static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off,
721 TCGCond cond, TCGv pred)
722 {
723 target_ulong dest = ctx->pkt.pc + pc_off;
724 if (ctx->pkt.pkt_has_multi_cof) {
725 gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred);
726 } else {
727 /* Defer this jump to the end of the TB */
728 ctx->branch_cond = TCG_COND_ALWAYS;
729 if (pred != NULL) {
730 ctx->branch_cond = cond;
731 tcg_gen_mov_tl(ctx->branch_taken, pred);
732 }
733 ctx->branch_dest = dest;
734 }
735 }
736
737 void gen_set_usr_field(DisasContext *ctx, int field, TCGv val)
738 {
739 TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
740 tcg_gen_deposit_tl(usr, usr, val,
741 reg_field_info[field].offset,
742 reg_field_info[field].width);
743 }
744
745 void gen_set_usr_fieldi(DisasContext *ctx, int field, int x)
746 {
747 if (reg_field_info[field].width == 1) {
748 TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
749 target_ulong bit = 1 << reg_field_info[field].offset;
750 if ((x & 1) == 1) {
751 tcg_gen_ori_tl(usr, usr, bit);
752 } else {
753 tcg_gen_andi_tl(usr, usr, ~bit);
754 }
755 } else {
756 TCGv val = tcg_constant_tl(x);
757 gen_set_usr_field(ctx, field, val);
758 }
759 }
760
761 static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2)
762 {
763 TCGv one = tcg_constant_tl(0xff);
764 TCGv zero = tcg_constant_tl(0);
765
766 tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero);
767 }
768
769 #ifndef CONFIG_HEXAGON_IDEF_PARSER
770 static inline void gen_loop0r(DisasContext *ctx, TCGv RsV, int riV)
771 {
772 fIMMEXT(riV);
773 fPCALIGN(riV);
774 tcg_gen_mov_tl(get_result_gpr(ctx, HEX_REG_LC0), RsV);
775 tcg_gen_movi_tl(get_result_gpr(ctx, HEX_REG_SA0), ctx->pkt.pc + riV);
776 gen_set_usr_fieldi(ctx, USR_LPCFG, 0);
777 }
778
779 static void gen_loop0i(DisasContext *ctx, int count, int riV)
780 {
781 gen_loop0r(ctx, tcg_constant_tl(count), riV);
782 }
783
784 static inline void gen_loop1r(DisasContext *ctx, TCGv RsV, int riV)
785 {
786 fIMMEXT(riV);
787 fPCALIGN(riV);
788 tcg_gen_mov_tl(get_result_gpr(ctx, HEX_REG_LC1), RsV);
789 tcg_gen_movi_tl(get_result_gpr(ctx, HEX_REG_SA1), ctx->pkt.pc + riV);
790 }
791
792 static void gen_loop1i(DisasContext *ctx, int count, int riV)
793 {
794 gen_loop1r(ctx, tcg_constant_tl(count), riV);
795 }
796
797 static void gen_ploopNsr(DisasContext *ctx, int N, TCGv RsV, int riV)
798 {
799 fIMMEXT(riV);
800 fPCALIGN(riV);
801 tcg_gen_mov_tl(get_result_gpr(ctx, HEX_REG_LC0), RsV);
802 tcg_gen_movi_tl(get_result_gpr(ctx, HEX_REG_SA0), ctx->pkt.pc + riV);
803 gen_set_usr_fieldi(ctx, USR_LPCFG, N);
804 gen_pred_write(ctx, 3, tcg_constant_tl(0));
805 }
806
807 static void gen_ploopNsi(DisasContext *ctx, int N, int count, int riV)
808 {
809 gen_ploopNsr(ctx, N, tcg_constant_tl(count), riV);
810 }
811
812 static inline void gen_comparei(TCGCond cond, TCGv res, TCGv arg1, int arg2)
813 {
814 gen_compare(cond, res, arg1, tcg_constant_tl(arg2));
815 }
816 #endif
817
818 static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc,
819 TCGCond cond, TCGv pred)
820 {
821 gen_write_new_pc_addr(ctx, dst_pc, cond, pred);
822 }
823
824 static void gen_cond_jumpr31(DisasContext *ctx, TCGCond cond, TCGv pred)
825 {
826 gen_cond_jumpr(ctx, hex_gpr[HEX_REG_LR], cond, pred);
827 }
828
829 static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred,
830 int pc_off)
831 {
832 gen_write_new_pc_pcrel(ctx, pc_off, cond, pred);
833 }
834
835 static void gen_cmpnd_cmp_jmp(DisasContext *ctx,
836 int pnum, TCGCond cond1, TCGv arg1, TCGv arg2,
837 TCGCond cond2, int pc_off)
838 {
839 if (ctx->insn->part1) {
840 TCGv pred = tcg_temp_new();
841 gen_compare(cond1, pred, arg1, arg2);
842 gen_pred_write(ctx, pnum, pred);
843 } else {
844 TCGv pred = tcg_temp_new();
845 tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]);
846 gen_cond_jump(ctx, cond2, pred, pc_off);
847 }
848 }
849
850 static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx,
851 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
852 int pc_off)
853 {
854 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_TSTEQ, pc_off);
855 }
856
857 static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx,
858 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
859 int pc_off)
860 {
861 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_TSTNE, pc_off);
862 }
863
864 static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx,
865 int pnum, TCGCond cond, TCGv arg1, int arg2,
866 int pc_off)
867 {
868 TCGv tmp = tcg_constant_tl(arg2);
869 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_TSTEQ, pc_off);
870 }
871
872 static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx,
873 int pnum, TCGCond cond, TCGv arg1, int arg2,
874 int pc_off)
875 {
876 TCGv tmp = tcg_constant_tl(arg2);
877 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_TSTNE, pc_off);
878 }
879
880 static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond,
881 TCGv arg, int pc_off)
882 {
883 gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off);
884 }
885
886 static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond,
887 TCGv arg, int pc_off)
888 {
889 gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off);
890 }
891
892 static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx,
893 int pnum, TCGv arg, TCGCond cond, int pc_off)
894 {
895 if (ctx->insn->part1) {
896 TCGv pred = tcg_temp_new();
897 tcg_gen_andi_tl(pred, arg, 1);
898 gen_8bitsof(pred, pred);
899 gen_pred_write(ctx, pnum, pred);
900 } else {
901 TCGv pred = tcg_temp_new();
902 tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]);
903 gen_cond_jump(ctx, cond, pred, pc_off);
904 }
905 }
906
907 static void gen_testbit0_jumpnv(DisasContext *ctx,
908 TCGv arg, TCGCond cond, int pc_off)
909 {
910 gen_cond_jump(ctx, cond, arg, pc_off);
911 }
912
913 static void gen_jump(DisasContext *ctx, int pc_off)
914 {
915 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL);
916 }
917
918 static void gen_jumpr(DisasContext *ctx, TCGv new_pc)
919 {
920 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL);
921 }
922
923 static void gen_call(DisasContext *ctx, int pc_off)
924 {
925 TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
926 tcg_gen_movi_tl(lr, ctx->next_PC);
927 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL);
928 }
929
930 static void gen_callr(DisasContext *ctx, TCGv new_pc)
931 {
932 TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
933 tcg_gen_movi_tl(lr, ctx->next_PC);
934 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL);
935 }
936
937 static void gen_cond_call(DisasContext *ctx, TCGv pred,
938 TCGCond cond, int pc_off)
939 {
940 TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
941 TCGLabel *skip = gen_new_label();
942 gen_write_new_pc_pcrel(ctx, pc_off, cond, pred);
943 tcg_gen_brcondi_tl(cond, pred, 1, skip);
944 tcg_gen_movi_tl(lr, ctx->next_PC);
945 gen_set_label(skip);
946 }
947
948 static void gen_cond_callr(DisasContext *ctx,
949 TCGCond cond, TCGv pred, TCGv new_pc)
950 {
951 TCGLabel *skip = gen_new_label();
952 tcg_gen_brcondi_tl(cond, pred, 1, skip);
953 gen_callr(ctx, new_pc);
954 gen_set_label(skip);
955 }
956
957 #ifndef CONFIG_HEXAGON_IDEF_PARSER
958 /* frame = ((LR << 32) | FP) ^ (FRAMEKEY << 32)) */
959 static TCGv_i64 gen_frame_scramble(void)
960 {
961 TCGv_i64 frame = tcg_temp_new_i64();
962 TCGv tmp = tcg_temp_new();
963 tcg_gen_xor_tl(tmp, hex_gpr[HEX_REG_LR], hex_gpr[HEX_REG_FRAMEKEY]);
964 tcg_gen_concat_i32_i64(frame, hex_gpr[HEX_REG_FP], tmp);
965 return frame;
966 }
967 #endif
968
969 /* frame ^= (int64_t)FRAMEKEY << 32 */
970 static void gen_frame_unscramble(TCGv_i64 frame)
971 {
972 TCGv_i64 framekey = tcg_temp_new_i64();
973 tcg_gen_extu_i32_i64(framekey, hex_gpr[HEX_REG_FRAMEKEY]);
974 tcg_gen_shli_i64(framekey, framekey, 32);
975 tcg_gen_xor_i64(frame, frame, framekey);
976 }
977
978 static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA)
979 {
980 Insn *insn = ctx->insn; /* Needed for CHECK_NOSHUF */
981 CHECK_NOSHUF(EA, 8);
982 tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_LE | MO_UQ | MO_ALIGN);
983 }
984
985 /* Stack overflow check */
986 void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea)
987 {
988 #ifndef CONFIG_USER_ONLY
989 TCGLabel *ok = gen_new_label();
990 tcg_gen_brcond_i32(TCG_COND_GEU, addr, hex_gpr[HEX_REG_FRAMELIMIT], ok);
991 gen_helper_raise_stack_overflow(tcg_env,
992 tcg_constant_i32(ctx->insn->slot), ea);
993 gen_set_label(ok);
994 #endif
995 }
996
997 #ifndef CONFIG_HEXAGON_IDEF_PARSER
998 static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize)
999 {
1000 TCGv r30 = get_result_gpr(ctx, HEX_REG_FP);
1001 TCGv_i32 new_r29 = tcg_temp_new_i32();
1002 TCGv_i64 frame;
1003 tcg_gen_addi_tl(r30, r29, -8);
1004 frame = gen_frame_scramble();
1005 gen_store8(tcg_env, r30, frame, ctx->insn->slot);
1006 tcg_gen_subi_tl(new_r29, r30, framesize);
1007 gen_framecheck(ctx, new_r29, hex_gpr[HEX_REG_PC]);
1008 tcg_gen_mov_tl(r29, new_r29);
1009 }
1010
1011 static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30)
1012 {
1013 TCGv r29 = get_result_gpr(ctx, HEX_REG_SP);
1014 TCGv_i64 frame = tcg_temp_new_i64();
1015 gen_load_frame(ctx, frame, r30);
1016 gen_frame_unscramble(frame);
1017 tcg_gen_mov_i64(r31_30, frame);
1018 tcg_gen_addi_tl(r29, r30, 8);
1019 }
1020 #endif
1021
1022 static void gen_return(DisasContext *ctx, TCGv_i64 dst, TCGv src)
1023 {
1024 /*
1025 * frame = *src
1026 * dst = frame_unscramble(frame)
1027 * SP = src + 8
1028 * PC = dst.w[1]
1029 */
1030 TCGv_i64 frame = tcg_temp_new_i64();
1031 TCGv r31 = tcg_temp_new();
1032 TCGv r29 = get_result_gpr(ctx, HEX_REG_SP);
1033
1034 gen_load_frame(ctx, frame, src);
1035 gen_frame_unscramble(frame);
1036 tcg_gen_mov_i64(dst, frame);
1037 tcg_gen_addi_tl(r29, src, 8);
1038 tcg_gen_extrh_i64_i32(r31, dst);
1039 gen_jumpr(ctx, r31);
1040 }
1041
1042 /* if (pred) dst = dealloc_return(src):raw */
1043 static void gen_cond_return(DisasContext *ctx, TCGv_i64 dst, TCGv src,
1044 TCGv pred, TCGCond cond)
1045 {
1046 TCGv LSB = tcg_temp_new();
1047 TCGLabel *skip = gen_new_label();
1048 tcg_gen_andi_tl(LSB, pred, 1);
1049
1050 tcg_gen_brcondi_tl(cond, LSB, 0, skip);
1051 gen_return(ctx, dst, src);
1052 gen_set_label(skip);
1053 }
1054
1055 /* sub-instruction version (no RddV, so handle it manually) */
1056 static void gen_cond_return_subinsn(DisasContext *ctx, TCGCond cond, TCGv pred)
1057 {
1058 TCGv_i64 RddV = get_result_gpr_pair(ctx, HEX_REG_FP);
1059 gen_cond_return(ctx, RddV, hex_gpr[HEX_REG_FP], pred, cond);
1060 gen_write_reg_pair(ctx, HEX_REG_FP, RddV);
1061 }
1062
1063 static void gen_endloop0(DisasContext *ctx)
1064 {
1065 TCGv lpcfg = tcg_temp_new();
1066
1067 GET_USR_FIELD(USR_LPCFG, lpcfg);
1068
1069 /*
1070 * if (lpcfg == 1) {
1071 * p3 = 0xff;
1072 * }
1073 */
1074 TCGLabel *label1 = gen_new_label();
1075 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
1076 {
1077 gen_pred_write(ctx, 3, tcg_constant_tl(0xff));
1078 }
1079 gen_set_label(label1);
1080
1081 /*
1082 * if (lpcfg) {
1083 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
1084 * }
1085 */
1086 TCGLabel *label2 = gen_new_label();
1087 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
1088 {
1089 tcg_gen_subi_tl(lpcfg, lpcfg, 1);
1090 gen_set_usr_field(ctx, USR_LPCFG, lpcfg);
1091 }
1092 gen_set_label(label2);
1093
1094 /*
1095 * If we're in a tight loop, we'll do this at the end of the TB to take
1096 * advantage of direct block chaining.
1097 */
1098 if (!ctx->is_tight_loop) {
1099 /*
1100 * if (LC0 > 1) {
1101 * PC = SA0;
1102 * LC0--;
1103 * }
1104 */
1105 TCGLabel *label3 = gen_new_label();
1106 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
1107 {
1108 TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0);
1109 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
1110 tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1);
1111 }
1112 gen_set_label(label3);
1113 }
1114 }
1115
1116 static void gen_endloop1(DisasContext *ctx)
1117 {
1118 /*
1119 * if (LC1 > 1) {
1120 * PC = SA1;
1121 * LC1--;
1122 * }
1123 */
1124 TCGLabel *label = gen_new_label();
1125 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, label);
1126 {
1127 TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1);
1128 gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]);
1129 tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1);
1130 }
1131 gen_set_label(label);
1132 }
1133
1134 static void gen_endloop01(DisasContext *ctx)
1135 {
1136 TCGv lpcfg = tcg_temp_new();
1137 TCGLabel *label1 = gen_new_label();
1138 TCGLabel *label2 = gen_new_label();
1139 TCGLabel *label3 = gen_new_label();
1140 TCGLabel *done = gen_new_label();
1141
1142 GET_USR_FIELD(USR_LPCFG, lpcfg);
1143
1144 /*
1145 * if (lpcfg == 1) {
1146 * p3 = 0xff;
1147 * }
1148 */
1149 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
1150 {
1151 gen_pred_write(ctx, 3, tcg_constant_tl(0xff));
1152 }
1153 gen_set_label(label1);
1154
1155 /*
1156 * if (lpcfg) {
1157 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
1158 * }
1159 */
1160 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
1161 {
1162 tcg_gen_subi_tl(lpcfg, lpcfg, 1);
1163 gen_set_usr_field(ctx, USR_LPCFG, lpcfg);
1164 }
1165 gen_set_label(label2);
1166
1167 /*
1168 * if (LC0 > 1) {
1169 * PC = SA0;
1170 * LC0--;
1171 * } else if (LC1 > 1) {
1172 * PC = SA1;
1173 * LC1--;
1174 * }
1175 */
1176 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
1177 {
1178 TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0);
1179 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
1180 tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1);
1181 tcg_gen_br(done);
1182 }
1183 gen_set_label(label3);
1184 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, done);
1185 {
1186 TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1);
1187 gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]);
1188 tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1);
1189 }
1190 gen_set_label(done);
1191 }
1192
1193 static void gen_cmp_jumpnv(DisasContext *ctx,
1194 TCGCond cond, TCGv val, TCGv src, int pc_off)
1195 {
1196 TCGv pred = tcg_temp_new();
1197 tcg_gen_setcond_tl(cond, pred, val, src);
1198 gen_cond_jump(ctx, TCG_COND_TSTEQ, pred, pc_off);
1199 }
1200
1201 static void gen_cmpi_jumpnv(DisasContext *ctx,
1202 TCGCond cond, TCGv val, int src, int pc_off)
1203 {
1204 TCGv pred = tcg_temp_new();
1205 tcg_gen_setcondi_tl(cond, pred, val, src);
1206 gen_cond_jump(ctx, TCG_COND_TSTEQ, pred, pc_off);
1207 }
1208
1209 /* Shift left with saturation */
1210 static void gen_shl_sat(DisasContext *ctx, TCGv dst, TCGv src, TCGv shift_amt)
1211 {
1212 TCGv tmp = tcg_temp_new(); /* In case dst == src */
1213 TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
1214 TCGv sh32 = tcg_temp_new();
1215 TCGv dst_sar = tcg_temp_new();
1216 TCGv ovf = tcg_temp_new();
1217 TCGv satval = tcg_temp_new();
1218 TCGv min = tcg_constant_tl(0x80000000);
1219 TCGv max = tcg_constant_tl(0x7fffffff);
1220
1221 /*
1222 * Possible values for shift_amt are 0 .. 64
1223 * We need special handling for values above 31
1224 *
1225 * sh32 = shift & 31;
1226 * dst = sh32 == shift ? src : 0;
1227 * dst <<= sh32;
1228 * dst_sar = dst >> sh32;
1229 * satval = src < 0 ? min : max;
1230 * if (dst_asr != src) {
1231 * usr.OVF |= 1;
1232 * dst = satval;
1233 * }
1234 */
1235
1236 tcg_gen_andi_tl(sh32, shift_amt, 31);
1237 tcg_gen_movcond_tl(TCG_COND_EQ, tmp, sh32, shift_amt,
1238 src, tcg_constant_tl(0));
1239 tcg_gen_shl_tl(tmp, tmp, sh32);
1240 tcg_gen_sar_tl(dst_sar, tmp, sh32);
1241 tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max);
1242
1243 tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src);
1244 tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset);
1245 tcg_gen_or_tl(usr, usr, ovf);
1246
1247 tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, tmp, satval);
1248 }
1249
1250 static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt)
1251 {
1252 /*
1253 * Shift arithmetic right
1254 * Robust when shift_amt is >31 bits
1255 */
1256 TCGv tmp = tcg_temp_new();
1257 tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31));
1258 tcg_gen_sar_tl(dst, src, tmp);
1259 }
1260
1261 /* Bidirectional shift right with saturation */
1262 static void gen_asr_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV)
1263 {
1264 TCGv shift_amt = tcg_temp_new();
1265 TCGLabel *positive = gen_new_label();
1266 TCGLabel *done = gen_new_label();
1267
1268 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
1269 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
1270
1271 /* Negative shift amount => shift left */
1272 tcg_gen_neg_tl(shift_amt, shift_amt);
1273 gen_shl_sat(ctx, RdV, RsV, shift_amt);
1274 tcg_gen_br(done);
1275
1276 gen_set_label(positive);
1277 /* Positive shift amount => shift right */
1278 gen_sar(RdV, RsV, shift_amt);
1279
1280 gen_set_label(done);
1281 }
1282
1283 /* Bidirectional shift left with saturation */
1284 static void gen_asl_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV)
1285 {
1286 TCGv shift_amt = tcg_temp_new();
1287 TCGLabel *positive = gen_new_label();
1288 TCGLabel *done = gen_new_label();
1289
1290 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
1291 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
1292
1293 /* Negative shift amount => shift right */
1294 tcg_gen_neg_tl(shift_amt, shift_amt);
1295 gen_sar(RdV, RsV, shift_amt);
1296 tcg_gen_br(done);
1297
1298 gen_set_label(positive);
1299 /* Positive shift amount => shift left */
1300 gen_shl_sat(ctx, RdV, RsV, shift_amt);
1301
1302 gen_set_label(done);
1303 }
1304
1305 static void gen_insert_rp(DisasContext *ctx, TCGv RxV, TCGv RsV, TCGv_i64 RttV)
1306 {
1307 /*
1308 * int width = fZXTN(6, 32, (fGETWORD(1, RttV)));
1309 * int offset = fSXTN(7, 32, (fGETWORD(0, RttV)));
1310 * size8u_t mask = ((fCONSTLL(1) << width) - 1);
1311 * if (offset < 0) {
1312 * RxV = 0;
1313 * } else {
1314 * RxV &= ~(mask << offset);
1315 * RxV |= ((RsV & mask) << offset);
1316 * }
1317 */
1318
1319 TCGv width = tcg_temp_new();
1320 TCGv offset = tcg_temp_new();
1321 TCGv_i64 mask = tcg_temp_new_i64();
1322 TCGv_i64 result = tcg_temp_new_i64();
1323 TCGv_i64 tmp = tcg_temp_new_i64();
1324 TCGv_i64 offset64 = tcg_temp_new_i64();
1325 TCGLabel *label = gen_new_label();
1326 TCGLabel *done = gen_new_label();
1327
1328 tcg_gen_extrh_i64_i32(width, RttV);
1329 tcg_gen_extract_tl(width, width, 0, 6);
1330 tcg_gen_extrl_i64_i32(offset, RttV);
1331 tcg_gen_sextract_tl(offset, offset, 0, 7);
1332 /* Possible values for offset are -64 .. 63 */
1333 tcg_gen_brcondi_tl(TCG_COND_GE, offset, 0, label);
1334 /* For negative offsets, zero out the result */
1335 tcg_gen_movi_tl(RxV, 0);
1336 tcg_gen_br(done);
1337 gen_set_label(label);
1338 /* At this point, possible values of offset are 0 .. 63 */
1339 tcg_gen_ext_i32_i64(mask, width);
1340 tcg_gen_shl_i64(mask, tcg_constant_i64(1), mask);
1341 tcg_gen_subi_i64(mask, mask, 1);
1342 tcg_gen_extu_i32_i64(result, RxV);
1343 tcg_gen_ext_i32_i64(tmp, offset);
1344 tcg_gen_shl_i64(tmp, mask, tmp);
1345 tcg_gen_andc_i64(result, result, tmp);
1346 tcg_gen_extu_i32_i64(tmp, RsV);
1347 tcg_gen_and_i64(tmp, tmp, mask);
1348 tcg_gen_extu_i32_i64(offset64, offset);
1349 tcg_gen_shl_i64(tmp, tmp, offset64);
1350 tcg_gen_or_i64(result, result, tmp);
1351 tcg_gen_extrl_i64_i32(RxV, result);
1352 gen_set_label(done);
1353 }
1354
1355 static void gen_asr_r_svw_trun(DisasContext *ctx, TCGv RdV,
1356 TCGv_i64 RssV, TCGv RtV)
1357 {
1358 /*
1359 * for (int i = 0; i < 2; i++) {
1360 * fSETHALF(i, RdV, fGETHALF(0, ((fSXTN(7, 32, RtV) > 0) ?
1361 * (fCAST4_8s(fGETWORD(i, RssV)) >> fSXTN(7, 32, RtV)) :
1362 * (fCAST4_8s(fGETWORD(i, RssV)) << -fSXTN(7, 32, RtV)))));
1363 * }
1364 */
1365 TCGv shift_amt32 = tcg_temp_new();
1366 TCGv_i64 shift_amt64 = tcg_temp_new_i64();
1367 TCGv_i64 tmp64 = tcg_temp_new_i64();
1368 TCGv tmp32 = tcg_temp_new();
1369 TCGLabel *label = gen_new_label();
1370 TCGLabel *zero = gen_new_label();
1371 TCGLabel *done = gen_new_label();
1372
1373 tcg_gen_sextract_tl(shift_amt32, RtV, 0, 7);
1374 /* Possible values of shift_amt32 are -64 .. 63 */
1375 tcg_gen_brcondi_tl(TCG_COND_LE, shift_amt32, 0, label);
1376 /* After branch, possible values of shift_amt32 are 1 .. 63 */
1377 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32);
1378 for (int i = 0; i < 2; i++) {
1379 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32);
1380 tcg_gen_sar_i64(tmp64, tmp64, shift_amt64);
1381 tcg_gen_extrl_i64_i32(tmp32, tmp64);
1382 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16);
1383 }
1384 tcg_gen_br(done);
1385 gen_set_label(label);
1386 tcg_gen_neg_tl(shift_amt32, shift_amt32);
1387 /*At this point, possible values of shift_amt32 are 0 .. 64 */
1388 tcg_gen_brcondi_tl(TCG_COND_GT, shift_amt32, 63, zero);
1389 /*At this point, possible values of shift_amt32 are 0 .. 63 */
1390 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32);
1391 for (int i = 0; i < 2; i++) {
1392 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32);
1393 tcg_gen_shl_i64(tmp64, tmp64, shift_amt64);
1394 tcg_gen_extrl_i64_i32(tmp32, tmp64);
1395 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16);
1396 }
1397 tcg_gen_br(done);
1398 gen_set_label(zero);
1399 /* When the shift_amt is 64, zero out the result */
1400 tcg_gen_movi_tl(RdV, 0);
1401 gen_set_label(done);
1402 }
1403
1404 static intptr_t vreg_src_off(DisasContext *ctx, int num)
1405 {
1406 intptr_t offset = offsetof(CPUHexagonState, VRegs[num]);
1407
1408 if (test_bit(num, ctx->vregs_select)) {
1409 offset = ctx_future_vreg_off(ctx, num, 1, false);
1410 }
1411 if (test_bit(num, ctx->vregs_updated_tmp)) {
1412 offset = ctx_tmp_vreg_off(ctx, num, 1, false);
1413 }
1414 return offset;
1415 }
1416
1417 static void gen_vreg_write(DisasContext *ctx, intptr_t srcoff, int num,
1418 VRegWriteType type)
1419 {
1420 intptr_t dstoff;
1421
1422 if (type != EXT_TMP) {
1423 dstoff = ctx_future_vreg_off(ctx, num, 1, true);
1424 tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
1425 sizeof(MMVector), sizeof(MMVector));
1426 } else {
1427 dstoff = ctx_tmp_vreg_off(ctx, num, 1, false);
1428 tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
1429 sizeof(MMVector), sizeof(MMVector));
1430 }
1431 }
1432
1433 static void gen_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num,
1434 VRegWriteType type)
1435 {
1436 gen_vreg_write(ctx, srcoff, num ^ 0, type);
1437 srcoff += sizeof(MMVector);
1438 gen_vreg_write(ctx, srcoff, num ^ 1, type);
1439 }
1440
1441 static intptr_t get_result_qreg(DisasContext *ctx, int qnum)
1442 {
1443 if (ctx->need_commit) {
1444 return offsetof(CPUHexagonState, future_QRegs[qnum]);
1445 } else {
1446 return offsetof(CPUHexagonState, QRegs[qnum]);
1447 }
1448 }
1449
1450 static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src,
1451 bool aligned)
1452 {
1453 TCGv_i64 tmp = tcg_temp_new_i64();
1454 if (aligned) {
1455 tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1));
1456 }
1457 for (int i = 0; i < sizeof(MMVector) / 8; i++) {
1458 tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_LE | MO_UQ);
1459 tcg_gen_addi_tl(src, src, 8);
1460 tcg_gen_st_i64(tmp, tcg_env, dstoff + i * 8);
1461 }
1462 }
1463
1464 static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
1465 int slot, bool aligned)
1466 {
1467 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
1468 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
1469
1470 if (is_gather_store_insn(ctx)) {
1471 TCGv sl = tcg_constant_tl(slot);
1472 gen_helper_gather_store(tcg_env, EA, sl);
1473 return;
1474 }
1475
1476 tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
1477 if (aligned) {
1478 tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
1479 ~((int32_t)sizeof(MMVector) - 1));
1480 } else {
1481 tcg_gen_mov_tl(hex_vstore_addr[slot], EA);
1482 }
1483 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
1484
1485 /* Copy the data to the vstore buffer */
1486 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
1487 /* Set the mask to all 1's */
1488 tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL);
1489 }
1490
1491 static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
1492 intptr_t bitsoff, int slot, bool invert)
1493 {
1494 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
1495 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
1496
1497 tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
1498 tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
1499 ~((int32_t)sizeof(MMVector) - 1));
1500 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
1501
1502 /* Copy the data to the vstore buffer */
1503 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
1504 /* Copy the mask */
1505 tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg));
1506 if (invert) {
1507 tcg_gen_gvec_not(MO_64, maskoff, maskoff,
1508 sizeof(MMQReg), sizeof(MMQReg));
1509 }
1510 }
1511
1512 static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff)
1513 {
1514 TCGv_i64 tmp = tcg_temp_new_i64();
1515 TCGv_i64 word = tcg_temp_new_i64();
1516 TCGv_i64 bits = tcg_temp_new_i64();
1517 TCGv_i64 mask = tcg_temp_new_i64();
1518 TCGv_i64 zero = tcg_constant_i64(0);
1519 TCGv_i64 ones = tcg_constant_i64(~0);
1520
1521 for (int i = 0; i < sizeof(MMVector) / 8; i++) {
1522 tcg_gen_ld_i64(tmp, tcg_env, srcoff + i * 8);
1523 tcg_gen_movi_i64(mask, 0);
1524
1525 for (int j = 0; j < 8; j += size) {
1526 tcg_gen_extract_i64(word, tmp, j * 8, size * 8);
1527 tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero);
1528 tcg_gen_deposit_i64(mask, mask, bits, j, size);
1529 }
1530
1531 tcg_gen_st8_i64(mask, tcg_env, dstoff + i);
1532 }
1533 }
1534
1535 void probe_noshuf_load(TCGv va, int s, int mi)
1536 {
1537 TCGv size = tcg_constant_tl(s);
1538 TCGv mem_idx = tcg_constant_tl(mi);
1539 gen_helper_probe_noshuf_load(tcg_env, va, size, mem_idx);
1540 }
1541
1542 /*
1543 * Note: Since this function might branch, `val` is
1544 * required to be a `tcg_temp_local`.
1545 */
1546 void gen_set_usr_field_if(DisasContext *ctx, int field, TCGv val)
1547 {
1548 /* Sets the USR field if `val` is non-zero */
1549 if (reg_field_info[field].width == 1) {
1550 TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
1551 TCGv tmp = tcg_temp_new();
1552 tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
1553 tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
1554 tcg_gen_or_tl(usr, usr, tmp);
1555 } else {
1556 TCGLabel *skip_label = gen_new_label();
1557 tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
1558 gen_set_usr_field(ctx, field, val);
1559 gen_set_label(skip_label);
1560 }
1561 }
1562
1563 void gen_sat_i32(TCGv dest, TCGv source, int width)
1564 {
1565 TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1);
1566 TCGv min_val = tcg_constant_tl(-(1 << (width - 1)));
1567 tcg_gen_smin_tl(dest, source, max_val);
1568 tcg_gen_smax_tl(dest, dest, min_val);
1569 }
1570
1571 void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
1572 {
1573 TCGv tmp = tcg_temp_new(); /* In case dest == source */
1574 gen_sat_i32(tmp, source, width);
1575 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp);
1576 tcg_gen_mov_tl(dest, tmp);
1577 }
1578
1579 void gen_satu_i32(TCGv dest, TCGv source, int width)
1580 {
1581 TCGv tmp = tcg_temp_new(); /* In case dest == source */
1582 TCGv max_val = tcg_constant_tl((1 << width) - 1);
1583 TCGv zero = tcg_constant_tl(0);
1584 tcg_gen_movcond_tl(TCG_COND_GTU, tmp, source, max_val, max_val, source);
1585 tcg_gen_movcond_tl(TCG_COND_LT, tmp, source, zero, zero, tmp);
1586 tcg_gen_mov_tl(dest, tmp);
1587 }
1588
1589 void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
1590 {
1591 TCGv tmp = tcg_temp_new(); /* In case dest == source */
1592 gen_satu_i32(tmp, source, width);
1593 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp);
1594 tcg_gen_mov_tl(dest, tmp);
1595 }
1596
1597 void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width)
1598 {
1599 TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL);
1600 TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1)));
1601 tcg_gen_smin_i64(dest, source, max_val);
1602 tcg_gen_smax_i64(dest, dest, min_val);
1603 }
1604
1605 void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
1606 {
1607 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */
1608 TCGv_i64 ovfl_64;
1609 gen_sat_i64(tmp, source, width);
1610 ovfl_64 = tcg_temp_new_i64();
1611 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source);
1612 tcg_gen_mov_i64(dest, tmp);
1613 tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
1614 }
1615
1616 void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width)
1617 {
1618 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */
1619 TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL);
1620 TCGv_i64 zero = tcg_constant_i64(0);
1621 tcg_gen_movcond_i64(TCG_COND_GTU, tmp, source, max_val, max_val, source);
1622 tcg_gen_movcond_i64(TCG_COND_LT, tmp, source, zero, zero, tmp);
1623 tcg_gen_mov_i64(dest, tmp);
1624 }
1625
1626 void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
1627 {
1628 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */
1629 TCGv_i64 ovfl_64;
1630 gen_satu_i64(tmp, source, width);
1631 ovfl_64 = tcg_temp_new_i64();
1632 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source);
1633 tcg_gen_mov_i64(dest, tmp);
1634 tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
1635 }
1636
1637 /* Implements the fADDSAT64 macro in TCG */
1638 void gen_add_sat_i64(DisasContext *ctx, TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b)
1639 {
1640 TCGv_i64 sum = tcg_temp_new_i64();
1641 TCGv_i64 xor = tcg_temp_new_i64();
1642 TCGv_i64 cond1 = tcg_temp_new_i64();
1643 TCGv_i64 cond2 = tcg_temp_new_i64();
1644 TCGv_i64 cond3 = tcg_temp_new_i64();
1645 TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
1646 TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
1647 TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
1648 TCGv_i64 zero = tcg_constant_i64(0);
1649 TCGLabel *no_ovfl_label = gen_new_label();
1650 TCGLabel *ovfl_label = gen_new_label();
1651 TCGLabel *ret_label = gen_new_label();
1652
1653 tcg_gen_add_i64(sum, a, b);
1654 tcg_gen_xor_i64(xor, a, b);
1655
1656 /* if (xor & mask) */
1657 tcg_gen_and_i64(cond1, xor, mask);
1658 tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
1659
1660 /* else if ((a ^ sum) & mask) */
1661 tcg_gen_xor_i64(cond2, a, sum);
1662 tcg_gen_and_i64(cond2, cond2, mask);
1663 tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
1664 /* fallthrough to no_ovfl_label branch */
1665
1666 /* if branch */
1667 gen_set_label(no_ovfl_label);
1668 tcg_gen_mov_i64(ret, sum);
1669 tcg_gen_br(ret_label);
1670
1671 /* else if branch */
1672 gen_set_label(ovfl_label);
1673 tcg_gen_and_i64(cond3, sum, mask);
1674 tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg);
1675 gen_set_usr_fieldi(ctx, USR_OVF, 1);
1676
1677 gen_set_label(ret_label);
1678 }
1679
1680 #include "tcg_funcs_generated.c.inc"
1681 const SemanticInsn opcode_genptr[XX_LAST_OPCODE] = {
1682 #define OPCODE(X) [X] = generate_##X
1683 #include "opcodes_def_generated.h.inc"
1684 #undef OPCODE
1685 };