]> git.proxmox.com Git - mirror_qemu.git/blob - target/hexagon/genptr.c
Merge tag 'pull-misc-20221218' of https://gitlab.com/rth7680/qemu into staging
[mirror_qemu.git] / target / hexagon / genptr.c
1 /*
2 * Copyright(c) 2019-2022 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 "insn.h"
24 #include "opcodes.h"
25 #include "translate.h"
26 #define QEMU_GENERATE /* Used internally by macros.h */
27 #include "macros.h"
28 #include "mmvec/macros.h"
29 #undef QEMU_GENERATE
30 #include "gen_tcg.h"
31 #include "gen_tcg_hvx.h"
32 #include "genptr.h"
33
34 TCGv gen_read_reg(TCGv result, int num)
35 {
36 tcg_gen_mov_tl(result, hex_gpr[num]);
37 return result;
38 }
39
40 TCGv gen_read_preg(TCGv pred, uint8_t num)
41 {
42 tcg_gen_mov_tl(pred, hex_pred[num]);
43 return pred;
44 }
45
46 static inline void gen_log_predicated_reg_write(int rnum, TCGv val,
47 uint32_t slot)
48 {
49 TCGv zero = tcg_constant_tl(0);
50 TCGv slot_mask = tcg_temp_new();
51
52 tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot);
53 tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero,
54 val, hex_new_value[rnum]);
55 if (HEX_DEBUG) {
56 /*
57 * Do this so HELPER(debug_commit_end) will know
58 *
59 * Note that slot_mask indicates the value is not written
60 * (i.e., slot was cancelled), so we create a true/false value before
61 * or'ing with hex_reg_written[rnum].
62 */
63 tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero);
64 tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask);
65 }
66
67 tcg_temp_free(slot_mask);
68 }
69
70 void gen_log_reg_write(int rnum, TCGv val)
71 {
72 tcg_gen_mov_tl(hex_new_value[rnum], val);
73 if (HEX_DEBUG) {
74 /* Do this so HELPER(debug_commit_end) will know */
75 tcg_gen_movi_tl(hex_reg_written[rnum], 1);
76 }
77 }
78
79 static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val,
80 uint32_t slot)
81 {
82 TCGv val32 = tcg_temp_new();
83 TCGv zero = tcg_constant_tl(0);
84 TCGv slot_mask = tcg_temp_new();
85
86 tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot);
87 /* Low word */
88 tcg_gen_extrl_i64_i32(val32, val);
89 tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum],
90 slot_mask, zero,
91 val32, hex_new_value[rnum]);
92 /* High word */
93 tcg_gen_extrh_i64_i32(val32, val);
94 tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum + 1],
95 slot_mask, zero,
96 val32, hex_new_value[rnum + 1]);
97 if (HEX_DEBUG) {
98 /*
99 * Do this so HELPER(debug_commit_end) will know
100 *
101 * Note that slot_mask indicates the value is not written
102 * (i.e., slot was cancelled), so we create a true/false value before
103 * or'ing with hex_reg_written[rnum].
104 */
105 tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero);
106 tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask);
107 tcg_gen_or_tl(hex_reg_written[rnum + 1], hex_reg_written[rnum + 1],
108 slot_mask);
109 }
110
111 tcg_temp_free(val32);
112 tcg_temp_free(slot_mask);
113 }
114
115 static void gen_log_reg_write_pair(int rnum, TCGv_i64 val)
116 {
117 /* Low word */
118 tcg_gen_extrl_i64_i32(hex_new_value[rnum], val);
119 if (HEX_DEBUG) {
120 /* Do this so HELPER(debug_commit_end) will know */
121 tcg_gen_movi_tl(hex_reg_written[rnum], 1);
122 }
123
124 /* High word */
125 tcg_gen_extrh_i64_i32(hex_new_value[rnum + 1], val);
126 if (HEX_DEBUG) {
127 /* Do this so HELPER(debug_commit_end) will know */
128 tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1);
129 }
130 }
131
132 void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
133 {
134 TCGv base_val = tcg_temp_new();
135
136 tcg_gen_andi_tl(base_val, val, 0xff);
137
138 /*
139 * Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual
140 *
141 * Multiple writes to the same preg are and'ed together
142 * If this is the first predicate write in the packet, do a
143 * straight assignment. Otherwise, do an and.
144 */
145 if (!test_bit(pnum, ctx->pregs_written)) {
146 tcg_gen_mov_tl(hex_new_pred_value[pnum], base_val);
147 } else {
148 tcg_gen_and_tl(hex_new_pred_value[pnum],
149 hex_new_pred_value[pnum], base_val);
150 }
151 tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pnum);
152
153 tcg_temp_free(base_val);
154 }
155
156 static inline void gen_read_p3_0(TCGv control_reg)
157 {
158 tcg_gen_movi_tl(control_reg, 0);
159 for (int i = 0; i < NUM_PREGS; i++) {
160 tcg_gen_deposit_tl(control_reg, control_reg, hex_pred[i], i * 8, 8);
161 }
162 }
163
164 /*
165 * Certain control registers require special handling on read
166 * HEX_REG_P3_0 aliased to the predicate registers
167 * -> concat the 4 predicate registers together
168 * HEX_REG_PC actual value stored in DisasContext
169 * -> assign from ctx->base.pc_next
170 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext
171 * -> add current TB changes to existing reg value
172 */
173 static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num,
174 TCGv dest)
175 {
176 if (reg_num == HEX_REG_P3_0) {
177 gen_read_p3_0(dest);
178 } else if (reg_num == HEX_REG_PC) {
179 tcg_gen_movi_tl(dest, ctx->base.pc_next);
180 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
181 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_PKT_CNT],
182 ctx->num_packets);
183 } else if (reg_num == HEX_REG_QEMU_INSN_CNT) {
184 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_INSN_CNT],
185 ctx->num_insns);
186 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
187 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT],
188 ctx->num_hvx_insns);
189 } else {
190 tcg_gen_mov_tl(dest, hex_gpr[reg_num]);
191 }
192 }
193
194 static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num,
195 TCGv_i64 dest)
196 {
197 if (reg_num == HEX_REG_P3_0) {
198 TCGv p3_0 = tcg_temp_new();
199 gen_read_p3_0(p3_0);
200 tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]);
201 tcg_temp_free(p3_0);
202 } else if (reg_num == HEX_REG_PC - 1) {
203 TCGv pc = tcg_constant_tl(ctx->base.pc_next);
204 tcg_gen_concat_i32_i64(dest, hex_gpr[reg_num], pc);
205 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
206 TCGv pkt_cnt = tcg_temp_new();
207 TCGv insn_cnt = tcg_temp_new();
208 tcg_gen_addi_tl(pkt_cnt, hex_gpr[HEX_REG_QEMU_PKT_CNT],
209 ctx->num_packets);
210 tcg_gen_addi_tl(insn_cnt, hex_gpr[HEX_REG_QEMU_INSN_CNT],
211 ctx->num_insns);
212 tcg_gen_concat_i32_i64(dest, pkt_cnt, insn_cnt);
213 tcg_temp_free(pkt_cnt);
214 tcg_temp_free(insn_cnt);
215 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
216 TCGv hvx_cnt = tcg_temp_new();
217 tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT],
218 ctx->num_hvx_insns);
219 tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]);
220 tcg_temp_free(hvx_cnt);
221 } else {
222 tcg_gen_concat_i32_i64(dest,
223 hex_gpr[reg_num],
224 hex_gpr[reg_num + 1]);
225 }
226 }
227
228 static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg)
229 {
230 TCGv hex_p8 = tcg_temp_new();
231 for (int i = 0; i < NUM_PREGS; i++) {
232 tcg_gen_extract_tl(hex_p8, control_reg, i * 8, 8);
233 gen_log_pred_write(ctx, i, hex_p8);
234 ctx_log_pred_write(ctx, i);
235 }
236 tcg_temp_free(hex_p8);
237 }
238
239 /*
240 * Certain control registers require special handling on write
241 * HEX_REG_P3_0 aliased to the predicate registers
242 * -> break the value across 4 predicate registers
243 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext
244 * -> clear the changes
245 */
246 static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
247 TCGv val)
248 {
249 if (reg_num == HEX_REG_P3_0) {
250 gen_write_p3_0(ctx, val);
251 } else {
252 gen_log_reg_write(reg_num, val);
253 ctx_log_reg_write(ctx, reg_num);
254 if (reg_num == HEX_REG_QEMU_PKT_CNT) {
255 ctx->num_packets = 0;
256 }
257 if (reg_num == HEX_REG_QEMU_INSN_CNT) {
258 ctx->num_insns = 0;
259 }
260 if (reg_num == HEX_REG_QEMU_HVX_CNT) {
261 ctx->num_hvx_insns = 0;
262 }
263 }
264 }
265
266 static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
267 TCGv_i64 val)
268 {
269 if (reg_num == HEX_REG_P3_0) {
270 TCGv val32 = tcg_temp_new();
271 tcg_gen_extrl_i64_i32(val32, val);
272 gen_write_p3_0(ctx, val32);
273 tcg_gen_extrh_i64_i32(val32, val);
274 gen_log_reg_write(reg_num + 1, val32);
275 tcg_temp_free(val32);
276 ctx_log_reg_write(ctx, reg_num + 1);
277 } else {
278 gen_log_reg_write_pair(reg_num, val);
279 ctx_log_reg_write_pair(ctx, reg_num);
280 if (reg_num == HEX_REG_QEMU_PKT_CNT) {
281 ctx->num_packets = 0;
282 ctx->num_insns = 0;
283 }
284 if (reg_num == HEX_REG_QEMU_HVX_CNT) {
285 ctx->num_hvx_insns = 0;
286 }
287 }
288 }
289
290 TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
291 {
292 if (sign) {
293 tcg_gen_sextract_tl(result, src, N * 8, 8);
294 } else {
295 tcg_gen_extract_tl(result, src, N * 8, 8);
296 }
297 return result;
298 }
299
300 TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
301 {
302 TCGv_i64 res64 = tcg_temp_new_i64();
303 if (sign) {
304 tcg_gen_sextract_i64(res64, src, N * 8, 8);
305 } else {
306 tcg_gen_extract_i64(res64, src, N * 8, 8);
307 }
308 tcg_gen_extrl_i64_i32(result, res64);
309 tcg_temp_free_i64(res64);
310
311 return result;
312 }
313
314 TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
315 {
316 if (sign) {
317 tcg_gen_sextract_tl(result, src, N * 16, 16);
318 } else {
319 tcg_gen_extract_tl(result, src, N * 16, 16);
320 }
321 return result;
322 }
323
324 void gen_set_half(int N, TCGv result, TCGv src)
325 {
326 tcg_gen_deposit_tl(result, result, src, N * 16, 16);
327 }
328
329 void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
330 {
331 TCGv_i64 src64 = tcg_temp_new_i64();
332 tcg_gen_extu_i32_i64(src64, src);
333 tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
334 tcg_temp_free_i64(src64);
335 }
336
337 void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
338 {
339 TCGv_i64 src64 = tcg_temp_new_i64();
340 tcg_gen_extu_i32_i64(src64, src);
341 tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
342 tcg_temp_free_i64(src64);
343 }
344
345 static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
346 {
347 tcg_gen_qemu_ld32u(dest, vaddr, mem_index);
348 tcg_gen_mov_tl(hex_llsc_addr, vaddr);
349 tcg_gen_mov_tl(hex_llsc_val, dest);
350 }
351
352 static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index)
353 {
354 tcg_gen_qemu_ld64(dest, vaddr, mem_index);
355 tcg_gen_mov_tl(hex_llsc_addr, vaddr);
356 tcg_gen_mov_i64(hex_llsc_val_i64, dest);
357 }
358
359 static inline void gen_store_conditional4(DisasContext *ctx,
360 TCGv pred, TCGv vaddr, TCGv src)
361 {
362 TCGLabel *fail = gen_new_label();
363 TCGLabel *done = gen_new_label();
364 TCGv one, zero, tmp;
365
366 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
367
368 one = tcg_constant_tl(0xff);
369 zero = tcg_constant_tl(0);
370 tmp = tcg_temp_new();
371 tcg_gen_atomic_cmpxchg_tl(tmp, hex_llsc_addr, hex_llsc_val, src,
372 ctx->mem_idx, MO_32);
373 tcg_gen_movcond_tl(TCG_COND_EQ, pred, tmp, hex_llsc_val,
374 one, zero);
375 tcg_temp_free(tmp);
376 tcg_gen_br(done);
377
378 gen_set_label(fail);
379 tcg_gen_movi_tl(pred, 0);
380
381 gen_set_label(done);
382 tcg_gen_movi_tl(hex_llsc_addr, ~0);
383 }
384
385 static inline void gen_store_conditional8(DisasContext *ctx,
386 TCGv pred, TCGv vaddr, TCGv_i64 src)
387 {
388 TCGLabel *fail = gen_new_label();
389 TCGLabel *done = gen_new_label();
390 TCGv_i64 one, zero, tmp;
391
392 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
393
394 one = tcg_constant_i64(0xff);
395 zero = tcg_constant_i64(0);
396 tmp = tcg_temp_new_i64();
397 tcg_gen_atomic_cmpxchg_i64(tmp, hex_llsc_addr, hex_llsc_val_i64, src,
398 ctx->mem_idx, MO_64);
399 tcg_gen_movcond_i64(TCG_COND_EQ, tmp, tmp, hex_llsc_val_i64,
400 one, zero);
401 tcg_gen_extrl_i64_i32(pred, tmp);
402 tcg_temp_free_i64(tmp);
403 tcg_gen_br(done);
404
405 gen_set_label(fail);
406 tcg_gen_movi_tl(pred, 0);
407
408 gen_set_label(done);
409 tcg_gen_movi_tl(hex_llsc_addr, ~0);
410 }
411
412 void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
413 {
414 tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
415 tcg_gen_movi_tl(hex_store_width[slot], width);
416 tcg_gen_mov_tl(hex_store_val32[slot], src);
417 }
418
419 void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot)
420 {
421 gen_store32(vaddr, src, 1, slot);
422 }
423
424 void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot)
425 {
426 TCGv tmp = tcg_constant_tl(src);
427 gen_store1(cpu_env, vaddr, tmp, slot);
428 }
429
430 void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot)
431 {
432 gen_store32(vaddr, src, 2, slot);
433 }
434
435 void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot)
436 {
437 TCGv tmp = tcg_constant_tl(src);
438 gen_store2(cpu_env, vaddr, tmp, slot);
439 }
440
441 void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot)
442 {
443 gen_store32(vaddr, src, 4, slot);
444 }
445
446 void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot)
447 {
448 TCGv tmp = tcg_constant_tl(src);
449 gen_store4(cpu_env, vaddr, tmp, slot);
450 }
451
452 void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, uint32_t slot)
453 {
454 tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
455 tcg_gen_movi_tl(hex_store_width[slot], 8);
456 tcg_gen_mov_i64(hex_store_val64[slot], src);
457 }
458
459 void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot)
460 {
461 TCGv_i64 tmp = tcg_constant_i64(src);
462 gen_store8(cpu_env, vaddr, tmp, slot);
463 }
464
465 TCGv gen_8bitsof(TCGv result, TCGv value)
466 {
467 TCGv zero = tcg_constant_tl(0);
468 TCGv ones = tcg_constant_tl(0xff);
469 tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
470
471 return result;
472 }
473
474 static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr,
475 TCGCond cond, TCGv pred)
476 {
477 TCGLabel *pred_false = NULL;
478 if (cond != TCG_COND_ALWAYS) {
479 pred_false = gen_new_label();
480 tcg_gen_brcondi_tl(cond, pred, 0, pred_false);
481 }
482
483 if (ctx->pkt->pkt_has_multi_cof) {
484 /* If there are multiple branches in a packet, ignore the second one */
485 tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC],
486 hex_branch_taken, tcg_constant_tl(0),
487 hex_gpr[HEX_REG_PC], addr);
488 tcg_gen_movi_tl(hex_branch_taken, 1);
489 } else {
490 tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr);
491 }
492
493 if (cond != TCG_COND_ALWAYS) {
494 gen_set_label(pred_false);
495 }
496 }
497
498 static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off,
499 TCGCond cond, TCGv pred)
500 {
501 target_ulong dest = ctx->pkt->pc + pc_off;
502 if (ctx->pkt->pkt_has_multi_cof) {
503 gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred);
504 } else {
505 /* Defer this jump to the end of the TB */
506 ctx->branch_cond = TCG_COND_ALWAYS;
507 if (pred != NULL) {
508 ctx->branch_cond = cond;
509 tcg_gen_mov_tl(hex_branch_taken, pred);
510 }
511 ctx->branch_dest = dest;
512 }
513 }
514
515 void gen_set_usr_field(int field, TCGv val)
516 {
517 tcg_gen_deposit_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR],
518 val,
519 reg_field_info[field].offset,
520 reg_field_info[field].width);
521 }
522
523 void gen_set_usr_fieldi(int field, int x)
524 {
525 if (reg_field_info[field].width == 1) {
526 target_ulong bit = 1 << reg_field_info[field].offset;
527 if ((x & 1) == 1) {
528 tcg_gen_ori_tl(hex_new_value[HEX_REG_USR],
529 hex_new_value[HEX_REG_USR],
530 bit);
531 } else {
532 tcg_gen_andi_tl(hex_new_value[HEX_REG_USR],
533 hex_new_value[HEX_REG_USR],
534 ~bit);
535 }
536 } else {
537 TCGv val = tcg_constant_tl(x);
538 gen_set_usr_field(field, val);
539 }
540 }
541
542 static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2)
543 {
544 TCGv one = tcg_constant_tl(0xff);
545 TCGv zero = tcg_constant_tl(0);
546
547 tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero);
548 }
549
550 static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc,
551 TCGCond cond, TCGv pred)
552 {
553 gen_write_new_pc_addr(ctx, dst_pc, cond, pred);
554 }
555
556 static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred,
557 int pc_off)
558 {
559 gen_write_new_pc_pcrel(ctx, pc_off, cond, pred);
560 }
561
562 static void gen_cmpnd_cmp_jmp(DisasContext *ctx,
563 int pnum, TCGCond cond1, TCGv arg1, TCGv arg2,
564 TCGCond cond2, int pc_off)
565 {
566 if (ctx->insn->part1) {
567 TCGv pred = tcg_temp_new();
568 gen_compare(cond1, pred, arg1, arg2);
569 gen_log_pred_write(ctx, pnum, pred);
570 tcg_temp_free(pred);
571 } else {
572 TCGv pred = tcg_temp_new();
573 tcg_gen_mov_tl(pred, hex_new_pred_value[pnum]);
574 gen_cond_jump(ctx, cond2, pred, pc_off);
575 tcg_temp_free(pred);
576 }
577 }
578
579 static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx,
580 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
581 int pc_off)
582 {
583 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off);
584 }
585
586 static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx,
587 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
588 int pc_off)
589 {
590 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off);
591 }
592
593 static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx,
594 int pnum, TCGCond cond, TCGv arg1, int arg2,
595 int pc_off)
596 {
597 TCGv tmp = tcg_constant_tl(arg2);
598 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off);
599 }
600
601 static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx,
602 int pnum, TCGCond cond, TCGv arg1, int arg2,
603 int pc_off)
604 {
605 TCGv tmp = tcg_constant_tl(arg2);
606 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off);
607 }
608
609 static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond,
610 TCGv arg, int pc_off)
611 {
612 gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off);
613 }
614
615 static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond,
616 TCGv arg, int pc_off)
617 {
618 gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off);
619 }
620
621 static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx,
622 int pnum, TCGv arg, TCGCond cond, int pc_off)
623 {
624 if (ctx->insn->part1) {
625 TCGv pred = tcg_temp_new();
626 tcg_gen_andi_tl(pred, arg, 1);
627 gen_8bitsof(pred, pred);
628 gen_log_pred_write(ctx, pnum, pred);
629 tcg_temp_free(pred);
630 } else {
631 TCGv pred = tcg_temp_new();
632 tcg_gen_mov_tl(pred, hex_new_pred_value[pnum]);
633 gen_cond_jump(ctx, cond, pred, pc_off);
634 tcg_temp_free(pred);
635 }
636 }
637
638 static void gen_testbit0_jumpnv(DisasContext *ctx,
639 TCGv arg, TCGCond cond, int pc_off)
640 {
641 TCGv pred = tcg_temp_new();
642 tcg_gen_andi_tl(pred, arg, 1);
643 gen_cond_jump(ctx, cond, pred, pc_off);
644 tcg_temp_free(pred);
645 }
646
647 static void gen_jump(DisasContext *ctx, int pc_off)
648 {
649 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL);
650 }
651
652 static void gen_jumpr(DisasContext *ctx, TCGv new_pc)
653 {
654 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL);
655 }
656
657 static void gen_call(DisasContext *ctx, int pc_off)
658 {
659 TCGv next_PC =
660 tcg_constant_tl(ctx->pkt->pc + ctx->pkt->encod_pkt_size_in_bytes);
661 gen_log_reg_write(HEX_REG_LR, next_PC);
662 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL);
663 }
664
665 static void gen_cond_call(DisasContext *ctx, TCGv pred,
666 TCGCond cond, int pc_off)
667 {
668 TCGv next_PC;
669 TCGv lsb = tcg_temp_local_new();
670 TCGLabel *skip = gen_new_label();
671 tcg_gen_andi_tl(lsb, pred, 1);
672 gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb);
673 tcg_gen_brcondi_tl(cond, lsb, 0, skip);
674 tcg_temp_free(lsb);
675 next_PC =
676 tcg_constant_tl(ctx->pkt->pc + ctx->pkt->encod_pkt_size_in_bytes);
677 gen_log_reg_write(HEX_REG_LR, next_PC);
678 gen_set_label(skip);
679 }
680
681 static void gen_endloop0(DisasContext *ctx)
682 {
683 TCGv lpcfg = tcg_temp_local_new();
684
685 GET_USR_FIELD(USR_LPCFG, lpcfg);
686
687 /*
688 * if (lpcfg == 1) {
689 * hex_new_pred_value[3] = 0xff;
690 * hex_pred_written |= 1 << 3;
691 * }
692 */
693 TCGLabel *label1 = gen_new_label();
694 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
695 {
696 tcg_gen_movi_tl(hex_new_pred_value[3], 0xff);
697 tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << 3);
698 }
699 gen_set_label(label1);
700
701 /*
702 * if (lpcfg) {
703 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
704 * }
705 */
706 TCGLabel *label2 = gen_new_label();
707 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
708 {
709 tcg_gen_subi_tl(lpcfg, lpcfg, 1);
710 SET_USR_FIELD(USR_LPCFG, lpcfg);
711 }
712 gen_set_label(label2);
713
714 /*
715 * If we're in a tight loop, we'll do this at the end of the TB to take
716 * advantage of direct block chaining.
717 */
718 if (!ctx->is_tight_loop) {
719 /*
720 * if (hex_gpr[HEX_REG_LC0] > 1) {
721 * PC = hex_gpr[HEX_REG_SA0];
722 * hex_new_value[HEX_REG_LC0] = hex_gpr[HEX_REG_LC0] - 1;
723 * }
724 */
725 TCGLabel *label3 = gen_new_label();
726 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
727 {
728 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
729 tcg_gen_subi_tl(hex_new_value[HEX_REG_LC0],
730 hex_gpr[HEX_REG_LC0], 1);
731 }
732 gen_set_label(label3);
733 }
734
735 tcg_temp_free(lpcfg);
736 }
737
738 static void gen_cmp_jumpnv(DisasContext *ctx,
739 TCGCond cond, TCGv val, TCGv src, int pc_off)
740 {
741 TCGv pred = tcg_temp_new();
742 tcg_gen_setcond_tl(cond, pred, val, src);
743 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
744 tcg_temp_free(pred);
745 }
746
747 static void gen_cmpi_jumpnv(DisasContext *ctx,
748 TCGCond cond, TCGv val, int src, int pc_off)
749 {
750 TCGv pred = tcg_temp_new();
751 tcg_gen_setcondi_tl(cond, pred, val, src);
752 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
753 tcg_temp_free(pred);
754 }
755
756 /* Shift left with saturation */
757 static void gen_shl_sat(TCGv dst, TCGv src, TCGv shift_amt)
758 {
759 TCGv sh32 = tcg_temp_new();
760 TCGv dst_sar = tcg_temp_new();
761 TCGv ovf = tcg_temp_new();
762 TCGv satval = tcg_temp_new();
763 TCGv min = tcg_constant_tl(0x80000000);
764 TCGv max = tcg_constant_tl(0x7fffffff);
765
766 /*
767 * Possible values for shift_amt are 0 .. 64
768 * We need special handling for values above 31
769 *
770 * sh32 = shift & 31;
771 * dst = sh32 == shift ? src : 0;
772 * dst <<= sh32;
773 * dst_sar = dst >> sh32;
774 * satval = src < 0 ? min : max;
775 * if (dst_asr != src) {
776 * usr.OVF |= 1;
777 * dst = satval;
778 * }
779 */
780
781 tcg_gen_andi_tl(sh32, shift_amt, 31);
782 tcg_gen_movcond_tl(TCG_COND_EQ, dst, sh32, shift_amt,
783 src, tcg_constant_tl(0));
784 tcg_gen_shl_tl(dst, dst, sh32);
785 tcg_gen_sar_tl(dst_sar, dst, sh32);
786 tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max);
787
788 tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src);
789 tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset);
790 tcg_gen_or_tl(hex_new_value[HEX_REG_USR], hex_new_value[HEX_REG_USR], ovf);
791
792 tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, dst, satval);
793
794 tcg_temp_free(sh32);
795 tcg_temp_free(dst_sar);
796 tcg_temp_free(ovf);
797 tcg_temp_free(satval);
798 }
799
800 static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt)
801 {
802 /*
803 * Shift arithmetic right
804 * Robust when shift_amt is >31 bits
805 */
806 TCGv tmp = tcg_temp_new();
807 tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31));
808 tcg_gen_sar_tl(dst, src, tmp);
809 tcg_temp_free(tmp);
810 }
811
812 /* Bidirectional shift right with saturation */
813 static void gen_asr_r_r_sat(TCGv RdV, TCGv RsV, TCGv RtV)
814 {
815 TCGv shift_amt = tcg_temp_local_new();
816 TCGLabel *positive = gen_new_label();
817 TCGLabel *done = gen_new_label();
818
819 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
820 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
821
822 /* Negative shift amount => shift left */
823 tcg_gen_neg_tl(shift_amt, shift_amt);
824 gen_shl_sat(RdV, RsV, shift_amt);
825 tcg_gen_br(done);
826
827 gen_set_label(positive);
828 /* Positive shift amount => shift right */
829 gen_sar(RdV, RsV, shift_amt);
830
831 gen_set_label(done);
832
833 tcg_temp_free(shift_amt);
834 }
835
836 /* Bidirectional shift left with saturation */
837 static void gen_asl_r_r_sat(TCGv RdV, TCGv RsV, TCGv RtV)
838 {
839 TCGv shift_amt = tcg_temp_local_new();
840 TCGLabel *positive = gen_new_label();
841 TCGLabel *done = gen_new_label();
842
843 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
844 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
845
846 /* Negative shift amount => shift right */
847 tcg_gen_neg_tl(shift_amt, shift_amt);
848 gen_sar(RdV, RsV, shift_amt);
849 tcg_gen_br(done);
850
851 gen_set_label(positive);
852 /* Positive shift amount => shift left */
853 gen_shl_sat(RdV, RsV, shift_amt);
854
855 gen_set_label(done);
856
857 tcg_temp_free(shift_amt);
858 }
859
860 static intptr_t vreg_src_off(DisasContext *ctx, int num)
861 {
862 intptr_t offset = offsetof(CPUHexagonState, VRegs[num]);
863
864 if (test_bit(num, ctx->vregs_select)) {
865 offset = ctx_future_vreg_off(ctx, num, 1, false);
866 }
867 if (test_bit(num, ctx->vregs_updated_tmp)) {
868 offset = ctx_tmp_vreg_off(ctx, num, 1, false);
869 }
870 return offset;
871 }
872
873 static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num,
874 VRegWriteType type, int slot_num,
875 bool is_predicated)
876 {
877 TCGLabel *label_end = NULL;
878 intptr_t dstoff;
879
880 if (is_predicated) {
881 TCGv cancelled = tcg_temp_local_new();
882 label_end = gen_new_label();
883
884 /* Don't do anything if the slot was cancelled */
885 tcg_gen_extract_tl(cancelled, hex_slot_cancelled, slot_num, 1);
886 tcg_gen_brcondi_tl(TCG_COND_NE, cancelled, 0, label_end);
887 tcg_temp_free(cancelled);
888 }
889
890 if (type != EXT_TMP) {
891 dstoff = ctx_future_vreg_off(ctx, num, 1, true);
892 tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
893 sizeof(MMVector), sizeof(MMVector));
894 tcg_gen_ori_tl(hex_VRegs_updated, hex_VRegs_updated, 1 << num);
895 } else {
896 dstoff = ctx_tmp_vreg_off(ctx, num, 1, false);
897 tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
898 sizeof(MMVector), sizeof(MMVector));
899 }
900
901 if (is_predicated) {
902 gen_set_label(label_end);
903 }
904 }
905
906 static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num,
907 VRegWriteType type, int slot_num,
908 bool is_predicated)
909 {
910 gen_log_vreg_write(ctx, srcoff, num ^ 0, type, slot_num, is_predicated);
911 srcoff += sizeof(MMVector);
912 gen_log_vreg_write(ctx, srcoff, num ^ 1, type, slot_num, is_predicated);
913 }
914
915 static void gen_log_qreg_write(intptr_t srcoff, int num, int vnew,
916 int slot_num, bool is_predicated)
917 {
918 TCGLabel *label_end = NULL;
919 intptr_t dstoff;
920
921 if (is_predicated) {
922 TCGv cancelled = tcg_temp_local_new();
923 label_end = gen_new_label();
924
925 /* Don't do anything if the slot was cancelled */
926 tcg_gen_extract_tl(cancelled, hex_slot_cancelled, slot_num, 1);
927 tcg_gen_brcondi_tl(TCG_COND_NE, cancelled, 0, label_end);
928 tcg_temp_free(cancelled);
929 }
930
931 dstoff = offsetof(CPUHexagonState, future_QRegs[num]);
932 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMQReg), sizeof(MMQReg));
933
934 if (is_predicated) {
935 tcg_gen_ori_tl(hex_QRegs_updated, hex_QRegs_updated, 1 << num);
936 gen_set_label(label_end);
937 }
938 }
939
940 static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src,
941 bool aligned)
942 {
943 TCGv_i64 tmp = tcg_temp_new_i64();
944 if (aligned) {
945 tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1));
946 }
947 for (int i = 0; i < sizeof(MMVector) / 8; i++) {
948 tcg_gen_qemu_ld64(tmp, src, ctx->mem_idx);
949 tcg_gen_addi_tl(src, src, 8);
950 tcg_gen_st_i64(tmp, cpu_env, dstoff + i * 8);
951 }
952 tcg_temp_free_i64(tmp);
953 }
954
955 static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
956 int slot, bool aligned)
957 {
958 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
959 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
960
961 if (is_gather_store_insn(ctx)) {
962 TCGv sl = tcg_constant_tl(slot);
963 gen_helper_gather_store(cpu_env, EA, sl);
964 return;
965 }
966
967 tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
968 if (aligned) {
969 tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
970 ~((int32_t)sizeof(MMVector) - 1));
971 } else {
972 tcg_gen_mov_tl(hex_vstore_addr[slot], EA);
973 }
974 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
975
976 /* Copy the data to the vstore buffer */
977 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
978 /* Set the mask to all 1's */
979 tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL);
980 }
981
982 static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
983 intptr_t bitsoff, int slot, bool invert)
984 {
985 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
986 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
987
988 tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
989 tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
990 ~((int32_t)sizeof(MMVector) - 1));
991 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
992
993 /* Copy the data to the vstore buffer */
994 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
995 /* Copy the mask */
996 tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg));
997 if (invert) {
998 tcg_gen_gvec_not(MO_64, maskoff, maskoff,
999 sizeof(MMQReg), sizeof(MMQReg));
1000 }
1001 }
1002
1003 static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff)
1004 {
1005 TCGv_i64 tmp = tcg_temp_new_i64();
1006 TCGv_i64 word = tcg_temp_new_i64();
1007 TCGv_i64 bits = tcg_temp_new_i64();
1008 TCGv_i64 mask = tcg_temp_new_i64();
1009 TCGv_i64 zero = tcg_constant_i64(0);
1010 TCGv_i64 ones = tcg_constant_i64(~0);
1011
1012 for (int i = 0; i < sizeof(MMVector) / 8; i++) {
1013 tcg_gen_ld_i64(tmp, cpu_env, srcoff + i * 8);
1014 tcg_gen_movi_i64(mask, 0);
1015
1016 for (int j = 0; j < 8; j += size) {
1017 tcg_gen_extract_i64(word, tmp, j * 8, size * 8);
1018 tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero);
1019 tcg_gen_deposit_i64(mask, mask, bits, j, size);
1020 }
1021
1022 tcg_gen_st8_i64(mask, cpu_env, dstoff + i);
1023 }
1024 tcg_temp_free_i64(tmp);
1025 tcg_temp_free_i64(word);
1026 tcg_temp_free_i64(bits);
1027 tcg_temp_free_i64(mask);
1028 }
1029
1030 void probe_noshuf_load(TCGv va, int s, int mi)
1031 {
1032 TCGv size = tcg_constant_tl(s);
1033 TCGv mem_idx = tcg_constant_tl(mi);
1034 gen_helper_probe_noshuf_load(cpu_env, va, size, mem_idx);
1035 }
1036
1037 /*
1038 * Note: Since this function might branch, `val` is
1039 * required to be a `tcg_temp_local`.
1040 */
1041 void gen_set_usr_field_if(int field, TCGv val)
1042 {
1043 /* Sets the USR field if `val` is non-zero */
1044 if (reg_field_info[field].width == 1) {
1045 TCGv tmp = tcg_temp_new();
1046 tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
1047 tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
1048 tcg_gen_or_tl(hex_new_value[HEX_REG_USR],
1049 hex_new_value[HEX_REG_USR],
1050 tmp);
1051 tcg_temp_free(tmp);
1052 } else {
1053 TCGLabel *skip_label = gen_new_label();
1054 tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
1055 gen_set_usr_field(field, val);
1056 gen_set_label(skip_label);
1057 }
1058 }
1059
1060 void gen_sat_i32(TCGv dest, TCGv source, int width)
1061 {
1062 TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1);
1063 TCGv min_val = tcg_constant_tl(-(1 << (width - 1)));
1064 tcg_gen_smin_tl(dest, source, max_val);
1065 tcg_gen_smax_tl(dest, dest, min_val);
1066 }
1067
1068 void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
1069 {
1070 gen_sat_i32(dest, source, width);
1071 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest);
1072 }
1073
1074 void gen_satu_i32(TCGv dest, TCGv source, int width)
1075 {
1076 TCGv max_val = tcg_constant_tl((1 << width) - 1);
1077 TCGv zero = tcg_constant_tl(0);
1078 tcg_gen_movcond_tl(TCG_COND_GTU, dest, source, max_val, max_val, source);
1079 tcg_gen_movcond_tl(TCG_COND_LT, dest, source, zero, zero, dest);
1080 }
1081
1082 void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
1083 {
1084 gen_satu_i32(dest, source, width);
1085 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, dest);
1086 }
1087
1088 void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width)
1089 {
1090 TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL);
1091 TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1)));
1092 tcg_gen_smin_i64(dest, source, max_val);
1093 tcg_gen_smax_i64(dest, dest, min_val);
1094 }
1095
1096 void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
1097 {
1098 TCGv_i64 ovfl_64;
1099 gen_sat_i64(dest, source, width);
1100 ovfl_64 = tcg_temp_new_i64();
1101 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
1102 tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
1103 tcg_temp_free_i64(ovfl_64);
1104 }
1105
1106 void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width)
1107 {
1108 TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL);
1109 TCGv_i64 zero = tcg_constant_i64(0);
1110 tcg_gen_movcond_i64(TCG_COND_GTU, dest, source, max_val, max_val, source);
1111 tcg_gen_movcond_i64(TCG_COND_LT, dest, source, zero, zero, dest);
1112 }
1113
1114 void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
1115 {
1116 TCGv_i64 ovfl_64;
1117 gen_satu_i64(dest, source, width);
1118 ovfl_64 = tcg_temp_new_i64();
1119 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, dest, source);
1120 tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
1121 tcg_temp_free_i64(ovfl_64);
1122 }
1123
1124 /* Implements the fADDSAT64 macro in TCG */
1125 void gen_add_sat_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b)
1126 {
1127 TCGv_i64 sum = tcg_temp_local_new_i64();
1128 TCGv_i64 xor = tcg_temp_new_i64();
1129 TCGv_i64 cond1 = tcg_temp_new_i64();
1130 TCGv_i64 cond2 = tcg_temp_local_new_i64();
1131 TCGv_i64 cond3 = tcg_temp_new_i64();
1132 TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
1133 TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
1134 TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
1135 TCGv_i64 zero = tcg_constant_i64(0);
1136 TCGLabel *no_ovfl_label = gen_new_label();
1137 TCGLabel *ovfl_label = gen_new_label();
1138 TCGLabel *ret_label = gen_new_label();
1139
1140 tcg_gen_add_i64(sum, a, b);
1141 tcg_gen_xor_i64(xor, a, b);
1142
1143 /* if (xor & mask) */
1144 tcg_gen_and_i64(cond1, xor, mask);
1145 tcg_temp_free_i64(xor);
1146 tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
1147 tcg_temp_free_i64(cond1);
1148
1149 /* else if ((a ^ sum) & mask) */
1150 tcg_gen_xor_i64(cond2, a, sum);
1151 tcg_gen_and_i64(cond2, cond2, mask);
1152 tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
1153 tcg_temp_free_i64(cond2);
1154 /* fallthrough to no_ovfl_label branch */
1155
1156 /* if branch */
1157 gen_set_label(no_ovfl_label);
1158 tcg_gen_mov_i64(ret, sum);
1159 tcg_gen_br(ret_label);
1160
1161 /* else if branch */
1162 gen_set_label(ovfl_label);
1163 tcg_gen_and_i64(cond3, sum, mask);
1164 tcg_temp_free_i64(mask);
1165 tcg_temp_free_i64(sum);
1166 tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg);
1167 tcg_temp_free_i64(cond3);
1168 SET_USR_FIELD(USR_OVF, 1);
1169
1170 gen_set_label(ret_label);
1171 }
1172
1173 #include "tcg_funcs_generated.c.inc"
1174 #include "tcg_func_table_generated.c.inc"