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