xref: /openbmc/qemu/target/hexagon/genptr.c (revision c85ba2d7a4056595166689890285105579db446a)
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 "translate.h"
27 #define QEMU_GENERATE       /* Used internally by macros.h */
28 #include "macros.h"
29 #include "mmvec/macros.h"
30 #undef QEMU_GENERATE
31 #include "gen_tcg.h"
32 #include "gen_tcg_hvx.h"
33 #include "genptr.h"
34 
35 TCGv gen_read_reg(TCGv result, int num)
36 {
37     tcg_gen_mov_tl(result, hex_gpr[num]);
38     return result;
39 }
40 
41 TCGv gen_read_preg(TCGv pred, uint8_t num)
42 {
43     tcg_gen_mov_tl(pred, hex_pred[num]);
44     return pred;
45 }
46 
47 #define IMMUTABLE (~0)
48 
49 const target_ulong reg_immut_masks[TOTAL_PER_THREAD_REGS] = {
50     [HEX_REG_USR] = 0xc13000c0,
51     [HEX_REG_PC] = IMMUTABLE,
52     [HEX_REG_GP] = 0x3f,
53     [HEX_REG_UPCYCLELO] = IMMUTABLE,
54     [HEX_REG_UPCYCLEHI] = IMMUTABLE,
55     [HEX_REG_UTIMERLO] = IMMUTABLE,
56     [HEX_REG_UTIMERHI] = IMMUTABLE,
57 };
58 
59 static inline void gen_masked_reg_write(TCGv new_val, TCGv cur_val,
60                                         target_ulong reg_mask)
61 {
62     if (reg_mask) {
63         TCGv tmp = tcg_temp_new();
64 
65         /* new_val = (new_val & ~reg_mask) | (cur_val & reg_mask) */
66         tcg_gen_andi_tl(new_val, new_val, ~reg_mask);
67         tcg_gen_andi_tl(tmp, cur_val, reg_mask);
68         tcg_gen_or_tl(new_val, new_val, tmp);
69     }
70 }
71 
72 TCGv get_result_gpr(DisasContext *ctx, int rnum)
73 {
74     if (ctx->need_commit) {
75         if (rnum == HEX_REG_USR) {
76             return hex_new_value_usr;
77         } else {
78             if (ctx->new_value[rnum] == NULL) {
79                 ctx->new_value[rnum] = tcg_temp_new();
80                 tcg_gen_movi_tl(ctx->new_value[rnum], 0);
81             }
82             return ctx->new_value[rnum];
83         }
84     } else {
85         return hex_gpr[rnum];
86     }
87 }
88 
89 static TCGv_i64 get_result_gpr_pair(DisasContext *ctx, int rnum)
90 {
91     TCGv_i64 result = tcg_temp_new_i64();
92     tcg_gen_concat_i32_i64(result, get_result_gpr(ctx, rnum),
93                                    get_result_gpr(ctx, rnum + 1));
94     return result;
95 }
96 
97 void gen_log_reg_write(DisasContext *ctx, 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(get_result_gpr(ctx, rnum), val);
103 }
104 
105 static void gen_log_reg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
106 {
107     TCGv val32 = tcg_temp_new();
108 
109     /* Low word */
110     tcg_gen_extrl_i64_i32(val32, val);
111     gen_log_reg_write(ctx, rnum, val32);
112 
113     /* High word */
114     tcg_gen_extrh_i64_i32(val32, val);
115     gen_log_reg_write(ctx, rnum + 1, val32);
116 }
117 
118 TCGv get_result_pred(DisasContext *ctx, int pnum)
119 {
120     if (ctx->need_commit) {
121         if (ctx->new_pred_value[pnum] == NULL) {
122             ctx->new_pred_value[pnum] = tcg_temp_new();
123             tcg_gen_movi_tl(ctx->new_pred_value[pnum], 0);
124         }
125         return ctx->new_pred_value[pnum];
126     } else {
127         return hex_pred[pnum];
128     }
129 }
130 
131 void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
132 {
133     TCGv pred = get_result_pred(ctx, pnum);
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(pred, base_val);
147     } else {
148         tcg_gen_and_tl(pred, pred, base_val);
149     }
150     set_bit(pnum, ctx->pregs_written);
151 }
152 
153 static inline void gen_read_p3_0(TCGv control_reg)
154 {
155     tcg_gen_movi_tl(control_reg, 0);
156     for (int i = 0; i < NUM_PREGS; i++) {
157         tcg_gen_deposit_tl(control_reg, control_reg, hex_pred[i], i * 8, 8);
158     }
159 }
160 
161 /*
162  * Certain control registers require special handling on read
163  *     HEX_REG_P3_0_ALIASED  aliased to the predicate registers
164  *                           -> concat the 4 predicate registers together
165  *     HEX_REG_PC            actual value stored in DisasContext
166  *                           -> assign from ctx->base.pc_next
167  *     HEX_REG_QEMU_*_CNT    changes in current TB in DisasContext
168  *                           -> add current TB changes to existing reg value
169  */
170 static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num,
171                                      TCGv dest)
172 {
173     if (reg_num == HEX_REG_P3_0_ALIASED) {
174         gen_read_p3_0(dest);
175     } else if (reg_num == HEX_REG_PC) {
176         tcg_gen_movi_tl(dest, ctx->base.pc_next);
177     } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
178         tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_PKT_CNT],
179                         ctx->num_packets);
180     } else if (reg_num == HEX_REG_QEMU_INSN_CNT) {
181         tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_INSN_CNT],
182                         ctx->num_insns);
183     } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
184         tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT],
185                         ctx->num_hvx_insns);
186     } else {
187         tcg_gen_mov_tl(dest, hex_gpr[reg_num]);
188     }
189 }
190 
191 static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num,
192                                           TCGv_i64 dest)
193 {
194     if (reg_num == HEX_REG_P3_0_ALIASED) {
195         TCGv p3_0 = tcg_temp_new();
196         gen_read_p3_0(p3_0);
197         tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]);
198     } else if (reg_num == HEX_REG_PC - 1) {
199         TCGv pc = tcg_constant_tl(ctx->base.pc_next);
200         tcg_gen_concat_i32_i64(dest, hex_gpr[reg_num], pc);
201     } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
202         TCGv pkt_cnt = tcg_temp_new();
203         TCGv insn_cnt = tcg_temp_new();
204         tcg_gen_addi_tl(pkt_cnt, hex_gpr[HEX_REG_QEMU_PKT_CNT],
205                         ctx->num_packets);
206         tcg_gen_addi_tl(insn_cnt, hex_gpr[HEX_REG_QEMU_INSN_CNT],
207                         ctx->num_insns);
208         tcg_gen_concat_i32_i64(dest, pkt_cnt, insn_cnt);
209     } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
210         TCGv hvx_cnt = tcg_temp_new();
211         tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT],
212                         ctx->num_hvx_insns);
213         tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]);
214     } else {
215         tcg_gen_concat_i32_i64(dest,
216             hex_gpr[reg_num],
217             hex_gpr[reg_num + 1]);
218     }
219 }
220 
221 static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg)
222 {
223     TCGv hex_p8 = tcg_temp_new();
224     for (int i = 0; i < NUM_PREGS; i++) {
225         tcg_gen_extract_tl(hex_p8, control_reg, i * 8, 8);
226         gen_log_pred_write(ctx, i, hex_p8);
227     }
228 }
229 
230 /*
231  * Certain control registers require special handling on write
232  *     HEX_REG_P3_0_ALIASED  aliased to the predicate registers
233  *                           -> break the value across 4 predicate registers
234  *     HEX_REG_QEMU_*_CNT    changes in current TB in DisasContext
235  *                            -> clear the changes
236  */
237 static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
238                                       TCGv val)
239 {
240     if (reg_num == HEX_REG_P3_0_ALIASED) {
241         gen_write_p3_0(ctx, val);
242     } else {
243         gen_log_reg_write(ctx, reg_num, val);
244         if (reg_num == HEX_REG_QEMU_PKT_CNT) {
245             ctx->num_packets = 0;
246         }
247         if (reg_num == HEX_REG_QEMU_INSN_CNT) {
248             ctx->num_insns = 0;
249         }
250         if (reg_num == HEX_REG_QEMU_HVX_CNT) {
251             ctx->num_hvx_insns = 0;
252         }
253     }
254 }
255 
256 static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
257                                            TCGv_i64 val)
258 {
259     if (reg_num == HEX_REG_P3_0_ALIASED) {
260         TCGv result = get_result_gpr(ctx, reg_num + 1);
261         TCGv val32 = tcg_temp_new();
262         tcg_gen_extrl_i64_i32(val32, val);
263         gen_write_p3_0(ctx, val32);
264         tcg_gen_extrh_i64_i32(val32, val);
265         tcg_gen_mov_tl(result, val32);
266     } else {
267         gen_log_reg_write_pair(ctx, reg_num, val);
268         if (reg_num == HEX_REG_QEMU_PKT_CNT) {
269             ctx->num_packets = 0;
270             ctx->num_insns = 0;
271         }
272         if (reg_num == HEX_REG_QEMU_HVX_CNT) {
273             ctx->num_hvx_insns = 0;
274         }
275     }
276 }
277 
278 TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
279 {
280     if (sign) {
281         tcg_gen_sextract_tl(result, src, N * 8, 8);
282     } else {
283         tcg_gen_extract_tl(result, src, N * 8, 8);
284     }
285     return result;
286 }
287 
288 TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
289 {
290     TCGv_i64 res64 = tcg_temp_new_i64();
291     if (sign) {
292         tcg_gen_sextract_i64(res64, src, N * 8, 8);
293     } else {
294         tcg_gen_extract_i64(res64, src, N * 8, 8);
295     }
296     tcg_gen_extrl_i64_i32(result, res64);
297 
298     return result;
299 }
300 
301 TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
302 {
303     if (sign) {
304         tcg_gen_sextract_tl(result, src, N * 16, 16);
305     } else {
306         tcg_gen_extract_tl(result, src, N * 16, 16);
307     }
308     return result;
309 }
310 
311 void gen_set_half(int N, TCGv result, TCGv src)
312 {
313     tcg_gen_deposit_tl(result, result, src, N * 16, 16);
314 }
315 
316 void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
317 {
318     TCGv_i64 src64 = tcg_temp_new_i64();
319     tcg_gen_extu_i32_i64(src64, src);
320     tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
321 }
322 
323 void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
324 {
325     TCGv_i64 src64 = tcg_temp_new_i64();
326     tcg_gen_extu_i32_i64(src64, src);
327     tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
328 }
329 
330 static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
331 {
332     tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_LE | MO_UL);
333     tcg_gen_mov_tl(hex_llsc_addr, vaddr);
334     tcg_gen_mov_tl(hex_llsc_val, dest);
335 }
336 
337 static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index)
338 {
339     tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_LE | MO_UQ);
340     tcg_gen_mov_tl(hex_llsc_addr, vaddr);
341     tcg_gen_mov_i64(hex_llsc_val_i64, dest);
342 }
343 
344 static inline void gen_store_conditional4(DisasContext *ctx,
345                                           TCGv pred, TCGv vaddr, TCGv src)
346 {
347     TCGLabel *fail = gen_new_label();
348     TCGLabel *done = gen_new_label();
349     TCGv one, zero, tmp;
350 
351     tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
352 
353     one = tcg_constant_tl(0xff);
354     zero = tcg_constant_tl(0);
355     tmp = tcg_temp_new();
356     tcg_gen_atomic_cmpxchg_tl(tmp, hex_llsc_addr, hex_llsc_val, src,
357                               ctx->mem_idx, MO_32);
358     tcg_gen_movcond_tl(TCG_COND_EQ, pred, tmp, hex_llsc_val,
359                        one, zero);
360     tcg_gen_br(done);
361 
362     gen_set_label(fail);
363     tcg_gen_movi_tl(pred, 0);
364 
365     gen_set_label(done);
366     tcg_gen_movi_tl(hex_llsc_addr, ~0);
367 }
368 
369 static inline void gen_store_conditional8(DisasContext *ctx,
370                                           TCGv pred, TCGv vaddr, TCGv_i64 src)
371 {
372     TCGLabel *fail = gen_new_label();
373     TCGLabel *done = gen_new_label();
374     TCGv_i64 one, zero, tmp;
375 
376     tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
377 
378     one = tcg_constant_i64(0xff);
379     zero = tcg_constant_i64(0);
380     tmp = tcg_temp_new_i64();
381     tcg_gen_atomic_cmpxchg_i64(tmp, hex_llsc_addr, hex_llsc_val_i64, src,
382                                ctx->mem_idx, MO_64);
383     tcg_gen_movcond_i64(TCG_COND_EQ, tmp, tmp, hex_llsc_val_i64,
384                         one, zero);
385     tcg_gen_extrl_i64_i32(pred, tmp);
386     tcg_gen_br(done);
387 
388     gen_set_label(fail);
389     tcg_gen_movi_tl(pred, 0);
390 
391     gen_set_label(done);
392     tcg_gen_movi_tl(hex_llsc_addr, ~0);
393 }
394 
395 #ifndef CONFIG_HEXAGON_IDEF_PARSER
396 static TCGv gen_slotval(DisasContext *ctx)
397 {
398     int slotval =
399         (ctx->pkt->pkt_has_scalar_store_s1 & 1) | (ctx->insn->slot << 1);
400     return tcg_constant_tl(slotval);
401 }
402 #endif
403 
404 void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
405 {
406     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
407     tcg_gen_movi_tl(hex_store_width[slot], width);
408     tcg_gen_mov_tl(hex_store_val32[slot], src);
409 }
410 
411 void gen_store1(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot)
412 {
413     gen_store32(vaddr, src, 1, slot);
414 }
415 
416 void gen_store1i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot)
417 {
418     TCGv tmp = tcg_constant_tl(src);
419     gen_store1(tcg_env, vaddr, tmp, slot);
420 }
421 
422 void gen_store2(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot)
423 {
424     gen_store32(vaddr, src, 2, slot);
425 }
426 
427 void gen_store2i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot)
428 {
429     TCGv tmp = tcg_constant_tl(src);
430     gen_store2(tcg_env, vaddr, tmp, slot);
431 }
432 
433 void gen_store4(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot)
434 {
435     gen_store32(vaddr, src, 4, slot);
436 }
437 
438 void gen_store4i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot)
439 {
440     TCGv tmp = tcg_constant_tl(src);
441     gen_store4(tcg_env, vaddr, tmp, slot);
442 }
443 
444 void gen_store8(TCGv_env tcg_env, TCGv vaddr, TCGv_i64 src, uint32_t slot)
445 {
446     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
447     tcg_gen_movi_tl(hex_store_width[slot], 8);
448     tcg_gen_mov_i64(hex_store_val64[slot], src);
449 }
450 
451 void gen_store8i(TCGv_env tcg_env, TCGv vaddr, int64_t src, uint32_t slot)
452 {
453     TCGv_i64 tmp = tcg_constant_i64(src);
454     gen_store8(tcg_env, vaddr, tmp, slot);
455 }
456 
457 TCGv gen_8bitsof(TCGv result, TCGv value)
458 {
459     TCGv zero = tcg_constant_tl(0);
460     TCGv ones = tcg_constant_tl(0xff);
461     tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
462 
463     return result;
464 }
465 
466 static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr,
467                                   TCGCond cond, TCGv pred)
468 {
469     TCGLabel *pred_false = NULL;
470     if (cond != TCG_COND_ALWAYS) {
471         pred_false = gen_new_label();
472         tcg_gen_brcondi_tl(cond, pred, 0, pred_false);
473     }
474 
475     if (ctx->pkt->pkt_has_multi_cof) {
476         /* If there are multiple branches in a packet, ignore the second one */
477         tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC],
478                            ctx->branch_taken, tcg_constant_tl(0),
479                            hex_gpr[HEX_REG_PC], addr);
480         tcg_gen_movi_tl(ctx->branch_taken, 1);
481     } else {
482         tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr);
483     }
484 
485     if (cond != TCG_COND_ALWAYS) {
486         gen_set_label(pred_false);
487     }
488 }
489 
490 static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off,
491                                    TCGCond cond, TCGv pred)
492 {
493     target_ulong dest = ctx->pkt->pc + pc_off;
494     if (ctx->pkt->pkt_has_multi_cof) {
495         gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred);
496     } else {
497         /* Defer this jump to the end of the TB */
498         ctx->branch_cond = TCG_COND_ALWAYS;
499         if (pred != NULL) {
500             ctx->branch_cond = cond;
501             tcg_gen_mov_tl(ctx->branch_taken, pred);
502         }
503         ctx->branch_dest = dest;
504     }
505 }
506 
507 void gen_set_usr_field(DisasContext *ctx, int field, TCGv val)
508 {
509     TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
510     tcg_gen_deposit_tl(usr, usr, val,
511                        reg_field_info[field].offset,
512                        reg_field_info[field].width);
513 }
514 
515 void gen_set_usr_fieldi(DisasContext *ctx, int field, int x)
516 {
517     if (reg_field_info[field].width == 1) {
518         TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
519         target_ulong bit = 1 << reg_field_info[field].offset;
520         if ((x & 1) == 1) {
521             tcg_gen_ori_tl(usr, usr, bit);
522         } else {
523             tcg_gen_andi_tl(usr, usr, ~bit);
524         }
525     } else {
526         TCGv val = tcg_constant_tl(x);
527         gen_set_usr_field(ctx, field, val);
528     }
529 }
530 
531 static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2)
532 {
533     TCGv one = tcg_constant_tl(0xff);
534     TCGv zero = tcg_constant_tl(0);
535 
536     tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero);
537 }
538 
539 #ifndef CONFIG_HEXAGON_IDEF_PARSER
540 static inline void gen_loop0r(DisasContext *ctx, TCGv RsV, int riV)
541 {
542     fIMMEXT(riV);
543     fPCALIGN(riV);
544     gen_log_reg_write(ctx, HEX_REG_LC0, RsV);
545     gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV));
546     gen_set_usr_fieldi(ctx, USR_LPCFG, 0);
547 }
548 
549 static void gen_loop0i(DisasContext *ctx, int count, int riV)
550 {
551     gen_loop0r(ctx, tcg_constant_tl(count), riV);
552 }
553 
554 static inline void gen_loop1r(DisasContext *ctx, TCGv RsV, int riV)
555 {
556     fIMMEXT(riV);
557     fPCALIGN(riV);
558     gen_log_reg_write(ctx, HEX_REG_LC1, RsV);
559     gen_log_reg_write(ctx, HEX_REG_SA1, tcg_constant_tl(ctx->pkt->pc + riV));
560 }
561 
562 static void gen_loop1i(DisasContext *ctx, int count, int riV)
563 {
564     gen_loop1r(ctx, tcg_constant_tl(count), riV);
565 }
566 
567 static void gen_ploopNsr(DisasContext *ctx, int N, TCGv RsV, int riV)
568 {
569     fIMMEXT(riV);
570     fPCALIGN(riV);
571     gen_log_reg_write(ctx, HEX_REG_LC0, RsV);
572     gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV));
573     gen_set_usr_fieldi(ctx, USR_LPCFG, N);
574     gen_log_pred_write(ctx, 3, tcg_constant_tl(0));
575 }
576 
577 static void gen_ploopNsi(DisasContext *ctx, int N, int count, int riV)
578 {
579     gen_ploopNsr(ctx, N, tcg_constant_tl(count), riV);
580 }
581 
582 static inline void gen_comparei(TCGCond cond, TCGv res, TCGv arg1, int arg2)
583 {
584     gen_compare(cond, res, arg1, tcg_constant_tl(arg2));
585 }
586 #endif
587 
588 static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc,
589                            TCGCond cond, TCGv pred)
590 {
591     gen_write_new_pc_addr(ctx, dst_pc, cond, pred);
592 }
593 
594 static void gen_cond_jumpr31(DisasContext *ctx, TCGCond cond, TCGv pred)
595 {
596     TCGv LSB = tcg_temp_new();
597     tcg_gen_andi_tl(LSB, pred, 1);
598     gen_cond_jumpr(ctx, hex_gpr[HEX_REG_LR], cond, LSB);
599 }
600 
601 static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred,
602                           int pc_off)
603 {
604     gen_write_new_pc_pcrel(ctx, pc_off, cond, pred);
605 }
606 
607 static void gen_cmpnd_cmp_jmp(DisasContext *ctx,
608                               int pnum, TCGCond cond1, TCGv arg1, TCGv arg2,
609                               TCGCond cond2, int pc_off)
610 {
611     if (ctx->insn->part1) {
612         TCGv pred = tcg_temp_new();
613         gen_compare(cond1, pred, arg1, arg2);
614         gen_log_pred_write(ctx, pnum, pred);
615     } else {
616         TCGv pred = tcg_temp_new();
617         tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]);
618         gen_cond_jump(ctx, cond2, pred, pc_off);
619     }
620 }
621 
622 static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx,
623                                 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
624                                 int pc_off)
625 {
626     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off);
627 }
628 
629 static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx,
630                                 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
631                                 int pc_off)
632 {
633     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off);
634 }
635 
636 static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx,
637                                  int pnum, TCGCond cond, TCGv arg1, int arg2,
638                                  int pc_off)
639 {
640     TCGv tmp = tcg_constant_tl(arg2);
641     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off);
642 }
643 
644 static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx,
645                                  int pnum, TCGCond cond, TCGv arg1, int arg2,
646                                  int pc_off)
647 {
648     TCGv tmp = tcg_constant_tl(arg2);
649     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off);
650 }
651 
652 static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond,
653                                    TCGv arg, int pc_off)
654 {
655     gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off);
656 }
657 
658 static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond,
659                                    TCGv arg, int pc_off)
660 {
661     gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off);
662 }
663 
664 static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx,
665                                   int pnum, TCGv arg, TCGCond cond, int pc_off)
666 {
667     if (ctx->insn->part1) {
668         TCGv pred = tcg_temp_new();
669         tcg_gen_andi_tl(pred, arg, 1);
670         gen_8bitsof(pred, pred);
671         gen_log_pred_write(ctx, pnum, pred);
672     } else {
673         TCGv pred = tcg_temp_new();
674         tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]);
675         gen_cond_jump(ctx, cond, pred, pc_off);
676     }
677 }
678 
679 static void gen_testbit0_jumpnv(DisasContext *ctx,
680                                 TCGv arg, TCGCond cond, int pc_off)
681 {
682     TCGv pred = tcg_temp_new();
683     tcg_gen_andi_tl(pred, arg, 1);
684     gen_cond_jump(ctx, cond, pred, pc_off);
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 lr = get_result_gpr(ctx, HEX_REG_LR);
700     tcg_gen_movi_tl(lr, ctx->next_PC);
701     gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL);
702 }
703 
704 static void gen_callr(DisasContext *ctx, TCGv new_pc)
705 {
706     TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
707     tcg_gen_movi_tl(lr, ctx->next_PC);
708     gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL);
709 }
710 
711 static void gen_cond_call(DisasContext *ctx, TCGv pred,
712                           TCGCond cond, int pc_off)
713 {
714     TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
715     TCGv lsb = tcg_temp_new();
716     TCGLabel *skip = gen_new_label();
717     tcg_gen_andi_tl(lsb, pred, 1);
718     gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb);
719     tcg_gen_brcondi_tl(cond, lsb, 0, skip);
720     tcg_gen_movi_tl(lr, ctx->next_PC);
721     gen_set_label(skip);
722 }
723 
724 static void gen_cond_callr(DisasContext *ctx,
725                            TCGCond cond, TCGv pred, TCGv new_pc)
726 {
727     TCGv lsb = tcg_temp_new();
728     TCGLabel *skip = gen_new_label();
729     tcg_gen_andi_tl(lsb, pred, 1);
730     tcg_gen_brcondi_tl(cond, lsb, 0, skip);
731     gen_callr(ctx, new_pc);
732     gen_set_label(skip);
733 }
734 
735 #ifndef CONFIG_HEXAGON_IDEF_PARSER
736 /* frame = ((LR << 32) | FP) ^ (FRAMEKEY << 32)) */
737 static TCGv_i64 gen_frame_scramble(void)
738 {
739     TCGv_i64 frame = tcg_temp_new_i64();
740     TCGv tmp = tcg_temp_new();
741     tcg_gen_xor_tl(tmp, hex_gpr[HEX_REG_LR], hex_gpr[HEX_REG_FRAMEKEY]);
742     tcg_gen_concat_i32_i64(frame, hex_gpr[HEX_REG_FP], tmp);
743     return frame;
744 }
745 #endif
746 
747 /* frame ^= (int64_t)FRAMEKEY << 32 */
748 static void gen_frame_unscramble(TCGv_i64 frame)
749 {
750     TCGv_i64 framekey = tcg_temp_new_i64();
751     tcg_gen_extu_i32_i64(framekey, hex_gpr[HEX_REG_FRAMEKEY]);
752     tcg_gen_shli_i64(framekey, framekey, 32);
753     tcg_gen_xor_i64(frame, frame, framekey);
754 }
755 
756 static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA)
757 {
758     Insn *insn = ctx->insn;  /* Needed for CHECK_NOSHUF */
759     CHECK_NOSHUF(EA, 8);
760     tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_LE | MO_UQ);
761 }
762 
763 #ifndef CONFIG_HEXAGON_IDEF_PARSER
764 /* Stack overflow check */
765 static void gen_framecheck(TCGv EA, int framesize)
766 {
767     /* Not modelled in linux-user mode */
768     /* Placeholder for system mode */
769 #ifndef CONFIG_USER_ONLY
770     g_assert_not_reached();
771 #endif
772 }
773 
774 static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize)
775 {
776     TCGv r30 = tcg_temp_new();
777     TCGv_i64 frame;
778     tcg_gen_addi_tl(r30, r29, -8);
779     frame = gen_frame_scramble();
780     gen_store8(tcg_env, r30, frame, ctx->insn->slot);
781     gen_log_reg_write(ctx, HEX_REG_FP, r30);
782     gen_framecheck(r30, framesize);
783     tcg_gen_subi_tl(r29, r30, framesize);
784 }
785 
786 static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30)
787 {
788     TCGv r29 = tcg_temp_new();
789     TCGv_i64 frame = tcg_temp_new_i64();
790     gen_load_frame(ctx, frame, r30);
791     gen_frame_unscramble(frame);
792     tcg_gen_mov_i64(r31_30, frame);
793     tcg_gen_addi_tl(r29, r30, 8);
794     gen_log_reg_write(ctx, HEX_REG_SP, r29);
795 }
796 #endif
797 
798 static void gen_return(DisasContext *ctx, TCGv_i64 dst, TCGv src)
799 {
800     /*
801      * frame = *src
802      * dst = frame_unscramble(frame)
803      * SP = src + 8
804      * PC = dst.w[1]
805      */
806     TCGv_i64 frame = tcg_temp_new_i64();
807     TCGv r31 = tcg_temp_new();
808     TCGv r29 = get_result_gpr(ctx, HEX_REG_SP);
809 
810     gen_load_frame(ctx, frame, src);
811     gen_frame_unscramble(frame);
812     tcg_gen_mov_i64(dst, frame);
813     tcg_gen_addi_tl(r29, src, 8);
814     tcg_gen_extrh_i64_i32(r31, dst);
815     gen_jumpr(ctx, r31);
816 }
817 
818 /* if (pred) dst = dealloc_return(src):raw */
819 static void gen_cond_return(DisasContext *ctx, TCGv_i64 dst, TCGv src,
820                             TCGv pred, TCGCond cond)
821 {
822     TCGv LSB = tcg_temp_new();
823     TCGLabel *skip = gen_new_label();
824     tcg_gen_andi_tl(LSB, pred, 1);
825 
826     tcg_gen_brcondi_tl(cond, LSB, 0, skip);
827     gen_return(ctx, dst, src);
828     gen_set_label(skip);
829 }
830 
831 /* sub-instruction version (no RddV, so handle it manually) */
832 static void gen_cond_return_subinsn(DisasContext *ctx, TCGCond cond, TCGv pred)
833 {
834     TCGv_i64 RddV = get_result_gpr_pair(ctx, HEX_REG_FP);
835     gen_cond_return(ctx, RddV, hex_gpr[HEX_REG_FP], pred, cond);
836     gen_log_reg_write_pair(ctx, HEX_REG_FP, RddV);
837 }
838 
839 static void gen_endloop0(DisasContext *ctx)
840 {
841     TCGv lpcfg = tcg_temp_new();
842 
843     GET_USR_FIELD(USR_LPCFG, lpcfg);
844 
845     /*
846      *    if (lpcfg == 1) {
847      *        p3 = 0xff;
848      *    }
849      */
850     TCGLabel *label1 = gen_new_label();
851     tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
852     {
853         gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff));
854     }
855     gen_set_label(label1);
856 
857     /*
858      *    if (lpcfg) {
859      *        SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
860      *    }
861      */
862     TCGLabel *label2 = gen_new_label();
863     tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
864     {
865         tcg_gen_subi_tl(lpcfg, lpcfg, 1);
866         gen_set_usr_field(ctx, USR_LPCFG, lpcfg);
867     }
868     gen_set_label(label2);
869 
870     /*
871      * If we're in a tight loop, we'll do this at the end of the TB to take
872      * advantage of direct block chaining.
873      */
874     if (!ctx->is_tight_loop) {
875         /*
876          *    if (LC0 > 1) {
877          *        PC = SA0;
878          *        LC0--;
879          *    }
880          */
881         TCGLabel *label3 = gen_new_label();
882         tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
883         {
884             TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0);
885             gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
886             tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1);
887         }
888         gen_set_label(label3);
889     }
890 }
891 
892 static void gen_endloop1(DisasContext *ctx)
893 {
894     /*
895      *    if (LC1 > 1) {
896      *        PC = SA1;
897      *        LC1--;
898      *    }
899      */
900     TCGLabel *label = gen_new_label();
901     tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, label);
902     {
903         TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1);
904         gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]);
905         tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1);
906     }
907     gen_set_label(label);
908 }
909 
910 static void gen_endloop01(DisasContext *ctx)
911 {
912     TCGv lpcfg = tcg_temp_new();
913     TCGLabel *label1 = gen_new_label();
914     TCGLabel *label2 = gen_new_label();
915     TCGLabel *label3 = gen_new_label();
916     TCGLabel *done = gen_new_label();
917 
918     GET_USR_FIELD(USR_LPCFG, lpcfg);
919 
920     /*
921      *    if (lpcfg == 1) {
922      *        p3 = 0xff;
923      *    }
924      */
925     tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
926     {
927         gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff));
928     }
929     gen_set_label(label1);
930 
931     /*
932      *    if (lpcfg) {
933      *        SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
934      *    }
935      */
936     tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
937     {
938         tcg_gen_subi_tl(lpcfg, lpcfg, 1);
939         gen_set_usr_field(ctx, USR_LPCFG, lpcfg);
940     }
941     gen_set_label(label2);
942 
943     /*
944      *    if (LC0 > 1) {
945      *        PC = SA0;
946      *        LC0--;
947      *    } else if (LC1 > 1) {
948      *        PC = SA1;
949      *        LC1--;
950      *    }
951      */
952     tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
953     {
954         TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0);
955         gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
956         tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1);
957         tcg_gen_br(done);
958     }
959     gen_set_label(label3);
960     tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, done);
961     {
962         TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1);
963         gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]);
964         tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1);
965     }
966     gen_set_label(done);
967 }
968 
969 static void gen_cmp_jumpnv(DisasContext *ctx,
970                            TCGCond cond, TCGv val, TCGv src, int pc_off)
971 {
972     TCGv pred = tcg_temp_new();
973     tcg_gen_setcond_tl(cond, pred, val, src);
974     gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
975 }
976 
977 static void gen_cmpi_jumpnv(DisasContext *ctx,
978                             TCGCond cond, TCGv val, int src, int pc_off)
979 {
980     TCGv pred = tcg_temp_new();
981     tcg_gen_setcondi_tl(cond, pred, val, src);
982     gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
983 }
984 
985 /* Shift left with saturation */
986 static void gen_shl_sat(DisasContext *ctx, TCGv dst, TCGv src, TCGv shift_amt)
987 {
988     TCGv tmp = tcg_temp_new();    /* In case dst == src */
989     TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
990     TCGv sh32 = tcg_temp_new();
991     TCGv dst_sar = tcg_temp_new();
992     TCGv ovf = tcg_temp_new();
993     TCGv satval = tcg_temp_new();
994     TCGv min = tcg_constant_tl(0x80000000);
995     TCGv max = tcg_constant_tl(0x7fffffff);
996 
997     /*
998      *    Possible values for shift_amt are 0 .. 64
999      *    We need special handling for values above 31
1000      *
1001      *    sh32 = shift & 31;
1002      *    dst = sh32 == shift ? src : 0;
1003      *    dst <<= sh32;
1004      *    dst_sar = dst >> sh32;
1005      *    satval = src < 0 ? min : max;
1006      *    if (dst_asr != src) {
1007      *        usr.OVF |= 1;
1008      *        dst = satval;
1009      *    }
1010      */
1011 
1012     tcg_gen_andi_tl(sh32, shift_amt, 31);
1013     tcg_gen_movcond_tl(TCG_COND_EQ, tmp, sh32, shift_amt,
1014                        src, tcg_constant_tl(0));
1015     tcg_gen_shl_tl(tmp, tmp, sh32);
1016     tcg_gen_sar_tl(dst_sar, tmp, sh32);
1017     tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max);
1018 
1019     tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src);
1020     tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset);
1021     tcg_gen_or_tl(usr, usr, ovf);
1022 
1023     tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, tmp, satval);
1024 }
1025 
1026 static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt)
1027 {
1028     /*
1029      *  Shift arithmetic right
1030      *  Robust when shift_amt is >31 bits
1031      */
1032     TCGv tmp = tcg_temp_new();
1033     tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31));
1034     tcg_gen_sar_tl(dst, src, tmp);
1035 }
1036 
1037 /* Bidirectional shift right with saturation */
1038 static void gen_asr_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV)
1039 {
1040     TCGv shift_amt = tcg_temp_new();
1041     TCGLabel *positive = gen_new_label();
1042     TCGLabel *done = gen_new_label();
1043 
1044     tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
1045     tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
1046 
1047     /* Negative shift amount => shift left */
1048     tcg_gen_neg_tl(shift_amt, shift_amt);
1049     gen_shl_sat(ctx, RdV, RsV, shift_amt);
1050     tcg_gen_br(done);
1051 
1052     gen_set_label(positive);
1053     /* Positive shift amount => shift right */
1054     gen_sar(RdV, RsV, shift_amt);
1055 
1056     gen_set_label(done);
1057 }
1058 
1059 /* Bidirectional shift left with saturation */
1060 static void gen_asl_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV)
1061 {
1062     TCGv shift_amt = tcg_temp_new();
1063     TCGLabel *positive = gen_new_label();
1064     TCGLabel *done = gen_new_label();
1065 
1066     tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
1067     tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
1068 
1069     /* Negative shift amount => shift right */
1070     tcg_gen_neg_tl(shift_amt, shift_amt);
1071     gen_sar(RdV, RsV, shift_amt);
1072     tcg_gen_br(done);
1073 
1074     gen_set_label(positive);
1075     /* Positive shift amount => shift left */
1076     gen_shl_sat(ctx, RdV, RsV, shift_amt);
1077 
1078     gen_set_label(done);
1079 }
1080 
1081 static void gen_insert_rp(DisasContext *ctx, TCGv RxV, TCGv RsV, TCGv_i64 RttV)
1082 {
1083     /*
1084      * int width = fZXTN(6, 32, (fGETWORD(1, RttV)));
1085      * int offset = fSXTN(7, 32, (fGETWORD(0, RttV)));
1086      * size8u_t mask = ((fCONSTLL(1) << width) - 1);
1087      * if (offset < 0) {
1088      *     RxV = 0;
1089      * } else {
1090      *     RxV &= ~(mask << offset);
1091      *     RxV |= ((RsV & mask) << offset);
1092      * }
1093      */
1094 
1095     TCGv width = tcg_temp_new();
1096     TCGv offset = tcg_temp_new();
1097     TCGv_i64 mask = tcg_temp_new_i64();
1098     TCGv_i64 result = tcg_temp_new_i64();
1099     TCGv_i64 tmp = tcg_temp_new_i64();
1100     TCGv_i64 offset64 = tcg_temp_new_i64();
1101     TCGLabel *label = gen_new_label();
1102     TCGLabel *done = gen_new_label();
1103 
1104     tcg_gen_extrh_i64_i32(width, RttV);
1105     tcg_gen_extract_tl(width, width, 0, 6);
1106     tcg_gen_extrl_i64_i32(offset, RttV);
1107     tcg_gen_sextract_tl(offset, offset, 0, 7);
1108     /* Possible values for offset are -64 .. 63 */
1109     tcg_gen_brcondi_tl(TCG_COND_GE, offset, 0, label);
1110     /* For negative offsets, zero out the result */
1111     tcg_gen_movi_tl(RxV, 0);
1112     tcg_gen_br(done);
1113     gen_set_label(label);
1114     /* At this point, possible values of offset are 0 .. 63 */
1115     tcg_gen_ext_i32_i64(mask, width);
1116     tcg_gen_shl_i64(mask, tcg_constant_i64(1), mask);
1117     tcg_gen_subi_i64(mask, mask, 1);
1118     tcg_gen_extu_i32_i64(result, RxV);
1119     tcg_gen_ext_i32_i64(tmp, offset);
1120     tcg_gen_shl_i64(tmp, mask, tmp);
1121     tcg_gen_andc_i64(result, result, tmp);
1122     tcg_gen_extu_i32_i64(tmp, RsV);
1123     tcg_gen_and_i64(tmp, tmp, mask);
1124     tcg_gen_extu_i32_i64(offset64, offset);
1125     tcg_gen_shl_i64(tmp, tmp, offset64);
1126     tcg_gen_or_i64(result, result, tmp);
1127     tcg_gen_extrl_i64_i32(RxV, result);
1128     gen_set_label(done);
1129 }
1130 
1131 static void gen_asr_r_svw_trun(DisasContext *ctx, TCGv RdV,
1132                                TCGv_i64 RssV, TCGv RtV)
1133 {
1134     /*
1135      * for (int i = 0; i < 2; i++) {
1136      *     fSETHALF(i, RdV, fGETHALF(0, ((fSXTN(7, 32, RtV) > 0) ?
1137      *         (fCAST4_8s(fGETWORD(i, RssV)) >> fSXTN(7, 32, RtV)) :
1138      *         (fCAST4_8s(fGETWORD(i, RssV)) << -fSXTN(7, 32, RtV)))));
1139      * }
1140      */
1141     TCGv shift_amt32 = tcg_temp_new();
1142     TCGv_i64 shift_amt64 = tcg_temp_new_i64();
1143     TCGv_i64 tmp64 = tcg_temp_new_i64();
1144     TCGv tmp32 = tcg_temp_new();
1145     TCGLabel *label = gen_new_label();
1146     TCGLabel *zero = gen_new_label();
1147     TCGLabel *done =  gen_new_label();
1148 
1149     tcg_gen_sextract_tl(shift_amt32, RtV, 0, 7);
1150     /* Possible values of shift_amt32 are -64 .. 63 */
1151     tcg_gen_brcondi_tl(TCG_COND_LE, shift_amt32, 0, label);
1152     /* After branch, possible values of shift_amt32 are 1 .. 63 */
1153     tcg_gen_ext_i32_i64(shift_amt64, shift_amt32);
1154     for (int i = 0; i < 2; i++) {
1155         tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32);
1156         tcg_gen_sar_i64(tmp64, tmp64, shift_amt64);
1157         tcg_gen_extrl_i64_i32(tmp32, tmp64);
1158         tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16);
1159     }
1160     tcg_gen_br(done);
1161     gen_set_label(label);
1162     tcg_gen_neg_tl(shift_amt32, shift_amt32);
1163     /*At this point, possible values of shift_amt32 are 0 .. 64 */
1164     tcg_gen_brcondi_tl(TCG_COND_GT, shift_amt32, 63, zero);
1165     /*At this point, possible values of shift_amt32 are 0 .. 63 */
1166     tcg_gen_ext_i32_i64(shift_amt64, shift_amt32);
1167     for (int i = 0; i < 2; i++) {
1168         tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32);
1169         tcg_gen_shl_i64(tmp64, tmp64, shift_amt64);
1170         tcg_gen_extrl_i64_i32(tmp32, tmp64);
1171         tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16);
1172     }
1173     tcg_gen_br(done);
1174     gen_set_label(zero);
1175     /* When the shift_amt is 64, zero out the result */
1176     tcg_gen_movi_tl(RdV, 0);
1177     gen_set_label(done);
1178 }
1179 
1180 static intptr_t vreg_src_off(DisasContext *ctx, int num)
1181 {
1182     intptr_t offset = offsetof(CPUHexagonState, VRegs[num]);
1183 
1184     if (test_bit(num, ctx->vregs_select)) {
1185         offset = ctx_future_vreg_off(ctx, num, 1, false);
1186     }
1187     if (test_bit(num, ctx->vregs_updated_tmp)) {
1188         offset = ctx_tmp_vreg_off(ctx, num, 1, false);
1189     }
1190     return offset;
1191 }
1192 
1193 static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num,
1194                                VRegWriteType type)
1195 {
1196     intptr_t dstoff;
1197 
1198     if (type != EXT_TMP) {
1199         dstoff = ctx_future_vreg_off(ctx, num, 1, true);
1200         tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
1201                          sizeof(MMVector), sizeof(MMVector));
1202     } else {
1203         dstoff = ctx_tmp_vreg_off(ctx, num, 1, false);
1204         tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
1205                          sizeof(MMVector), sizeof(MMVector));
1206     }
1207 }
1208 
1209 static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num,
1210                                     VRegWriteType type)
1211 {
1212     gen_log_vreg_write(ctx, srcoff, num ^ 0, type);
1213     srcoff += sizeof(MMVector);
1214     gen_log_vreg_write(ctx, srcoff, num ^ 1, type);
1215 }
1216 
1217 static intptr_t get_result_qreg(DisasContext *ctx, int qnum)
1218 {
1219     if (ctx->need_commit) {
1220         return  offsetof(CPUHexagonState, future_QRegs[qnum]);
1221     } else {
1222         return  offsetof(CPUHexagonState, QRegs[qnum]);
1223     }
1224 }
1225 
1226 static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src,
1227                           bool aligned)
1228 {
1229     TCGv_i64 tmp = tcg_temp_new_i64();
1230     if (aligned) {
1231         tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1));
1232     }
1233     for (int i = 0; i < sizeof(MMVector) / 8; i++) {
1234         tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_LE | MO_UQ);
1235         tcg_gen_addi_tl(src, src, 8);
1236         tcg_gen_st_i64(tmp, tcg_env, dstoff + i * 8);
1237     }
1238 }
1239 
1240 static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
1241                            int slot, bool aligned)
1242 {
1243     intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
1244     intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
1245 
1246     if (is_gather_store_insn(ctx)) {
1247         TCGv sl = tcg_constant_tl(slot);
1248         gen_helper_gather_store(tcg_env, EA, sl);
1249         return;
1250     }
1251 
1252     tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
1253     if (aligned) {
1254         tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
1255                         ~((int32_t)sizeof(MMVector) - 1));
1256     } else {
1257         tcg_gen_mov_tl(hex_vstore_addr[slot], EA);
1258     }
1259     tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
1260 
1261     /* Copy the data to the vstore buffer */
1262     tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
1263     /* Set the mask to all 1's */
1264     tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL);
1265 }
1266 
1267 static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
1268                                   intptr_t bitsoff, int slot, bool invert)
1269 {
1270     intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
1271     intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
1272 
1273     tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
1274     tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
1275                     ~((int32_t)sizeof(MMVector) - 1));
1276     tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
1277 
1278     /* Copy the data to the vstore buffer */
1279     tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
1280     /* Copy the mask */
1281     tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg));
1282     if (invert) {
1283         tcg_gen_gvec_not(MO_64, maskoff, maskoff,
1284                          sizeof(MMQReg), sizeof(MMQReg));
1285     }
1286 }
1287 
1288 static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff)
1289 {
1290     TCGv_i64 tmp = tcg_temp_new_i64();
1291     TCGv_i64 word = tcg_temp_new_i64();
1292     TCGv_i64 bits = tcg_temp_new_i64();
1293     TCGv_i64 mask = tcg_temp_new_i64();
1294     TCGv_i64 zero = tcg_constant_i64(0);
1295     TCGv_i64 ones = tcg_constant_i64(~0);
1296 
1297     for (int i = 0; i < sizeof(MMVector) / 8; i++) {
1298         tcg_gen_ld_i64(tmp, tcg_env, srcoff + i * 8);
1299         tcg_gen_movi_i64(mask, 0);
1300 
1301         for (int j = 0; j < 8; j += size) {
1302             tcg_gen_extract_i64(word, tmp, j * 8, size * 8);
1303             tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero);
1304             tcg_gen_deposit_i64(mask, mask, bits, j, size);
1305         }
1306 
1307         tcg_gen_st8_i64(mask, tcg_env, dstoff + i);
1308     }
1309 }
1310 
1311 void probe_noshuf_load(TCGv va, int s, int mi)
1312 {
1313     TCGv size = tcg_constant_tl(s);
1314     TCGv mem_idx = tcg_constant_tl(mi);
1315     gen_helper_probe_noshuf_load(tcg_env, va, size, mem_idx);
1316 }
1317 
1318 /*
1319  * Note: Since this function might branch, `val` is
1320  * required to be a `tcg_temp_local`.
1321  */
1322 void gen_set_usr_field_if(DisasContext *ctx, int field, TCGv val)
1323 {
1324     /* Sets the USR field if `val` is non-zero */
1325     if (reg_field_info[field].width == 1) {
1326         TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
1327         TCGv tmp = tcg_temp_new();
1328         tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
1329         tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
1330         tcg_gen_or_tl(usr, usr, tmp);
1331     } else {
1332         TCGLabel *skip_label = gen_new_label();
1333         tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
1334         gen_set_usr_field(ctx, field, val);
1335         gen_set_label(skip_label);
1336     }
1337 }
1338 
1339 void gen_sat_i32(TCGv dest, TCGv source, int width)
1340 {
1341     TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1);
1342     TCGv min_val = tcg_constant_tl(-(1 << (width - 1)));
1343     tcg_gen_smin_tl(dest, source, max_val);
1344     tcg_gen_smax_tl(dest, dest, min_val);
1345 }
1346 
1347 void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
1348 {
1349     TCGv tmp = tcg_temp_new();    /* In case dest == source */
1350     gen_sat_i32(tmp, source, width);
1351     tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp);
1352     tcg_gen_mov_tl(dest, tmp);
1353 }
1354 
1355 void gen_satu_i32(TCGv dest, TCGv source, int width)
1356 {
1357     TCGv tmp = tcg_temp_new();    /* In case dest == source */
1358     TCGv max_val = tcg_constant_tl((1 << width) - 1);
1359     TCGv zero = tcg_constant_tl(0);
1360     tcg_gen_movcond_tl(TCG_COND_GTU, tmp, source, max_val, max_val, source);
1361     tcg_gen_movcond_tl(TCG_COND_LT, tmp, source, zero, zero, tmp);
1362     tcg_gen_mov_tl(dest, tmp);
1363 }
1364 
1365 void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
1366 {
1367     TCGv tmp = tcg_temp_new();    /* In case dest == source */
1368     gen_satu_i32(tmp, source, width);
1369     tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp);
1370     tcg_gen_mov_tl(dest, tmp);
1371 }
1372 
1373 void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width)
1374 {
1375     TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL);
1376     TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1)));
1377     tcg_gen_smin_i64(dest, source, max_val);
1378     tcg_gen_smax_i64(dest, dest, min_val);
1379 }
1380 
1381 void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
1382 {
1383     TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */
1384     TCGv_i64 ovfl_64;
1385     gen_sat_i64(tmp, source, width);
1386     ovfl_64 = tcg_temp_new_i64();
1387     tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source);
1388     tcg_gen_mov_i64(dest, tmp);
1389     tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
1390 }
1391 
1392 void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width)
1393 {
1394     TCGv_i64 tmp = tcg_temp_new_i64();    /* In case dest == source */
1395     TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL);
1396     TCGv_i64 zero = tcg_constant_i64(0);
1397     tcg_gen_movcond_i64(TCG_COND_GTU, tmp, source, max_val, max_val, source);
1398     tcg_gen_movcond_i64(TCG_COND_LT, tmp, source, zero, zero, tmp);
1399     tcg_gen_mov_i64(dest, tmp);
1400 }
1401 
1402 void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
1403 {
1404     TCGv_i64 tmp = tcg_temp_new_i64();    /* In case dest == source */
1405     TCGv_i64 ovfl_64;
1406     gen_satu_i64(tmp, source, width);
1407     ovfl_64 = tcg_temp_new_i64();
1408     tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source);
1409     tcg_gen_mov_i64(dest, tmp);
1410     tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
1411 }
1412 
1413 /* Implements the fADDSAT64 macro in TCG */
1414 void gen_add_sat_i64(DisasContext *ctx, TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b)
1415 {
1416     TCGv_i64 sum = tcg_temp_new_i64();
1417     TCGv_i64 xor = tcg_temp_new_i64();
1418     TCGv_i64 cond1 = tcg_temp_new_i64();
1419     TCGv_i64 cond2 = tcg_temp_new_i64();
1420     TCGv_i64 cond3 = tcg_temp_new_i64();
1421     TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
1422     TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
1423     TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
1424     TCGv_i64 zero = tcg_constant_i64(0);
1425     TCGLabel *no_ovfl_label = gen_new_label();
1426     TCGLabel *ovfl_label = gen_new_label();
1427     TCGLabel *ret_label = gen_new_label();
1428 
1429     tcg_gen_add_i64(sum, a, b);
1430     tcg_gen_xor_i64(xor, a, b);
1431 
1432     /* if (xor & mask) */
1433     tcg_gen_and_i64(cond1, xor, mask);
1434     tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
1435 
1436     /* else if ((a ^ sum) & mask) */
1437     tcg_gen_xor_i64(cond2, a, sum);
1438     tcg_gen_and_i64(cond2, cond2, mask);
1439     tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
1440     /* fallthrough to no_ovfl_label branch */
1441 
1442     /* if branch */
1443     gen_set_label(no_ovfl_label);
1444     tcg_gen_mov_i64(ret, sum);
1445     tcg_gen_br(ret_label);
1446 
1447     /* else if branch */
1448     gen_set_label(ovfl_label);
1449     tcg_gen_and_i64(cond3, sum, mask);
1450     tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg);
1451     gen_set_usr_fieldi(ctx, USR_OVF, 1);
1452 
1453     gen_set_label(ret_label);
1454 }
1455 
1456 #include "tcg_funcs_generated.c.inc"
1457 #include "tcg_func_table_generated.c.inc"
1458