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