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