xref: /qemu/target/hexagon/op_helper.c (revision 5db05230)
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 "qemu/log.h"
20 #include "exec/exec-all.h"
21 #include "exec/cpu_ldst.h"
22 #include "exec/helper-proto.h"
23 #include "fpu/softfloat.h"
24 #include "cpu.h"
25 #include "internal.h"
26 #include "macros.h"
27 #include "arch.h"
28 #include "hex_arch_types.h"
29 #include "fma_emu.h"
30 #include "mmvec/mmvec.h"
31 #include "mmvec/macros.h"
32 #include "op_helper.h"
33 #include "translate.h"
34 
35 #define SF_BIAS        127
36 #define SF_MANTBITS    23
37 
38 /* Exceptions processing helpers */
39 static G_NORETURN
40 void do_raise_exception_err(CPUHexagonState *env,
41                             uint32_t exception,
42                             uintptr_t pc)
43 {
44     CPUState *cs = env_cpu(env);
45     qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
46     cs->exception_index = exception;
47     cpu_loop_exit_restore(cs, pc);
48 }
49 
50 G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
51 {
52     do_raise_exception_err(env, excp, 0);
53 }
54 
55 void log_store32(CPUHexagonState *env, target_ulong addr,
56                  target_ulong val, int width, int slot)
57 {
58     HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
59                   ", %" PRId32 " [0x08%" PRIx32 "])\n",
60                   width, addr, val, val);
61     env->mem_log_stores[slot].va = addr;
62     env->mem_log_stores[slot].width = width;
63     env->mem_log_stores[slot].data32 = val;
64 }
65 
66 void log_store64(CPUHexagonState *env, target_ulong addr,
67                  int64_t val, int width, int slot)
68 {
69     HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
70                   ", %" PRId64 " [0x016%" PRIx64 "])\n",
71                    width, addr, val, val);
72     env->mem_log_stores[slot].va = addr;
73     env->mem_log_stores[slot].width = width;
74     env->mem_log_stores[slot].data64 = val;
75 }
76 
77 /* Handy place to set a breakpoint */
78 void HELPER(debug_start_packet)(CPUHexagonState *env)
79 {
80     HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
81                   env->gpr[HEX_REG_PC]);
82 
83     for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
84         env->reg_written[i] = 0;
85     }
86 }
87 
88 /* Checks for bookkeeping errors between disassembly context and runtime */
89 void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
90 {
91     if (env->mem_log_stores[slot].width != check) {
92         HEX_DEBUG_LOG("ERROR: %d != %d\n",
93                       env->mem_log_stores[slot].width, check);
94         g_assert_not_reached();
95     }
96 }
97 
98 static void commit_store(CPUHexagonState *env, int slot_num, uintptr_t ra)
99 {
100     uint8_t width = env->mem_log_stores[slot_num].width;
101     target_ulong va = env->mem_log_stores[slot_num].va;
102 
103     switch (width) {
104     case 1:
105         cpu_stb_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
106         break;
107     case 2:
108         cpu_stw_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
109         break;
110     case 4:
111         cpu_stl_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
112         break;
113     case 8:
114         cpu_stq_data_ra(env, va, env->mem_log_stores[slot_num].data64, ra);
115         break;
116     default:
117         g_assert_not_reached();
118     }
119 }
120 
121 void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
122 {
123     uintptr_t ra = GETPC();
124     commit_store(env, slot_num, ra);
125 }
126 
127 void HELPER(gather_store)(CPUHexagonState *env, uint32_t addr, int slot)
128 {
129     mem_gather_store(env, addr, slot);
130 }
131 
132 void HELPER(commit_hvx_stores)(CPUHexagonState *env)
133 {
134     uintptr_t ra = GETPC();
135 
136     /* Normal (possibly masked) vector store */
137     for (int i = 0; i < VSTORES_MAX; i++) {
138         if (env->vstore_pending[i]) {
139             env->vstore_pending[i] = 0;
140             target_ulong va = env->vstore[i].va;
141             int size = env->vstore[i].size;
142             for (int j = 0; j < size; j++) {
143                 if (test_bit(j, env->vstore[i].mask)) {
144                     cpu_stb_data_ra(env, va + j, env->vstore[i].data.ub[j], ra);
145                 }
146             }
147         }
148     }
149 
150     /* Scatter store */
151     if (env->vtcm_pending) {
152         env->vtcm_pending = false;
153         if (env->vtcm_log.op) {
154             /* Need to perform the scatter read/modify/write at commit time */
155             if (env->vtcm_log.op_size == 2) {
156                 SCATTER_OP_WRITE_TO_MEM(uint16_t);
157             } else if (env->vtcm_log.op_size == 4) {
158                 /* Word Scatter += */
159                 SCATTER_OP_WRITE_TO_MEM(uint32_t);
160             } else {
161                 g_assert_not_reached();
162             }
163         } else {
164             for (int i = 0; i < sizeof(MMVector); i++) {
165                 if (test_bit(i, env->vtcm_log.mask)) {
166                     cpu_stb_data_ra(env, env->vtcm_log.va[i],
167                                     env->vtcm_log.data.ub[i], ra);
168                     clear_bit(i, env->vtcm_log.mask);
169                     env->vtcm_log.data.ub[i] = 0;
170                 }
171 
172             }
173         }
174     }
175 }
176 
177 static void print_store(CPUHexagonState *env, int slot)
178 {
179     if (!(env->slot_cancelled & (1 << slot))) {
180         uint8_t width = env->mem_log_stores[slot].width;
181         if (width == 1) {
182             uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
183             HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
184                           " (0x%02" PRIx32 ")\n",
185                           env->mem_log_stores[slot].va, data, data);
186         } else if (width == 2) {
187             uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
188             HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
189                           " (0x%04" PRIx32 ")\n",
190                           env->mem_log_stores[slot].va, data, data);
191         } else if (width == 4) {
192             uint32_t data = env->mem_log_stores[slot].data32;
193             HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
194                           " (0x%08" PRIx32 ")\n",
195                           env->mem_log_stores[slot].va, data, data);
196         } else if (width == 8) {
197             HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
198                           " (0x%016" PRIx64 ")\n",
199                           env->mem_log_stores[slot].va,
200                           env->mem_log_stores[slot].data64,
201                           env->mem_log_stores[slot].data64);
202         } else {
203             HEX_DEBUG_LOG("\tBad store width %d\n", width);
204             g_assert_not_reached();
205         }
206     }
207 }
208 
209 /* This function is a handy place to set a breakpoint */
210 void HELPER(debug_commit_end)(CPUHexagonState *env, uint32_t this_PC,
211                               int pred_written, int has_st0, int has_st1)
212 {
213     bool reg_printed = false;
214     bool pred_printed = false;
215     int i;
216 
217     HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n", this_PC);
218     HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
219 
220     for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
221         if (env->reg_written[i]) {
222             if (!reg_printed) {
223                 HEX_DEBUG_LOG("Regs written\n");
224                 reg_printed = true;
225             }
226             HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
227                           i, env->gpr[i], env->gpr[i]);
228         }
229     }
230 
231     for (i = 0; i < NUM_PREGS; i++) {
232         if (pred_written & (1 << i)) {
233             if (!pred_printed) {
234                 HEX_DEBUG_LOG("Predicates written\n");
235                 pred_printed = true;
236             }
237             HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
238                           i, env->pred[i]);
239         }
240     }
241 
242     if (has_st0 || has_st1) {
243         HEX_DEBUG_LOG("Stores\n");
244         if (has_st0) {
245             print_store(env, 0);
246         }
247         if (has_st1) {
248             print_store(env, 1);
249         }
250     }
251 
252     HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->gpr[HEX_REG_PC]);
253     HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
254                   ", insn = " TARGET_FMT_lx
255                   ", hvx = " TARGET_FMT_lx "\n",
256                   env->gpr[HEX_REG_QEMU_PKT_CNT],
257                   env->gpr[HEX_REG_QEMU_INSN_CNT],
258                   env->gpr[HEX_REG_QEMU_HVX_CNT]);
259 
260 }
261 
262 int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
263 {
264     uint32_t K_const = extract32(M, 24, 4);
265     uint32_t length = extract32(M, 0, 17);
266     uint32_t new_ptr = RxV + offset;
267     uint32_t start_addr;
268     uint32_t end_addr;
269 
270     if (K_const == 0 && length >= 4) {
271         start_addr = CS;
272         end_addr = start_addr + length;
273     } else {
274         /*
275          * Versions v3 and earlier used the K value to specify a power-of-2 size
276          * 2^(K+2) that is greater than the buffer length
277          */
278         int32_t mask = (1 << (K_const + 2)) - 1;
279         start_addr = RxV & (~mask);
280         end_addr = start_addr | length;
281     }
282 
283     if (new_ptr >= end_addr) {
284         new_ptr -= length;
285     } else if (new_ptr < start_addr) {
286         new_ptr += length;
287     }
288 
289     return new_ptr;
290 }
291 
292 uint32_t HELPER(fbrev)(uint32_t addr)
293 {
294     /*
295      *  Bit reverse the low 16 bits of the address
296      */
297     return deposit32(addr, 0, 16, revbit16(addr));
298 }
299 
300 static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
301 {
302     return make_float32(
303         ((sign & 1) << 31) |
304         ((exp & 0xff) << SF_MANTBITS) |
305         (mant & ((1 << SF_MANTBITS) - 1)));
306 }
307 
308 /*
309  * sfrecipa, sfinvsqrta have two 32-bit results
310  *     r0,p0=sfrecipa(r1,r2)
311  *     r0,p0=sfinvsqrta(r1)
312  *
313  * Since helpers can only return a single value, we pack the two results
314  * into a 64-bit value.
315  */
316 uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
317 {
318     int32_t PeV = 0;
319     float32 RdV;
320     int idx;
321     int adjust;
322     int mant;
323     int exp;
324 
325     arch_fpop_start(env);
326     if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
327         PeV = adjust;
328         idx = (RtV >> 16) & 0x7f;
329         mant = (recip_lookup_table[idx] << 15) | 1;
330         exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
331         RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
332     }
333     arch_fpop_end(env);
334     return ((uint64_t)RdV << 32) | PeV;
335 }
336 
337 uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
338 {
339     int PeV = 0;
340     float32 RdV;
341     int idx;
342     int adjust;
343     int mant;
344     int exp;
345 
346     arch_fpop_start(env);
347     if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
348         PeV = adjust;
349         idx = (RsV >> 17) & 0x7f;
350         mant = (invsqrt_lookup_table[idx] << 15);
351         exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
352         RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
353     }
354     arch_fpop_end(env);
355     return ((uint64_t)RdV << 32) | PeV;
356 }
357 
358 int64_t HELPER(vacsh_val)(CPUHexagonState *env,
359                            int64_t RxxV, int64_t RssV, int64_t RttV,
360                            uint32_t pkt_need_commit)
361 {
362     for (int i = 0; i < 4; i++) {
363         int xv = sextract64(RxxV, i * 16, 16);
364         int sv = sextract64(RssV, i * 16, 16);
365         int tv = sextract64(RttV, i * 16, 16);
366         int max;
367         xv = xv + tv;
368         sv = sv - tv;
369         max = xv > sv ? xv : sv;
370         /* Note that fSATH can set the OVF bit in usr */
371         RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
372     }
373     return RxxV;
374 }
375 
376 int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
377                            int64_t RxxV, int64_t RssV, int64_t RttV)
378 {
379     int32_t PeV = 0;
380     for (int i = 0; i < 4; i++) {
381         int xv = sextract64(RxxV, i * 16, 16);
382         int sv = sextract64(RssV, i * 16, 16);
383         int tv = sextract64(RttV, i * 16, 16);
384         xv = xv + tv;
385         sv = sv - tv;
386         PeV = deposit32(PeV, i * 2, 1, (xv > sv));
387         PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
388     }
389     return PeV;
390 }
391 
392 int64_t HELPER(cabacdecbin_val)(int64_t RssV, int64_t RttV)
393 {
394     int64_t RddV = 0;
395     size4u_t state;
396     size4u_t valMPS;
397     size4u_t bitpos;
398     size4u_t range;
399     size4u_t offset;
400     size4u_t rLPS;
401     size4u_t rMPS;
402 
403     state =  fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0);
404     valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8);
405     bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0);
406     range =  fGETWORD(0, RssV);
407     offset = fGETWORD(1, RssV);
408 
409     /* calculate rLPS */
410     range <<= bitpos;
411     offset <<= bitpos;
412     rLPS = rLPS_table_64x4[state][(range >> 29) & 3];
413     rLPS  = rLPS << 23;   /* left aligned */
414 
415     /* calculate rMPS */
416     rMPS = (range & 0xff800000) - rLPS;
417 
418     /* most probable region */
419     if (offset < rMPS) {
420         RddV = AC_next_state_MPS_64[state];
421         fINSERT_RANGE(RddV, 8, 8, valMPS);
422         fINSERT_RANGE(RddV, 31, 23, (rMPS >> 23));
423         fSETWORD(1, RddV, offset);
424     }
425     /* least probable region */
426     else {
427         RddV = AC_next_state_LPS_64[state];
428         fINSERT_RANGE(RddV, 8, 8, ((!state) ? (1 - valMPS) : (valMPS)));
429         fINSERT_RANGE(RddV, 31, 23, (rLPS >> 23));
430         fSETWORD(1, RddV, (offset - rMPS));
431     }
432     return RddV;
433 }
434 
435 int32_t HELPER(cabacdecbin_pred)(int64_t RssV, int64_t RttV)
436 {
437     int32_t p0 = 0;
438     size4u_t state;
439     size4u_t valMPS;
440     size4u_t bitpos;
441     size4u_t range;
442     size4u_t offset;
443     size4u_t rLPS;
444     size4u_t rMPS;
445 
446     state =  fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0);
447     valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8);
448     bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0);
449     range =  fGETWORD(0, RssV);
450     offset = fGETWORD(1, RssV);
451 
452     /* calculate rLPS */
453     range <<= bitpos;
454     offset <<= bitpos;
455     rLPS = rLPS_table_64x4[state][(range >> 29) & 3];
456     rLPS  = rLPS << 23;   /* left aligned */
457 
458     /* calculate rMPS */
459     rMPS = (range & 0xff800000) - rLPS;
460 
461     /* most probable region */
462     if (offset < rMPS) {
463         p0 = valMPS;
464 
465     }
466     /* least probable region */
467     else {
468         p0 = valMPS ^ 1;
469     }
470     return p0;
471 }
472 
473 static void probe_store(CPUHexagonState *env, int slot, int mmu_idx,
474                         bool is_predicated, uintptr_t retaddr)
475 {
476     if (!is_predicated || !(env->slot_cancelled & (1 << slot))) {
477         size1u_t width = env->mem_log_stores[slot].width;
478         target_ulong va = env->mem_log_stores[slot].va;
479         probe_write(env, va, width, mmu_idx, retaddr);
480     }
481 }
482 
483 /*
484  * Called from a mem_noshuf packet to make sure the load doesn't
485  * raise an exception
486  */
487 void HELPER(probe_noshuf_load)(CPUHexagonState *env, target_ulong va,
488                                int size, int mmu_idx)
489 {
490     uintptr_t retaddr = GETPC();
491     probe_read(env, va, size, mmu_idx, retaddr);
492 }
493 
494 /* Called during packet commit when there are two scalar stores */
495 void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int args)
496 {
497     int mmu_idx = FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, MMU_IDX);
498     bool is_predicated =
499         FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, IS_PREDICATED);
500     uintptr_t ra = GETPC();
501     probe_store(env, 0, mmu_idx, is_predicated, ra);
502 }
503 
504 static void probe_hvx_stores(CPUHexagonState *env, int mmu_idx,
505                                     uintptr_t retaddr)
506 {
507     /* Normal (possibly masked) vector store */
508     for (int i = 0; i < VSTORES_MAX; i++) {
509         if (env->vstore_pending[i]) {
510             target_ulong va = env->vstore[i].va;
511             int size = env->vstore[i].size;
512             for (int j = 0; j < size; j++) {
513                 if (test_bit(j, env->vstore[i].mask)) {
514                     probe_write(env, va + j, 1, mmu_idx, retaddr);
515                 }
516             }
517         }
518     }
519 
520     /* Scatter store */
521     if (env->vtcm_pending) {
522         if (env->vtcm_log.op) {
523             /* Need to perform the scatter read/modify/write at commit time */
524             if (env->vtcm_log.op_size == 2) {
525                 SCATTER_OP_PROBE_MEM(size2u_t, mmu_idx, retaddr);
526             } else if (env->vtcm_log.op_size == 4) {
527                 /* Word Scatter += */
528                 SCATTER_OP_PROBE_MEM(size4u_t, mmu_idx, retaddr);
529             } else {
530                 g_assert_not_reached();
531             }
532         } else {
533             for (int i = 0; i < sizeof(MMVector); i++) {
534                 if (test_bit(i, env->vtcm_log.mask)) {
535                     probe_write(env, env->vtcm_log.va[i], 1, mmu_idx, retaddr);
536                 }
537 
538             }
539         }
540     }
541 }
542 
543 void HELPER(probe_hvx_stores)(CPUHexagonState *env, int mmu_idx)
544 {
545     uintptr_t retaddr = GETPC();
546     probe_hvx_stores(env, mmu_idx, retaddr);
547 }
548 
549 void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask)
550 {
551     bool has_st0 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST0);
552     bool has_st1 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST1);
553     bool has_hvx_stores =
554         FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_HVX_STORES);
555     bool s0_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED);
556     bool s1_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED);
557     int mmu_idx = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX);
558     uintptr_t ra = GETPC();
559 
560     if (has_st0) {
561         probe_store(env, 0, mmu_idx, s0_is_pred, ra);
562     }
563     if (has_st1) {
564         probe_store(env, 1, mmu_idx, s1_is_pred, ra);
565     }
566     if (has_hvx_stores) {
567         probe_hvx_stores(env, mmu_idx, ra);
568     }
569 }
570 
571 #ifndef CONFIG_HEXAGON_IDEF_PARSER
572 /*
573  * mem_noshuf
574  * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
575  *
576  * If the load is in slot 0 and there is a store in slot1 (that
577  * wasn't cancelled), we have to do the store first.
578  */
579 static void check_noshuf(CPUHexagonState *env, bool pkt_has_store_s1,
580                          uint32_t slot, target_ulong vaddr, int size,
581                          uintptr_t ra)
582 {
583     if (slot == 0 && pkt_has_store_s1 &&
584         ((env->slot_cancelled & (1 << 1)) == 0)) {
585         probe_read(env, vaddr, size, MMU_USER_IDX, ra);
586         commit_store(env, 1, ra);
587     }
588 }
589 #endif
590 
591 /* Floating point */
592 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
593 {
594     float64 out_f64;
595     arch_fpop_start(env);
596     out_f64 = float32_to_float64(RsV, &env->fp_status);
597     arch_fpop_end(env);
598     return out_f64;
599 }
600 
601 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
602 {
603     float32 out_f32;
604     arch_fpop_start(env);
605     out_f32 = float64_to_float32(RssV, &env->fp_status);
606     arch_fpop_end(env);
607     return out_f32;
608 }
609 
610 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
611 {
612     float32 RdV;
613     arch_fpop_start(env);
614     RdV = uint32_to_float32(RsV, &env->fp_status);
615     arch_fpop_end(env);
616     return RdV;
617 }
618 
619 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
620 {
621     float64 RddV;
622     arch_fpop_start(env);
623     RddV = uint32_to_float64(RsV, &env->fp_status);
624     arch_fpop_end(env);
625     return RddV;
626 }
627 
628 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
629 {
630     float32 RdV;
631     arch_fpop_start(env);
632     RdV = int32_to_float32(RsV, &env->fp_status);
633     arch_fpop_end(env);
634     return RdV;
635 }
636 
637 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
638 {
639     float64 RddV;
640     arch_fpop_start(env);
641     RddV = int32_to_float64(RsV, &env->fp_status);
642     arch_fpop_end(env);
643     return RddV;
644 }
645 
646 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
647 {
648     float32 RdV;
649     arch_fpop_start(env);
650     RdV = uint64_to_float32(RssV, &env->fp_status);
651     arch_fpop_end(env);
652     return RdV;
653 }
654 
655 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
656 {
657     float64 RddV;
658     arch_fpop_start(env);
659     RddV = uint64_to_float64(RssV, &env->fp_status);
660     arch_fpop_end(env);
661     return RddV;
662 }
663 
664 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
665 {
666     float32 RdV;
667     arch_fpop_start(env);
668     RdV = int64_to_float32(RssV, &env->fp_status);
669     arch_fpop_end(env);
670     return RdV;
671 }
672 
673 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
674 {
675     float64 RddV;
676     arch_fpop_start(env);
677     RddV = int64_to_float64(RssV, &env->fp_status);
678     arch_fpop_end(env);
679     return RddV;
680 }
681 
682 uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
683 {
684     uint32_t RdV;
685     arch_fpop_start(env);
686     /* Hexagon checks the sign before rounding */
687     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
688         float_raise(float_flag_invalid, &env->fp_status);
689         RdV = 0;
690     } else {
691         RdV = float32_to_uint32(RsV, &env->fp_status);
692     }
693     arch_fpop_end(env);
694     return RdV;
695 }
696 
697 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
698 {
699     int32_t RdV;
700     arch_fpop_start(env);
701     /* Hexagon returns -1 for NaN */
702     if (float32_is_any_nan(RsV)) {
703         float_raise(float_flag_invalid, &env->fp_status);
704         RdV = -1;
705     } else {
706         RdV = float32_to_int32(RsV, &env->fp_status);
707     }
708     arch_fpop_end(env);
709     return RdV;
710 }
711 
712 uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
713 {
714     uint64_t RddV;
715     arch_fpop_start(env);
716     /* Hexagon checks the sign before rounding */
717     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
718         float_raise(float_flag_invalid, &env->fp_status);
719         RddV = 0;
720     } else {
721         RddV = float32_to_uint64(RsV, &env->fp_status);
722     }
723     arch_fpop_end(env);
724     return RddV;
725 }
726 
727 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
728 {
729     int64_t RddV;
730     arch_fpop_start(env);
731     /* Hexagon returns -1 for NaN */
732     if (float32_is_any_nan(RsV)) {
733         float_raise(float_flag_invalid, &env->fp_status);
734         RddV = -1;
735     } else {
736         RddV = float32_to_int64(RsV, &env->fp_status);
737     }
738     arch_fpop_end(env);
739     return RddV;
740 }
741 
742 uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
743 {
744     uint32_t RdV;
745     arch_fpop_start(env);
746     /* Hexagon checks the sign before rounding */
747     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
748         float_raise(float_flag_invalid, &env->fp_status);
749         RdV = 0;
750     } else {
751         RdV = float64_to_uint32(RssV, &env->fp_status);
752     }
753     arch_fpop_end(env);
754     return RdV;
755 }
756 
757 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
758 {
759     int32_t RdV;
760     arch_fpop_start(env);
761     /* Hexagon returns -1 for NaN */
762     if (float64_is_any_nan(RssV)) {
763         float_raise(float_flag_invalid, &env->fp_status);
764         RdV = -1;
765     } else {
766         RdV = float64_to_int32(RssV, &env->fp_status);
767     }
768     arch_fpop_end(env);
769     return RdV;
770 }
771 
772 uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
773 {
774     uint64_t RddV;
775     arch_fpop_start(env);
776     /* Hexagon checks the sign before rounding */
777     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
778         float_raise(float_flag_invalid, &env->fp_status);
779         RddV = 0;
780     } else {
781         RddV = float64_to_uint64(RssV, &env->fp_status);
782     }
783     arch_fpop_end(env);
784     return RddV;
785 }
786 
787 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
788 {
789     int64_t RddV;
790     arch_fpop_start(env);
791     /* Hexagon returns -1 for NaN */
792     if (float64_is_any_nan(RssV)) {
793         float_raise(float_flag_invalid, &env->fp_status);
794         RddV = -1;
795     } else {
796         RddV = float64_to_int64(RssV, &env->fp_status);
797     }
798     arch_fpop_end(env);
799     return RddV;
800 }
801 
802 uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
803 {
804     uint32_t RdV;
805     arch_fpop_start(env);
806     /* Hexagon checks the sign before rounding */
807     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
808         float_raise(float_flag_invalid, &env->fp_status);
809         RdV = 0;
810     } else {
811         RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
812     }
813     arch_fpop_end(env);
814     return RdV;
815 }
816 
817 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
818 {
819     int32_t RdV;
820     arch_fpop_start(env);
821     /* Hexagon returns -1 for NaN */
822     if (float32_is_any_nan(RsV)) {
823         float_raise(float_flag_invalid, &env->fp_status);
824         RdV = -1;
825     } else {
826         RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
827     }
828     arch_fpop_end(env);
829     return RdV;
830 }
831 
832 uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
833 {
834     uint64_t RddV;
835     arch_fpop_start(env);
836     /* Hexagon checks the sign before rounding */
837     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
838         float_raise(float_flag_invalid, &env->fp_status);
839         RddV = 0;
840     } else {
841         RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
842     }
843     arch_fpop_end(env);
844     return RddV;
845 }
846 
847 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
848 {
849     int64_t RddV;
850     arch_fpop_start(env);
851     /* Hexagon returns -1 for NaN */
852     if (float32_is_any_nan(RsV)) {
853         float_raise(float_flag_invalid, &env->fp_status);
854         RddV = -1;
855     } else {
856         RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
857     }
858     arch_fpop_end(env);
859     return RddV;
860 }
861 
862 uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
863 {
864     uint32_t RdV;
865     arch_fpop_start(env);
866     /* Hexagon checks the sign before rounding */
867     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
868         float_raise(float_flag_invalid, &env->fp_status);
869         RdV = 0;
870     } else {
871         RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
872     }
873     arch_fpop_end(env);
874     return RdV;
875 }
876 
877 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
878 {
879     int32_t RdV;
880     arch_fpop_start(env);
881     /* Hexagon returns -1 for NaN */
882     if (float64_is_any_nan(RssV)) {
883         float_raise(float_flag_invalid, &env->fp_status);
884         RdV = -1;
885     } else {
886         RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
887     }
888     arch_fpop_end(env);
889     return RdV;
890 }
891 
892 uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
893 {
894     uint64_t RddV;
895     arch_fpop_start(env);
896     /* Hexagon checks the sign before rounding */
897     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
898         float_raise(float_flag_invalid, &env->fp_status);
899         RddV = 0;
900     } else {
901         RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
902     }
903     arch_fpop_end(env);
904     return RddV;
905 }
906 
907 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
908 {
909     int64_t RddV;
910     arch_fpop_start(env);
911     /* Hexagon returns -1 for NaN */
912     if (float64_is_any_nan(RssV)) {
913         float_raise(float_flag_invalid, &env->fp_status);
914         RddV = -1;
915     } else {
916         RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
917     }
918     arch_fpop_end(env);
919     return RddV;
920 }
921 
922 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
923 {
924     float32 RdV;
925     arch_fpop_start(env);
926     RdV = float32_add(RsV, RtV, &env->fp_status);
927     arch_fpop_end(env);
928     return RdV;
929 }
930 
931 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
932 {
933     float32 RdV;
934     arch_fpop_start(env);
935     RdV = float32_sub(RsV, RtV, &env->fp_status);
936     arch_fpop_end(env);
937     return RdV;
938 }
939 
940 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
941 {
942     int32_t PdV;
943     arch_fpop_start(env);
944     PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
945     arch_fpop_end(env);
946     return PdV;
947 }
948 
949 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
950 {
951     int cmp;
952     int32_t PdV;
953     arch_fpop_start(env);
954     cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
955     PdV = f8BITSOF(cmp == float_relation_greater);
956     arch_fpop_end(env);
957     return PdV;
958 }
959 
960 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
961 {
962     int cmp;
963     int32_t PdV;
964     arch_fpop_start(env);
965     cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
966     PdV = f8BITSOF(cmp == float_relation_greater ||
967                    cmp == float_relation_equal);
968     arch_fpop_end(env);
969     return PdV;
970 }
971 
972 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
973 {
974     int32_t PdV;
975     arch_fpop_start(env);
976     PdV = f8BITSOF(float32_unordered_quiet(RsV, RtV, &env->fp_status));
977     arch_fpop_end(env);
978     return PdV;
979 }
980 
981 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
982 {
983     float32 RdV;
984     arch_fpop_start(env);
985     RdV = float32_maximum_number(RsV, RtV, &env->fp_status);
986     arch_fpop_end(env);
987     return RdV;
988 }
989 
990 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
991 {
992     float32 RdV;
993     arch_fpop_start(env);
994     RdV = float32_minimum_number(RsV, RtV, &env->fp_status);
995     arch_fpop_end(env);
996     return RdV;
997 }
998 
999 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
1000 {
1001     int32_t PdV = 0;
1002     arch_fpop_start(env);
1003     if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
1004         PdV = 0xff;
1005     }
1006     if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
1007         PdV = 0xff;
1008     }
1009     if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
1010         PdV = 0xff;
1011     }
1012     if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
1013         PdV = 0xff;
1014     }
1015     if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
1016         PdV = 0xff;
1017     }
1018     set_float_exception_flags(0, &env->fp_status);
1019     arch_fpop_end(env);
1020     return PdV;
1021 }
1022 
1023 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
1024 {
1025     float32 RdV = 0;
1026     int adjust;
1027     arch_fpop_start(env);
1028     arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
1029     RdV = RsV;
1030     arch_fpop_end(env);
1031     return RdV;
1032 }
1033 
1034 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
1035 {
1036     float32 RdV = 0;
1037     int adjust;
1038     arch_fpop_start(env);
1039     arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
1040     RdV = RtV;
1041     arch_fpop_end(env);
1042     return RdV;
1043 }
1044 
1045 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
1046 {
1047     float32 RdV = 0;
1048     int adjust;
1049     arch_fpop_start(env);
1050     arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
1051     RdV = RsV;
1052     arch_fpop_end(env);
1053     return RdV;
1054 }
1055 
1056 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
1057 {
1058     float64 RddV;
1059     arch_fpop_start(env);
1060     RddV = float64_add(RssV, RttV, &env->fp_status);
1061     arch_fpop_end(env);
1062     return RddV;
1063 }
1064 
1065 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
1066 {
1067     float64 RddV;
1068     arch_fpop_start(env);
1069     RddV = float64_sub(RssV, RttV, &env->fp_status);
1070     arch_fpop_end(env);
1071     return RddV;
1072 }
1073 
1074 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
1075 {
1076     float64 RddV;
1077     arch_fpop_start(env);
1078     RddV = float64_maximum_number(RssV, RttV, &env->fp_status);
1079     arch_fpop_end(env);
1080     return RddV;
1081 }
1082 
1083 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
1084 {
1085     float64 RddV;
1086     arch_fpop_start(env);
1087     RddV = float64_minimum_number(RssV, RttV, &env->fp_status);
1088     arch_fpop_end(env);
1089     return RddV;
1090 }
1091 
1092 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
1093 {
1094     int32_t PdV;
1095     arch_fpop_start(env);
1096     PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
1097     arch_fpop_end(env);
1098     return PdV;
1099 }
1100 
1101 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
1102 {
1103     int cmp;
1104     int32_t PdV;
1105     arch_fpop_start(env);
1106     cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
1107     PdV = f8BITSOF(cmp == float_relation_greater);
1108     arch_fpop_end(env);
1109     return PdV;
1110 }
1111 
1112 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
1113 {
1114     int cmp;
1115     int32_t PdV;
1116     arch_fpop_start(env);
1117     cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
1118     PdV = f8BITSOF(cmp == float_relation_greater ||
1119                    cmp == float_relation_equal);
1120     arch_fpop_end(env);
1121     return PdV;
1122 }
1123 
1124 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
1125 {
1126     int32_t PdV;
1127     arch_fpop_start(env);
1128     PdV = f8BITSOF(float64_unordered_quiet(RssV, RttV, &env->fp_status));
1129     arch_fpop_end(env);
1130     return PdV;
1131 }
1132 
1133 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
1134 {
1135     int32_t PdV = 0;
1136     arch_fpop_start(env);
1137     if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
1138         PdV = 0xff;
1139     }
1140     if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
1141         PdV = 0xff;
1142     }
1143     if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
1144         PdV = 0xff;
1145     }
1146     if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
1147         PdV = 0xff;
1148     }
1149     if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
1150         PdV = 0xff;
1151     }
1152     set_float_exception_flags(0, &env->fp_status);
1153     arch_fpop_end(env);
1154     return PdV;
1155 }
1156 
1157 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
1158 {
1159     float32 RdV;
1160     arch_fpop_start(env);
1161     RdV = internal_mpyf(RsV, RtV, &env->fp_status);
1162     arch_fpop_end(env);
1163     return RdV;
1164 }
1165 
1166 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
1167                       float32 RsV, float32 RtV)
1168 {
1169     arch_fpop_start(env);
1170     RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1171     arch_fpop_end(env);
1172     return RxV;
1173 }
1174 
1175 static bool is_zero_prod(float32 a, float32 b)
1176 {
1177     return ((float32_is_zero(a) && is_finite(b)) ||
1178             (float32_is_zero(b) && is_finite(a)));
1179 }
1180 
1181 static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
1182 {
1183     float32 ret = dst;
1184     if (float32_is_any_nan(x)) {
1185         if (extract32(x, 22, 1) == 0) {
1186             float_raise(float_flag_invalid, fp_status);
1187         }
1188         ret = make_float32(0xffffffff);    /* nan */
1189     }
1190     return ret;
1191 }
1192 
1193 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
1194                          float32 RsV, float32 RtV, float32 PuV)
1195 {
1196     size4s_t tmp;
1197     arch_fpop_start(env);
1198     RxV = check_nan(RxV, RxV, &env->fp_status);
1199     RxV = check_nan(RxV, RsV, &env->fp_status);
1200     RxV = check_nan(RxV, RtV, &env->fp_status);
1201     tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
1202     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1203         RxV = tmp;
1204     }
1205     arch_fpop_end(env);
1206     return RxV;
1207 }
1208 
1209 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
1210                       float32 RsV, float32 RtV)
1211 {
1212     float32 neg_RsV;
1213     arch_fpop_start(env);
1214     neg_RsV = float32_set_sign(RsV, float32_is_neg(RsV) ? 0 : 1);
1215     RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
1216     arch_fpop_end(env);
1217     return RxV;
1218 }
1219 
1220 static bool is_inf_prod(int32_t a, int32_t b)
1221 {
1222     return (float32_is_infinity(a) && float32_is_infinity(b)) ||
1223            (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
1224            (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
1225 }
1226 
1227 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
1228                           float32 RsV, float32 RtV)
1229 {
1230     bool infinp;
1231     bool infminusinf;
1232     float32 tmp;
1233 
1234     arch_fpop_start(env);
1235     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1236     infminusinf = float32_is_infinity(RxV) &&
1237                   is_inf_prod(RsV, RtV) &&
1238                   (fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
1239     infinp = float32_is_infinity(RxV) ||
1240              float32_is_infinity(RtV) ||
1241              float32_is_infinity(RsV);
1242     RxV = check_nan(RxV, RxV, &env->fp_status);
1243     RxV = check_nan(RxV, RsV, &env->fp_status);
1244     RxV = check_nan(RxV, RtV, &env->fp_status);
1245     tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1246     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1247         RxV = tmp;
1248     }
1249     set_float_exception_flags(0, &env->fp_status);
1250     if (float32_is_infinity(RxV) && !infinp) {
1251         RxV = RxV - 1;
1252     }
1253     if (infminusinf) {
1254         RxV = 0;
1255     }
1256     arch_fpop_end(env);
1257     return RxV;
1258 }
1259 
1260 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
1261                           float32 RsV, float32 RtV)
1262 {
1263     bool infinp;
1264     bool infminusinf;
1265     float32 tmp;
1266 
1267     arch_fpop_start(env);
1268     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1269     infminusinf = float32_is_infinity(RxV) &&
1270                   is_inf_prod(RsV, RtV) &&
1271                   (fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
1272     infinp = float32_is_infinity(RxV) ||
1273              float32_is_infinity(RtV) ||
1274              float32_is_infinity(RsV);
1275     RxV = check_nan(RxV, RxV, &env->fp_status);
1276     RxV = check_nan(RxV, RsV, &env->fp_status);
1277     RxV = check_nan(RxV, RtV, &env->fp_status);
1278     float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1279     tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
1280     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1281         RxV = tmp;
1282     }
1283     set_float_exception_flags(0, &env->fp_status);
1284     if (float32_is_infinity(RxV) && !infinp) {
1285         RxV = RxV - 1;
1286     }
1287     if (infminusinf) {
1288         RxV = 0;
1289     }
1290     arch_fpop_end(env);
1291     return RxV;
1292 }
1293 
1294 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
1295 {
1296     int64_t RddV;
1297     arch_fpop_start(env);
1298     if (float64_is_denormal(RssV) &&
1299         (float64_getexp(RttV) >= 512) &&
1300         float64_is_normal(RttV)) {
1301         RddV = float64_mul(RssV, make_float64(0x4330000000000000),
1302                            &env->fp_status);
1303     } else if (float64_is_denormal(RttV) &&
1304                (float64_getexp(RssV) >= 512) &&
1305                float64_is_normal(RssV)) {
1306         RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
1307                            &env->fp_status);
1308     } else {
1309         RddV = RssV;
1310     }
1311     arch_fpop_end(env);
1312     return RddV;
1313 }
1314 
1315 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
1316                         float64 RssV, float64 RttV)
1317 {
1318     arch_fpop_start(env);
1319     RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
1320     arch_fpop_end(env);
1321     return RxxV;
1322 }
1323 
1324 /* Histogram instructions */
1325 
1326 void HELPER(vhist)(CPUHexagonState *env)
1327 {
1328     MMVector *input = &env->tmp_VRegs[0];
1329 
1330     for (int lane = 0; lane < 8; lane++) {
1331         for (int i = 0; i < sizeof(MMVector) / 8; ++i) {
1332             unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i];
1333             unsigned char regno = value >> 3;
1334             unsigned char element = value & 7;
1335 
1336             env->VRegs[regno].uh[(sizeof(MMVector) / 16) * lane + element]++;
1337         }
1338     }
1339 }
1340 
1341 void HELPER(vhistq)(CPUHexagonState *env)
1342 {
1343     MMVector *input = &env->tmp_VRegs[0];
1344 
1345     for (int lane = 0; lane < 8; lane++) {
1346         for (int i = 0; i < sizeof(MMVector) / 8; ++i) {
1347             unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i];
1348             unsigned char regno = value >> 3;
1349             unsigned char element = value & 7;
1350 
1351             if (fGETQBIT(env->qtmp, sizeof(MMVector) / 8 * lane + i)) {
1352                 env->VRegs[regno].uh[
1353                     (sizeof(MMVector) / 16) * lane + element]++;
1354             }
1355         }
1356     }
1357 }
1358 
1359 void HELPER(vwhist256)(CPUHexagonState *env)
1360 {
1361     MMVector *input = &env->tmp_VRegs[0];
1362 
1363     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1364         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1365         unsigned int weight = fGETUBYTE(1, input->h[i]);
1366         unsigned int vindex = (bucket >> 3) & 0x1F;
1367         unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1368 
1369         env->VRegs[vindex].uh[elindex] =
1370             env->VRegs[vindex].uh[elindex] + weight;
1371     }
1372 }
1373 
1374 void HELPER(vwhist256q)(CPUHexagonState *env)
1375 {
1376     MMVector *input = &env->tmp_VRegs[0];
1377 
1378     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1379         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1380         unsigned int weight = fGETUBYTE(1, input->h[i]);
1381         unsigned int vindex = (bucket >> 3) & 0x1F;
1382         unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1383 
1384         if (fGETQBIT(env->qtmp, 2 * i)) {
1385             env->VRegs[vindex].uh[elindex] =
1386                 env->VRegs[vindex].uh[elindex] + weight;
1387         }
1388     }
1389 }
1390 
1391 void HELPER(vwhist256_sat)(CPUHexagonState *env)
1392 {
1393     MMVector *input = &env->tmp_VRegs[0];
1394 
1395     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1396         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1397         unsigned int weight = fGETUBYTE(1, input->h[i]);
1398         unsigned int vindex = (bucket >> 3) & 0x1F;
1399         unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1400 
1401         env->VRegs[vindex].uh[elindex] =
1402             fVSATUH(env->VRegs[vindex].uh[elindex] + weight);
1403     }
1404 }
1405 
1406 void HELPER(vwhist256q_sat)(CPUHexagonState *env)
1407 {
1408     MMVector *input = &env->tmp_VRegs[0];
1409 
1410     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1411         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1412         unsigned int weight = fGETUBYTE(1, input->h[i]);
1413         unsigned int vindex = (bucket >> 3) & 0x1F;
1414         unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1415 
1416         if (fGETQBIT(env->qtmp, 2 * i)) {
1417             env->VRegs[vindex].uh[elindex] =
1418                 fVSATUH(env->VRegs[vindex].uh[elindex] + weight);
1419         }
1420     }
1421 }
1422 
1423 void HELPER(vwhist128)(CPUHexagonState *env)
1424 {
1425     MMVector *input = &env->tmp_VRegs[0];
1426 
1427     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1428         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1429         unsigned int weight = fGETUBYTE(1, input->h[i]);
1430         unsigned int vindex = (bucket >> 3) & 0x1F;
1431         unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1432 
1433         env->VRegs[vindex].uw[elindex] =
1434             env->VRegs[vindex].uw[elindex] + weight;
1435     }
1436 }
1437 
1438 void HELPER(vwhist128q)(CPUHexagonState *env)
1439 {
1440     MMVector *input = &env->tmp_VRegs[0];
1441 
1442     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1443         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1444         unsigned int weight = fGETUBYTE(1, input->h[i]);
1445         unsigned int vindex = (bucket >> 3) & 0x1F;
1446         unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1447 
1448         if (fGETQBIT(env->qtmp, 2 * i)) {
1449             env->VRegs[vindex].uw[elindex] =
1450                 env->VRegs[vindex].uw[elindex] + weight;
1451         }
1452     }
1453 }
1454 
1455 void HELPER(vwhist128m)(CPUHexagonState *env, int32_t uiV)
1456 {
1457     MMVector *input = &env->tmp_VRegs[0];
1458 
1459     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1460         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1461         unsigned int weight = fGETUBYTE(1, input->h[i]);
1462         unsigned int vindex = (bucket >> 3) & 0x1F;
1463         unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1464 
1465         if ((bucket & 1) == uiV) {
1466             env->VRegs[vindex].uw[elindex] =
1467                 env->VRegs[vindex].uw[elindex] + weight;
1468         }
1469     }
1470 }
1471 
1472 void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
1473 {
1474     MMVector *input = &env->tmp_VRegs[0];
1475 
1476     for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1477         unsigned int bucket = fGETUBYTE(0, input->h[i]);
1478         unsigned int weight = fGETUBYTE(1, input->h[i]);
1479         unsigned int vindex = (bucket >> 3) & 0x1F;
1480         unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1481 
1482         if (((bucket & 1) == uiV) && fGETQBIT(env->qtmp, 2 * i)) {
1483             env->VRegs[vindex].uw[elindex] =
1484                 env->VRegs[vindex].uw[elindex] + weight;
1485         }
1486     }
1487 }
1488 
1489 /* These macros can be referenced in the generated helper functions */
1490 #define warn(...) /* Nothing */
1491 #define fatal(...) g_assert_not_reached();
1492 
1493 #define BOGUS_HELPER(tag) \
1494     printf("ERROR: bogus helper: " #tag "\n")
1495 
1496 #include "helper_funcs_generated.c.inc"
1497