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