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