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