1 /* 2 * PowerPC floating point and SPE emulation helpers for QEMU. 3 * 4 * Copyright (c) 2003-2007 Jocelyn Mayer 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 #include "qemu/osdep.h" 20 #include "cpu.h" 21 #include "exec/helper-proto.h" 22 #include "exec/exec-all.h" 23 #include "internal.h" 24 #include "fpu/softfloat.h" 25 26 static inline float128 float128_snan_to_qnan(float128 x) 27 { 28 float128 r; 29 30 r.high = x.high | 0x0000800000000000; 31 r.low = x.low; 32 return r; 33 } 34 35 #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL) 36 #define float32_snan_to_qnan(x) ((x) | 0x00400000) 37 #define float16_snan_to_qnan(x) ((x) | 0x0200) 38 39 static inline float32 bfp32_neg(float32 a) 40 { 41 if (unlikely(float32_is_any_nan(a))) { 42 return a; 43 } else { 44 return float32_chs(a); 45 } 46 } 47 48 static inline bool fp_exceptions_enabled(CPUPPCState *env) 49 { 50 #ifdef CONFIG_USER_ONLY 51 return true; 52 #else 53 return (env->msr & ((1U << MSR_FE0) | (1U << MSR_FE1))) != 0; 54 #endif 55 } 56 57 /*****************************************************************************/ 58 /* Floating point operations helpers */ 59 60 /* 61 * This is the non-arithmatic conversion that happens e.g. on loads. 62 * In the Power ISA pseudocode, this is called DOUBLE. 63 */ 64 uint64_t helper_todouble(uint32_t arg) 65 { 66 uint32_t abs_arg = arg & 0x7fffffff; 67 uint64_t ret; 68 69 if (likely(abs_arg >= 0x00800000)) { 70 if (unlikely(extract32(arg, 23, 8) == 0xff)) { 71 /* Inf or NAN. */ 72 ret = (uint64_t)extract32(arg, 31, 1) << 63; 73 ret |= (uint64_t)0x7ff << 52; 74 ret |= (uint64_t)extract32(arg, 0, 23) << 29; 75 } else { 76 /* Normalized operand. */ 77 ret = (uint64_t)extract32(arg, 30, 2) << 62; 78 ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59; 79 ret |= (uint64_t)extract32(arg, 0, 30) << 29; 80 } 81 } else { 82 /* Zero or Denormalized operand. */ 83 ret = (uint64_t)extract32(arg, 31, 1) << 63; 84 if (unlikely(abs_arg != 0)) { 85 /* 86 * Denormalized operand. 87 * Shift fraction so that the msb is in the implicit bit position. 88 * Thus, shift is in the range [1:23]. 89 */ 90 int shift = clz32(abs_arg) - 8; 91 /* 92 * The first 3 terms compute the float64 exponent. We then bias 93 * this result by -1 so that we can swallow the implicit bit below. 94 */ 95 int exp = -126 - shift + 1023 - 1; 96 97 ret |= (uint64_t)exp << 52; 98 ret += (uint64_t)abs_arg << (52 - 23 + shift); 99 } 100 } 101 return ret; 102 } 103 104 /* 105 * This is the non-arithmatic conversion that happens e.g. on stores. 106 * In the Power ISA pseudocode, this is called SINGLE. 107 */ 108 uint32_t helper_tosingle(uint64_t arg) 109 { 110 int exp = extract64(arg, 52, 11); 111 uint32_t ret; 112 113 if (likely(exp > 896)) { 114 /* No denormalization required (includes Inf, NaN). */ 115 ret = extract64(arg, 62, 2) << 30; 116 ret |= extract64(arg, 29, 30); 117 } else { 118 /* 119 * Zero or Denormal result. If the exponent is in bounds for 120 * a single-precision denormal result, extract the proper 121 * bits. If the input is not zero, and the exponent is out of 122 * bounds, then the result is undefined; this underflows to 123 * zero. 124 */ 125 ret = extract64(arg, 63, 1) << 31; 126 if (unlikely(exp >= 874)) { 127 /* Denormal result. */ 128 ret |= ((1ULL << 52) | extract64(arg, 0, 52)) >> (896 + 30 - exp); 129 } 130 } 131 return ret; 132 } 133 134 static inline int ppc_float32_get_unbiased_exp(float32 f) 135 { 136 return ((f >> 23) & 0xFF) - 127; 137 } 138 139 static inline int ppc_float64_get_unbiased_exp(float64 f) 140 { 141 return ((f >> 52) & 0x7FF) - 1023; 142 } 143 144 #define COMPUTE_FPRF(tp) \ 145 void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \ 146 { \ 147 bool neg = tp##_is_neg(arg); \ 148 target_ulong fprf; \ 149 if (likely(tp##_is_normal(arg))) { \ 150 fprf = neg ? 0x08 << FPSCR_FPRF : 0x04 << FPSCR_FPRF; \ 151 } else if (tp##_is_zero(arg)) { \ 152 fprf = neg ? 0x12 << FPSCR_FPRF : 0x02 << FPSCR_FPRF; \ 153 } else if (tp##_is_zero_or_denormal(arg)) { \ 154 fprf = neg ? 0x18 << FPSCR_FPRF : 0x14 << FPSCR_FPRF; \ 155 } else if (tp##_is_infinity(arg)) { \ 156 fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \ 157 } else { \ 158 if (tp##_is_signaling_nan(arg, &env->fp_status)) { \ 159 fprf = 0x00 << FPSCR_FPRF; \ 160 } else { \ 161 fprf = 0x11 << FPSCR_FPRF; \ 162 } \ 163 } \ 164 env->fpscr = (env->fpscr & ~FP_FPRF) | fprf; \ 165 } 166 167 COMPUTE_FPRF(float16) 168 COMPUTE_FPRF(float32) 169 COMPUTE_FPRF(float64) 170 COMPUTE_FPRF(float128) 171 172 /* Floating-point invalid operations exception */ 173 static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) 174 { 175 /* Update the floating-point invalid operation summary */ 176 env->fpscr |= FP_VX; 177 /* Update the floating-point exception summary */ 178 env->fpscr |= FP_FX; 179 if (env->fpscr & FP_VE) { 180 /* Update the floating-point enabled exception summary */ 181 env->fpscr |= FP_FEX; 182 if (fp_exceptions_enabled(env)) { 183 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 184 POWERPC_EXCP_FP | op, retaddr); 185 } 186 } 187 } 188 189 static void finish_invalid_op_arith(CPUPPCState *env, int op, 190 bool set_fpcc, uintptr_t retaddr) 191 { 192 env->fpscr &= ~(FP_FR | FP_FI); 193 if (!(env->fpscr & FP_VE)) { 194 if (set_fpcc) { 195 env->fpscr &= ~FP_FPCC; 196 env->fpscr |= (FP_C | FP_FU); 197 } 198 } 199 finish_invalid_op_excp(env, op, retaddr); 200 } 201 202 /* Signalling NaN */ 203 static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) 204 { 205 env->fpscr |= FP_VXSNAN; 206 finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr); 207 } 208 209 /* Magnitude subtraction of infinities */ 210 static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, 211 uintptr_t retaddr) 212 { 213 env->fpscr |= FP_VXISI; 214 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr); 215 } 216 217 /* Division of infinity by infinity */ 218 static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, 219 uintptr_t retaddr) 220 { 221 env->fpscr |= FP_VXIDI; 222 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr); 223 } 224 225 /* Division of zero by zero */ 226 static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, 227 uintptr_t retaddr) 228 { 229 env->fpscr |= FP_VXZDZ; 230 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr); 231 } 232 233 /* Multiplication of zero by infinity */ 234 static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, 235 uintptr_t retaddr) 236 { 237 env->fpscr |= FP_VXIMZ; 238 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr); 239 } 240 241 /* Square root of a negative number */ 242 static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, 243 uintptr_t retaddr) 244 { 245 env->fpscr |= FP_VXSQRT; 246 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr); 247 } 248 249 /* Ordered comparison of NaN */ 250 static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, 251 uintptr_t retaddr) 252 { 253 env->fpscr |= FP_VXVC; 254 if (set_fpcc) { 255 env->fpscr &= ~FP_FPCC; 256 env->fpscr |= (FP_C | FP_FU); 257 } 258 /* Update the floating-point invalid operation summary */ 259 env->fpscr |= FP_VX; 260 /* Update the floating-point exception summary */ 261 env->fpscr |= FP_FX; 262 /* We must update the target FPR before raising the exception */ 263 if (env->fpscr & FP_VE) { 264 CPUState *cs = env_cpu(env); 265 266 cs->exception_index = POWERPC_EXCP_PROGRAM; 267 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; 268 /* Update the floating-point enabled exception summary */ 269 env->fpscr |= FP_FEX; 270 /* Exception is deferred */ 271 } 272 } 273 274 /* Invalid conversion */ 275 static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, 276 uintptr_t retaddr) 277 { 278 env->fpscr |= FP_VXCVI; 279 env->fpscr &= ~(FP_FR | FP_FI); 280 if (!(env->fpscr & FP_VE)) { 281 if (set_fpcc) { 282 env->fpscr &= ~FP_FPCC; 283 env->fpscr |= (FP_C | FP_FU); 284 } 285 } 286 finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr); 287 } 288 289 static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) 290 { 291 env->fpscr |= FP_ZX; 292 env->fpscr &= ~(FP_FR | FP_FI); 293 /* Update the floating-point exception summary */ 294 env->fpscr |= FP_FX; 295 if (env->fpscr & FP_ZE) { 296 /* Update the floating-point enabled exception summary */ 297 env->fpscr |= FP_FEX; 298 if (fp_exceptions_enabled(env)) { 299 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 300 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, 301 raddr); 302 } 303 } 304 } 305 306 static inline int float_overflow_excp(CPUPPCState *env) 307 { 308 CPUState *cs = env_cpu(env); 309 310 env->fpscr |= FP_OX; 311 /* Update the floating-point exception summary */ 312 env->fpscr |= FP_FX; 313 314 bool overflow_enabled = !!(env->fpscr & FP_OE); 315 if (overflow_enabled) { 316 /* Update the floating-point enabled exception summary */ 317 env->fpscr |= FP_FEX; 318 /* We must update the target FPR before raising the exception */ 319 cs->exception_index = POWERPC_EXCP_PROGRAM; 320 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; 321 } 322 323 return overflow_enabled ? 0 : float_flag_inexact; 324 } 325 326 static inline void float_underflow_excp(CPUPPCState *env) 327 { 328 CPUState *cs = env_cpu(env); 329 330 env->fpscr |= FP_UX; 331 /* Update the floating-point exception summary */ 332 env->fpscr |= FP_FX; 333 if (env->fpscr & FP_UE) { 334 /* Update the floating-point enabled exception summary */ 335 env->fpscr |= FP_FEX; 336 /* We must update the target FPR before raising the exception */ 337 cs->exception_index = POWERPC_EXCP_PROGRAM; 338 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; 339 } 340 } 341 342 static inline void float_inexact_excp(CPUPPCState *env) 343 { 344 CPUState *cs = env_cpu(env); 345 346 env->fpscr |= FP_XX; 347 /* Update the floating-point exception summary */ 348 env->fpscr |= FP_FX; 349 if (env->fpscr & FP_XE) { 350 /* Update the floating-point enabled exception summary */ 351 env->fpscr |= FP_FEX; 352 /* We must update the target FPR before raising the exception */ 353 cs->exception_index = POWERPC_EXCP_PROGRAM; 354 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; 355 } 356 } 357 358 void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) 359 { 360 uint32_t mask = 1u << bit; 361 if (env->fpscr & mask) { 362 ppc_store_fpscr(env, env->fpscr & ~(target_ulong)mask); 363 } 364 } 365 366 void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) 367 { 368 uint32_t mask = 1u << bit; 369 if (!(env->fpscr & mask)) { 370 ppc_store_fpscr(env, env->fpscr | mask); 371 } 372 } 373 374 void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles) 375 { 376 target_ulong mask = 0; 377 int i; 378 379 /* TODO: push this extension back to translation time */ 380 for (i = 0; i < sizeof(target_ulong) * 2; i++) { 381 if (nibbles & (1 << i)) { 382 mask |= (target_ulong) 0xf << (4 * i); 383 } 384 } 385 val = (val & mask) | (env->fpscr & ~mask); 386 ppc_store_fpscr(env, val); 387 } 388 389 static void do_fpscr_check_status(CPUPPCState *env, uintptr_t raddr) 390 { 391 CPUState *cs = env_cpu(env); 392 target_ulong fpscr = env->fpscr; 393 int error = 0; 394 395 if ((fpscr & FP_OX) && (fpscr & FP_OE)) { 396 error = POWERPC_EXCP_FP_OX; 397 } else if ((fpscr & FP_UX) && (fpscr & FP_UE)) { 398 error = POWERPC_EXCP_FP_UX; 399 } else if ((fpscr & FP_XX) && (fpscr & FP_XE)) { 400 error = POWERPC_EXCP_FP_XX; 401 } else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) { 402 error = POWERPC_EXCP_FP_ZX; 403 } else if (fpscr & FP_VE) { 404 if (fpscr & FP_VXSOFT) { 405 error = POWERPC_EXCP_FP_VXSOFT; 406 } else if (fpscr & FP_VXSNAN) { 407 error = POWERPC_EXCP_FP_VXSNAN; 408 } else if (fpscr & FP_VXISI) { 409 error = POWERPC_EXCP_FP_VXISI; 410 } else if (fpscr & FP_VXIDI) { 411 error = POWERPC_EXCP_FP_VXIDI; 412 } else if (fpscr & FP_VXZDZ) { 413 error = POWERPC_EXCP_FP_VXZDZ; 414 } else if (fpscr & FP_VXIMZ) { 415 error = POWERPC_EXCP_FP_VXIMZ; 416 } else if (fpscr & FP_VXVC) { 417 error = POWERPC_EXCP_FP_VXVC; 418 } else if (fpscr & FP_VXSQRT) { 419 error = POWERPC_EXCP_FP_VXSQRT; 420 } else if (fpscr & FP_VXCVI) { 421 error = POWERPC_EXCP_FP_VXCVI; 422 } else { 423 return; 424 } 425 } else { 426 return; 427 } 428 cs->exception_index = POWERPC_EXCP_PROGRAM; 429 env->error_code = error | POWERPC_EXCP_FP; 430 env->fpscr |= FP_FEX; 431 /* Deferred floating-point exception after target FPSCR update */ 432 if (fp_exceptions_enabled(env)) { 433 raise_exception_err_ra(env, cs->exception_index, 434 env->error_code, raddr); 435 } 436 } 437 438 void helper_fpscr_check_status(CPUPPCState *env) 439 { 440 do_fpscr_check_status(env, GETPC()); 441 } 442 443 static void do_float_check_status(CPUPPCState *env, bool change_fi, 444 uintptr_t raddr) 445 { 446 CPUState *cs = env_cpu(env); 447 int status = get_float_exception_flags(&env->fp_status); 448 449 if (status & float_flag_overflow) { 450 status |= float_overflow_excp(env); 451 } else if (status & float_flag_underflow) { 452 float_underflow_excp(env); 453 } 454 if (status & float_flag_inexact) { 455 float_inexact_excp(env); 456 } 457 if (change_fi) { 458 env->fpscr = FIELD_DP64(env->fpscr, FPSCR, FI, 459 !!(status & float_flag_inexact)); 460 } 461 462 if (cs->exception_index == POWERPC_EXCP_PROGRAM && 463 (env->error_code & POWERPC_EXCP_FP)) { 464 /* Deferred floating-point exception after target FPR update */ 465 if (fp_exceptions_enabled(env)) { 466 raise_exception_err_ra(env, cs->exception_index, 467 env->error_code, raddr); 468 } 469 } 470 } 471 472 void helper_float_check_status(CPUPPCState *env) 473 { 474 do_float_check_status(env, true, GETPC()); 475 } 476 477 void helper_reset_fpstatus(CPUPPCState *env) 478 { 479 set_float_exception_flags(0, &env->fp_status); 480 } 481 482 static void float_invalid_op_addsub(CPUPPCState *env, int flags, 483 bool set_fpcc, uintptr_t retaddr) 484 { 485 if (flags & float_flag_invalid_isi) { 486 float_invalid_op_vxisi(env, set_fpcc, retaddr); 487 } else if (flags & float_flag_invalid_snan) { 488 float_invalid_op_vxsnan(env, retaddr); 489 } 490 } 491 492 static inline void addsub_flags_handler(CPUPPCState *env, int flags, 493 uintptr_t ra) 494 { 495 if (unlikely(flags & float_flag_invalid)) { 496 float_invalid_op_addsub(env, flags, 1, ra); 497 } 498 } 499 500 static void float_invalid_op_mul(CPUPPCState *env, int flags, 501 bool set_fprc, uintptr_t retaddr) 502 { 503 if (flags & float_flag_invalid_imz) { 504 float_invalid_op_vximz(env, set_fprc, retaddr); 505 } else if (flags & float_flag_invalid_snan) { 506 float_invalid_op_vxsnan(env, retaddr); 507 } 508 } 509 510 static inline void mul_flags_handler(CPUPPCState *env, int flags, uintptr_t ra) 511 { 512 if (unlikely(flags & float_flag_invalid)) { 513 float_invalid_op_mul(env, flags, 1, ra); 514 } 515 } 516 517 static void float_invalid_op_div(CPUPPCState *env, int flags, 518 bool set_fprc, uintptr_t retaddr) 519 { 520 if (flags & float_flag_invalid_idi) { 521 float_invalid_op_vxidi(env, set_fprc, retaddr); 522 } else if (flags & float_flag_invalid_zdz) { 523 float_invalid_op_vxzdz(env, set_fprc, retaddr); 524 } else if (flags & float_flag_invalid_snan) { 525 float_invalid_op_vxsnan(env, retaddr); 526 } 527 } 528 529 static inline void div_flags_handler(CPUPPCState *env, int flags, uintptr_t ra) 530 { 531 if (unlikely(flags & float_flag_invalid)) { 532 float_invalid_op_div(env, flags, 1, ra); 533 } 534 if (unlikely(flags & float_flag_divbyzero)) { 535 float_zero_divide_excp(env, ra); 536 } 537 } 538 539 static uint64_t float_invalid_cvt(CPUPPCState *env, int flags, 540 uint64_t ret, uint64_t ret_nan, 541 bool set_fprc, uintptr_t retaddr) 542 { 543 /* 544 * VXCVI is different from most in that it sets two exception bits, 545 * VXCVI and VXSNAN for an SNaN input. 546 */ 547 if (flags & float_flag_invalid_snan) { 548 env->fpscr |= FP_VXSNAN; 549 } 550 float_invalid_op_vxcvi(env, set_fprc, retaddr); 551 552 return flags & float_flag_invalid_cvti ? ret : ret_nan; 553 } 554 555 #define FPU_FCTI(op, cvt, nanval) \ 556 uint64_t helper_##op(CPUPPCState *env, float64 arg) \ 557 { \ 558 uint64_t ret = float64_to_##cvt(arg, &env->fp_status); \ 559 int flags = get_float_exception_flags(&env->fp_status); \ 560 if (unlikely(flags & float_flag_invalid)) { \ 561 ret = float_invalid_cvt(env, flags, ret, nanval, 1, GETPC()); \ 562 } \ 563 return ret; \ 564 } 565 566 FPU_FCTI(fctiw, int32, 0x80000000U) 567 FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U) 568 FPU_FCTI(fctiwu, uint32, 0x00000000U) 569 FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U) 570 FPU_FCTI(fctid, int64, 0x8000000000000000ULL) 571 FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL) 572 FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL) 573 FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL) 574 575 #define FPU_FCFI(op, cvtr, is_single) \ 576 uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ 577 { \ 578 CPU_DoubleU farg; \ 579 \ 580 if (is_single) { \ 581 float32 tmp = cvtr(arg, &env->fp_status); \ 582 farg.d = float32_to_float64(tmp, &env->fp_status); \ 583 } else { \ 584 farg.d = cvtr(arg, &env->fp_status); \ 585 } \ 586 do_float_check_status(env, true, GETPC()); \ 587 return farg.ll; \ 588 } 589 590 FPU_FCFI(fcfid, int64_to_float64, 0) 591 FPU_FCFI(fcfids, int64_to_float32, 1) 592 FPU_FCFI(fcfidu, uint64_to_float64, 0) 593 FPU_FCFI(fcfidus, uint64_to_float32, 1) 594 595 static uint64_t do_fri(CPUPPCState *env, uint64_t arg, 596 FloatRoundMode rounding_mode) 597 { 598 FloatRoundMode old_rounding_mode = get_float_rounding_mode(&env->fp_status); 599 int flags; 600 601 set_float_rounding_mode(rounding_mode, &env->fp_status); 602 arg = float64_round_to_int(arg, &env->fp_status); 603 set_float_rounding_mode(old_rounding_mode, &env->fp_status); 604 605 flags = get_float_exception_flags(&env->fp_status); 606 if (flags & float_flag_invalid_snan) { 607 float_invalid_op_vxsnan(env, GETPC()); 608 } 609 610 /* fri* does not set FPSCR[XX] */ 611 set_float_exception_flags(flags & ~float_flag_inexact, &env->fp_status); 612 do_float_check_status(env, true, GETPC()); 613 614 return arg; 615 } 616 617 uint64_t helper_frin(CPUPPCState *env, uint64_t arg) 618 { 619 return do_fri(env, arg, float_round_ties_away); 620 } 621 622 uint64_t helper_friz(CPUPPCState *env, uint64_t arg) 623 { 624 return do_fri(env, arg, float_round_to_zero); 625 } 626 627 uint64_t helper_frip(CPUPPCState *env, uint64_t arg) 628 { 629 return do_fri(env, arg, float_round_up); 630 } 631 632 uint64_t helper_frim(CPUPPCState *env, uint64_t arg) 633 { 634 return do_fri(env, arg, float_round_down); 635 } 636 637 static void float_invalid_op_madd(CPUPPCState *env, int flags, 638 bool set_fpcc, uintptr_t retaddr) 639 { 640 if (flags & float_flag_invalid_imz) { 641 float_invalid_op_vximz(env, set_fpcc, retaddr); 642 } else { 643 float_invalid_op_addsub(env, flags, set_fpcc, retaddr); 644 } 645 } 646 647 static float64 do_fmadd(CPUPPCState *env, float64 a, float64 b, 648 float64 c, int madd_flags, uintptr_t retaddr) 649 { 650 float64 ret = float64_muladd(a, b, c, madd_flags, &env->fp_status); 651 int flags = get_float_exception_flags(&env->fp_status); 652 653 if (unlikely(flags & float_flag_invalid)) { 654 float_invalid_op_madd(env, flags, 1, retaddr); 655 } 656 return ret; 657 } 658 659 static uint64_t do_fmadds(CPUPPCState *env, float64 a, float64 b, 660 float64 c, int madd_flags, uintptr_t retaddr) 661 { 662 float64 ret = float64r32_muladd(a, b, c, madd_flags, &env->fp_status); 663 int flags = get_float_exception_flags(&env->fp_status); 664 665 if (unlikely(flags & float_flag_invalid)) { 666 float_invalid_op_madd(env, flags, 1, retaddr); 667 } 668 return ret; 669 } 670 671 #define FPU_FMADD(op, madd_flags) \ 672 uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \ 673 uint64_t arg2, uint64_t arg3) \ 674 { return do_fmadd(env, arg1, arg2, arg3, madd_flags, GETPC()); } \ 675 uint64_t helper_##op##S(CPUPPCState *env, uint64_t arg1, \ 676 uint64_t arg2, uint64_t arg3) \ 677 { return do_fmadds(env, arg1, arg2, arg3, madd_flags, GETPC()); } 678 679 #define MADD_FLGS 0 680 #define MSUB_FLGS float_muladd_negate_c 681 #define NMADD_FLGS float_muladd_negate_result 682 #define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result) 683 684 FPU_FMADD(FMADD, MADD_FLGS) 685 FPU_FMADD(FNMADD, NMADD_FLGS) 686 FPU_FMADD(FMSUB, MSUB_FLGS) 687 FPU_FMADD(FNMSUB, NMSUB_FLGS) 688 689 /* frsp - frsp. */ 690 static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr) 691 { 692 float32 f32 = float64_to_float32(arg, &env->fp_status); 693 int flags = get_float_exception_flags(&env->fp_status); 694 695 if (unlikely(flags & float_flag_invalid_snan)) { 696 float_invalid_op_vxsnan(env, retaddr); 697 } 698 return helper_todouble(f32); 699 } 700 701 uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) 702 { 703 return do_frsp(env, arg, GETPC()); 704 } 705 706 static void float_invalid_op_sqrt(CPUPPCState *env, int flags, 707 bool set_fpcc, uintptr_t retaddr) 708 { 709 if (unlikely(flags & float_flag_invalid_sqrt)) { 710 float_invalid_op_vxsqrt(env, set_fpcc, retaddr); 711 } else if (unlikely(flags & float_flag_invalid_snan)) { 712 float_invalid_op_vxsnan(env, retaddr); 713 } 714 } 715 716 #define FPU_FSQRT(name, op) \ 717 float64 helper_##name(CPUPPCState *env, float64 arg) \ 718 { \ 719 float64 ret = op(arg, &env->fp_status); \ 720 int flags = get_float_exception_flags(&env->fp_status); \ 721 \ 722 if (unlikely(flags & float_flag_invalid)) { \ 723 float_invalid_op_sqrt(env, flags, 1, GETPC()); \ 724 } \ 725 \ 726 return ret; \ 727 } 728 729 FPU_FSQRT(FSQRT, float64_sqrt) 730 FPU_FSQRT(FSQRTS, float64r32_sqrt) 731 732 #define FPU_FRE(name, op) \ 733 float64 helper_##name(CPUPPCState *env, float64 arg) \ 734 { \ 735 /* "Estimate" the reciprocal with actual division. */ \ 736 float64 ret = op(float64_one, arg, &env->fp_status); \ 737 int flags = get_float_exception_flags(&env->fp_status); \ 738 \ 739 if (unlikely(flags & float_flag_invalid_snan)) { \ 740 float_invalid_op_vxsnan(env, GETPC()); \ 741 } \ 742 if (unlikely(flags & float_flag_divbyzero)) { \ 743 float_zero_divide_excp(env, GETPC()); \ 744 /* For FPSCR.ZE == 0, the result is 1/2. */ \ 745 ret = float64_set_sign(float64_half, float64_is_neg(arg)); \ 746 } \ 747 \ 748 return ret; \ 749 } 750 751 #define FPU_FRSQRTE(name, op) \ 752 float64 helper_##name(CPUPPCState *env, float64 arg) \ 753 { \ 754 /* "Estimate" the reciprocal with actual division. */ \ 755 float64 rets = float64_sqrt(arg, &env->fp_status); \ 756 float64 retd = op(float64_one, rets, &env->fp_status); \ 757 int flags = get_float_exception_flags(&env->fp_status); \ 758 \ 759 if (unlikely(flags & float_flag_invalid)) { \ 760 float_invalid_op_sqrt(env, flags, 1, GETPC()); \ 761 } \ 762 if (unlikely(flags & float_flag_divbyzero)) { \ 763 /* Reciprocal of (square root of) zero. */ \ 764 float_zero_divide_excp(env, GETPC()); \ 765 } \ 766 \ 767 return retd; \ 768 } 769 770 #define FPU_HELPER(name, op, flags_handler) \ 771 float64 helper_##name(CPUPPCState *env, float64 arg1, float64 arg2) \ 772 { \ 773 float64 ret = op(arg1, arg2, &env->fp_status); \ 774 int flags = get_float_exception_flags(&env->fp_status); \ 775 uintptr_t ra = GETPC(); \ 776 flags_handler(env, flags, ra); \ 777 return ret; \ 778 } 779 780 FPU_FRE(FRE, float64_div) 781 FPU_FRE(FRES, float64r32_div) 782 FPU_FRSQRTE(FRSQRTE, float64_div) 783 FPU_FRSQRTE(FRSQRTES, float64r32_div) 784 FPU_HELPER(FADD, float64_add, addsub_flags_handler) 785 FPU_HELPER(FADDS, float64r32_add, addsub_flags_handler) 786 FPU_HELPER(FSUB, float64_sub, addsub_flags_handler) 787 FPU_HELPER(FSUBS, float64r32_sub, addsub_flags_handler) 788 FPU_HELPER(FMUL, float64_mul, mul_flags_handler) 789 FPU_HELPER(FMULS, float64r32_mul, mul_flags_handler) 790 FPU_HELPER(FDIV, float64_div, div_flags_handler) 791 FPU_HELPER(FDIVS, float64r32_div, div_flags_handler) 792 793 /* fsel - fsel. */ 794 uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c) 795 { 796 CPU_DoubleU fa; 797 798 fa.ll = a; 799 800 if ((!float64_is_neg(fa.d) || float64_is_zero(fa.d)) && 801 !float64_is_any_nan(fa.d)) { 802 return c; 803 } else { 804 return b; 805 } 806 } 807 808 uint32_t helper_FTDIV(uint64_t fra, uint64_t frb) 809 { 810 int fe_flag = 0; 811 int fg_flag = 0; 812 813 if (unlikely(float64_is_infinity(fra) || 814 float64_is_infinity(frb) || 815 float64_is_zero(frb))) { 816 fe_flag = 1; 817 fg_flag = 1; 818 } else { 819 int e_a = ppc_float64_get_unbiased_exp(fra); 820 int e_b = ppc_float64_get_unbiased_exp(frb); 821 822 if (unlikely(float64_is_any_nan(fra) || 823 float64_is_any_nan(frb))) { 824 fe_flag = 1; 825 } else if ((e_b <= -1022) || (e_b >= 1021)) { 826 fe_flag = 1; 827 } else if (!float64_is_zero(fra) && 828 (((e_a - e_b) >= 1023) || 829 ((e_a - e_b) <= -1021) || 830 (e_a <= -970))) { 831 fe_flag = 1; 832 } 833 834 if (unlikely(float64_is_zero_or_denormal(frb))) { 835 /* XB is not zero because of the above check and */ 836 /* so must be denormalized. */ 837 fg_flag = 1; 838 } 839 } 840 841 return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); 842 } 843 844 uint32_t helper_FTSQRT(uint64_t frb) 845 { 846 int fe_flag = 0; 847 int fg_flag = 0; 848 849 if (unlikely(float64_is_infinity(frb) || float64_is_zero(frb))) { 850 fe_flag = 1; 851 fg_flag = 1; 852 } else { 853 int e_b = ppc_float64_get_unbiased_exp(frb); 854 855 if (unlikely(float64_is_any_nan(frb))) { 856 fe_flag = 1; 857 } else if (unlikely(float64_is_zero(frb))) { 858 fe_flag = 1; 859 } else if (unlikely(float64_is_neg(frb))) { 860 fe_flag = 1; 861 } else if (!float64_is_zero(frb) && (e_b <= (-1022 + 52))) { 862 fe_flag = 1; 863 } 864 865 if (unlikely(float64_is_zero_or_denormal(frb))) { 866 /* XB is not zero because of the above check and */ 867 /* therefore must be denormalized. */ 868 fg_flag = 1; 869 } 870 } 871 872 return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); 873 } 874 875 void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, 876 uint32_t crfD) 877 { 878 CPU_DoubleU farg1, farg2; 879 uint32_t ret = 0; 880 881 farg1.ll = arg1; 882 farg2.ll = arg2; 883 884 if (unlikely(float64_is_any_nan(farg1.d) || 885 float64_is_any_nan(farg2.d))) { 886 ret = 0x01UL; 887 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { 888 ret = 0x08UL; 889 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { 890 ret = 0x04UL; 891 } else { 892 ret = 0x02UL; 893 } 894 895 env->fpscr &= ~FP_FPCC; 896 env->fpscr |= ret << FPSCR_FPCC; 897 env->crf[crfD] = ret; 898 if (unlikely(ret == 0x01UL 899 && (float64_is_signaling_nan(farg1.d, &env->fp_status) || 900 float64_is_signaling_nan(farg2.d, &env->fp_status)))) { 901 /* sNaN comparison */ 902 float_invalid_op_vxsnan(env, GETPC()); 903 } 904 } 905 906 void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, 907 uint32_t crfD) 908 { 909 CPU_DoubleU farg1, farg2; 910 uint32_t ret = 0; 911 912 farg1.ll = arg1; 913 farg2.ll = arg2; 914 915 if (unlikely(float64_is_any_nan(farg1.d) || 916 float64_is_any_nan(farg2.d))) { 917 ret = 0x01UL; 918 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { 919 ret = 0x08UL; 920 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { 921 ret = 0x04UL; 922 } else { 923 ret = 0x02UL; 924 } 925 926 env->fpscr &= ~FP_FPCC; 927 env->fpscr |= ret << FPSCR_FPCC; 928 env->crf[crfD] = (uint32_t) ret; 929 if (unlikely(ret == 0x01UL)) { 930 float_invalid_op_vxvc(env, 1, GETPC()); 931 if (float64_is_signaling_nan(farg1.d, &env->fp_status) || 932 float64_is_signaling_nan(farg2.d, &env->fp_status)) { 933 /* sNaN comparison */ 934 float_invalid_op_vxsnan(env, GETPC()); 935 } 936 } 937 } 938 939 /* Single-precision floating-point conversions */ 940 static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val) 941 { 942 CPU_FloatU u; 943 944 u.f = int32_to_float32(val, &env->vec_status); 945 946 return u.l; 947 } 948 949 static inline uint32_t efscfui(CPUPPCState *env, uint32_t val) 950 { 951 CPU_FloatU u; 952 953 u.f = uint32_to_float32(val, &env->vec_status); 954 955 return u.l; 956 } 957 958 static inline int32_t efsctsi(CPUPPCState *env, uint32_t val) 959 { 960 CPU_FloatU u; 961 962 u.l = val; 963 /* NaN are not treated the same way IEEE 754 does */ 964 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { 965 return 0; 966 } 967 968 return float32_to_int32(u.f, &env->vec_status); 969 } 970 971 static inline uint32_t efsctui(CPUPPCState *env, uint32_t val) 972 { 973 CPU_FloatU u; 974 975 u.l = val; 976 /* NaN are not treated the same way IEEE 754 does */ 977 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { 978 return 0; 979 } 980 981 return float32_to_uint32(u.f, &env->vec_status); 982 } 983 984 static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val) 985 { 986 CPU_FloatU u; 987 988 u.l = val; 989 /* NaN are not treated the same way IEEE 754 does */ 990 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { 991 return 0; 992 } 993 994 return float32_to_int32_round_to_zero(u.f, &env->vec_status); 995 } 996 997 static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val) 998 { 999 CPU_FloatU u; 1000 1001 u.l = val; 1002 /* NaN are not treated the same way IEEE 754 does */ 1003 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { 1004 return 0; 1005 } 1006 1007 return float32_to_uint32_round_to_zero(u.f, &env->vec_status); 1008 } 1009 1010 static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val) 1011 { 1012 CPU_FloatU u; 1013 float32 tmp; 1014 1015 u.f = int32_to_float32(val, &env->vec_status); 1016 tmp = int64_to_float32(1ULL << 32, &env->vec_status); 1017 u.f = float32_div(u.f, tmp, &env->vec_status); 1018 1019 return u.l; 1020 } 1021 1022 static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val) 1023 { 1024 CPU_FloatU u; 1025 float32 tmp; 1026 1027 u.f = uint32_to_float32(val, &env->vec_status); 1028 tmp = uint64_to_float32(1ULL << 32, &env->vec_status); 1029 u.f = float32_div(u.f, tmp, &env->vec_status); 1030 1031 return u.l; 1032 } 1033 1034 static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val) 1035 { 1036 CPU_FloatU u; 1037 float32 tmp; 1038 1039 u.l = val; 1040 /* NaN are not treated the same way IEEE 754 does */ 1041 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { 1042 return 0; 1043 } 1044 tmp = uint64_to_float32(1ULL << 32, &env->vec_status); 1045 u.f = float32_mul(u.f, tmp, &env->vec_status); 1046 1047 return float32_to_int32(u.f, &env->vec_status); 1048 } 1049 1050 static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val) 1051 { 1052 CPU_FloatU u; 1053 float32 tmp; 1054 1055 u.l = val; 1056 /* NaN are not treated the same way IEEE 754 does */ 1057 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { 1058 return 0; 1059 } 1060 tmp = uint64_to_float32(1ULL << 32, &env->vec_status); 1061 u.f = float32_mul(u.f, tmp, &env->vec_status); 1062 1063 return float32_to_uint32(u.f, &env->vec_status); 1064 } 1065 1066 #define HELPER_SPE_SINGLE_CONV(name) \ 1067 uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \ 1068 { \ 1069 return e##name(env, val); \ 1070 } 1071 /* efscfsi */ 1072 HELPER_SPE_SINGLE_CONV(fscfsi); 1073 /* efscfui */ 1074 HELPER_SPE_SINGLE_CONV(fscfui); 1075 /* efscfuf */ 1076 HELPER_SPE_SINGLE_CONV(fscfuf); 1077 /* efscfsf */ 1078 HELPER_SPE_SINGLE_CONV(fscfsf); 1079 /* efsctsi */ 1080 HELPER_SPE_SINGLE_CONV(fsctsi); 1081 /* efsctui */ 1082 HELPER_SPE_SINGLE_CONV(fsctui); 1083 /* efsctsiz */ 1084 HELPER_SPE_SINGLE_CONV(fsctsiz); 1085 /* efsctuiz */ 1086 HELPER_SPE_SINGLE_CONV(fsctuiz); 1087 /* efsctsf */ 1088 HELPER_SPE_SINGLE_CONV(fsctsf); 1089 /* efsctuf */ 1090 HELPER_SPE_SINGLE_CONV(fsctuf); 1091 1092 #define HELPER_SPE_VECTOR_CONV(name) \ 1093 uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \ 1094 { \ 1095 return ((uint64_t)e##name(env, val >> 32) << 32) | \ 1096 (uint64_t)e##name(env, val); \ 1097 } 1098 /* evfscfsi */ 1099 HELPER_SPE_VECTOR_CONV(fscfsi); 1100 /* evfscfui */ 1101 HELPER_SPE_VECTOR_CONV(fscfui); 1102 /* evfscfuf */ 1103 HELPER_SPE_VECTOR_CONV(fscfuf); 1104 /* evfscfsf */ 1105 HELPER_SPE_VECTOR_CONV(fscfsf); 1106 /* evfsctsi */ 1107 HELPER_SPE_VECTOR_CONV(fsctsi); 1108 /* evfsctui */ 1109 HELPER_SPE_VECTOR_CONV(fsctui); 1110 /* evfsctsiz */ 1111 HELPER_SPE_VECTOR_CONV(fsctsiz); 1112 /* evfsctuiz */ 1113 HELPER_SPE_VECTOR_CONV(fsctuiz); 1114 /* evfsctsf */ 1115 HELPER_SPE_VECTOR_CONV(fsctsf); 1116 /* evfsctuf */ 1117 HELPER_SPE_VECTOR_CONV(fsctuf); 1118 1119 /* Single-precision floating-point arithmetic */ 1120 static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2) 1121 { 1122 CPU_FloatU u1, u2; 1123 1124 u1.l = op1; 1125 u2.l = op2; 1126 u1.f = float32_add(u1.f, u2.f, &env->vec_status); 1127 return u1.l; 1128 } 1129 1130 static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2) 1131 { 1132 CPU_FloatU u1, u2; 1133 1134 u1.l = op1; 1135 u2.l = op2; 1136 u1.f = float32_sub(u1.f, u2.f, &env->vec_status); 1137 return u1.l; 1138 } 1139 1140 static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2) 1141 { 1142 CPU_FloatU u1, u2; 1143 1144 u1.l = op1; 1145 u2.l = op2; 1146 u1.f = float32_mul(u1.f, u2.f, &env->vec_status); 1147 return u1.l; 1148 } 1149 1150 static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2) 1151 { 1152 CPU_FloatU u1, u2; 1153 1154 u1.l = op1; 1155 u2.l = op2; 1156 u1.f = float32_div(u1.f, u2.f, &env->vec_status); 1157 return u1.l; 1158 } 1159 1160 #define HELPER_SPE_SINGLE_ARITH(name) \ 1161 uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ 1162 { \ 1163 return e##name(env, op1, op2); \ 1164 } 1165 /* efsadd */ 1166 HELPER_SPE_SINGLE_ARITH(fsadd); 1167 /* efssub */ 1168 HELPER_SPE_SINGLE_ARITH(fssub); 1169 /* efsmul */ 1170 HELPER_SPE_SINGLE_ARITH(fsmul); 1171 /* efsdiv */ 1172 HELPER_SPE_SINGLE_ARITH(fsdiv); 1173 1174 #define HELPER_SPE_VECTOR_ARITH(name) \ 1175 uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ 1176 { \ 1177 return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \ 1178 (uint64_t)e##name(env, op1, op2); \ 1179 } 1180 /* evfsadd */ 1181 HELPER_SPE_VECTOR_ARITH(fsadd); 1182 /* evfssub */ 1183 HELPER_SPE_VECTOR_ARITH(fssub); 1184 /* evfsmul */ 1185 HELPER_SPE_VECTOR_ARITH(fsmul); 1186 /* evfsdiv */ 1187 HELPER_SPE_VECTOR_ARITH(fsdiv); 1188 1189 /* Single-precision floating-point comparisons */ 1190 static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2) 1191 { 1192 CPU_FloatU u1, u2; 1193 1194 u1.l = op1; 1195 u2.l = op2; 1196 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; 1197 } 1198 1199 static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2) 1200 { 1201 CPU_FloatU u1, u2; 1202 1203 u1.l = op1; 1204 u2.l = op2; 1205 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; 1206 } 1207 1208 static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2) 1209 { 1210 CPU_FloatU u1, u2; 1211 1212 u1.l = op1; 1213 u2.l = op2; 1214 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; 1215 } 1216 1217 static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2) 1218 { 1219 /* XXX: TODO: ignore special values (NaN, infinites, ...) */ 1220 return efscmplt(env, op1, op2); 1221 } 1222 1223 static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2) 1224 { 1225 /* XXX: TODO: ignore special values (NaN, infinites, ...) */ 1226 return efscmpgt(env, op1, op2); 1227 } 1228 1229 static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2) 1230 { 1231 /* XXX: TODO: ignore special values (NaN, infinites, ...) */ 1232 return efscmpeq(env, op1, op2); 1233 } 1234 1235 #define HELPER_SINGLE_SPE_CMP(name) \ 1236 uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ 1237 { \ 1238 return e##name(env, op1, op2); \ 1239 } 1240 /* efststlt */ 1241 HELPER_SINGLE_SPE_CMP(fststlt); 1242 /* efststgt */ 1243 HELPER_SINGLE_SPE_CMP(fststgt); 1244 /* efststeq */ 1245 HELPER_SINGLE_SPE_CMP(fststeq); 1246 /* efscmplt */ 1247 HELPER_SINGLE_SPE_CMP(fscmplt); 1248 /* efscmpgt */ 1249 HELPER_SINGLE_SPE_CMP(fscmpgt); 1250 /* efscmpeq */ 1251 HELPER_SINGLE_SPE_CMP(fscmpeq); 1252 1253 static inline uint32_t evcmp_merge(int t0, int t1) 1254 { 1255 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); 1256 } 1257 1258 #define HELPER_VECTOR_SPE_CMP(name) \ 1259 uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ 1260 { \ 1261 return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \ 1262 e##name(env, op1, op2)); \ 1263 } 1264 /* evfststlt */ 1265 HELPER_VECTOR_SPE_CMP(fststlt); 1266 /* evfststgt */ 1267 HELPER_VECTOR_SPE_CMP(fststgt); 1268 /* evfststeq */ 1269 HELPER_VECTOR_SPE_CMP(fststeq); 1270 /* evfscmplt */ 1271 HELPER_VECTOR_SPE_CMP(fscmplt); 1272 /* evfscmpgt */ 1273 HELPER_VECTOR_SPE_CMP(fscmpgt); 1274 /* evfscmpeq */ 1275 HELPER_VECTOR_SPE_CMP(fscmpeq); 1276 1277 /* Double-precision floating-point conversion */ 1278 uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val) 1279 { 1280 CPU_DoubleU u; 1281 1282 u.d = int32_to_float64(val, &env->vec_status); 1283 1284 return u.ll; 1285 } 1286 1287 uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val) 1288 { 1289 CPU_DoubleU u; 1290 1291 u.d = int64_to_float64(val, &env->vec_status); 1292 1293 return u.ll; 1294 } 1295 1296 uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val) 1297 { 1298 CPU_DoubleU u; 1299 1300 u.d = uint32_to_float64(val, &env->vec_status); 1301 1302 return u.ll; 1303 } 1304 1305 uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val) 1306 { 1307 CPU_DoubleU u; 1308 1309 u.d = uint64_to_float64(val, &env->vec_status); 1310 1311 return u.ll; 1312 } 1313 1314 uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val) 1315 { 1316 CPU_DoubleU u; 1317 1318 u.ll = val; 1319 /* NaN are not treated the same way IEEE 754 does */ 1320 if (unlikely(float64_is_any_nan(u.d))) { 1321 return 0; 1322 } 1323 1324 return float64_to_int32(u.d, &env->vec_status); 1325 } 1326 1327 uint32_t helper_efdctui(CPUPPCState *env, uint64_t val) 1328 { 1329 CPU_DoubleU u; 1330 1331 u.ll = val; 1332 /* NaN are not treated the same way IEEE 754 does */ 1333 if (unlikely(float64_is_any_nan(u.d))) { 1334 return 0; 1335 } 1336 1337 return float64_to_uint32(u.d, &env->vec_status); 1338 } 1339 1340 uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val) 1341 { 1342 CPU_DoubleU u; 1343 1344 u.ll = val; 1345 /* NaN are not treated the same way IEEE 754 does */ 1346 if (unlikely(float64_is_any_nan(u.d))) { 1347 return 0; 1348 } 1349 1350 return float64_to_int32_round_to_zero(u.d, &env->vec_status); 1351 } 1352 1353 uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val) 1354 { 1355 CPU_DoubleU u; 1356 1357 u.ll = val; 1358 /* NaN are not treated the same way IEEE 754 does */ 1359 if (unlikely(float64_is_any_nan(u.d))) { 1360 return 0; 1361 } 1362 1363 return float64_to_int64_round_to_zero(u.d, &env->vec_status); 1364 } 1365 1366 uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val) 1367 { 1368 CPU_DoubleU u; 1369 1370 u.ll = val; 1371 /* NaN are not treated the same way IEEE 754 does */ 1372 if (unlikely(float64_is_any_nan(u.d))) { 1373 return 0; 1374 } 1375 1376 return float64_to_uint32_round_to_zero(u.d, &env->vec_status); 1377 } 1378 1379 uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val) 1380 { 1381 CPU_DoubleU u; 1382 1383 u.ll = val; 1384 /* NaN are not treated the same way IEEE 754 does */ 1385 if (unlikely(float64_is_any_nan(u.d))) { 1386 return 0; 1387 } 1388 1389 return float64_to_uint64_round_to_zero(u.d, &env->vec_status); 1390 } 1391 1392 uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val) 1393 { 1394 CPU_DoubleU u; 1395 float64 tmp; 1396 1397 u.d = int32_to_float64(val, &env->vec_status); 1398 tmp = int64_to_float64(1ULL << 32, &env->vec_status); 1399 u.d = float64_div(u.d, tmp, &env->vec_status); 1400 1401 return u.ll; 1402 } 1403 1404 uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val) 1405 { 1406 CPU_DoubleU u; 1407 float64 tmp; 1408 1409 u.d = uint32_to_float64(val, &env->vec_status); 1410 tmp = int64_to_float64(1ULL << 32, &env->vec_status); 1411 u.d = float64_div(u.d, tmp, &env->vec_status); 1412 1413 return u.ll; 1414 } 1415 1416 uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val) 1417 { 1418 CPU_DoubleU u; 1419 float64 tmp; 1420 1421 u.ll = val; 1422 /* NaN are not treated the same way IEEE 754 does */ 1423 if (unlikely(float64_is_any_nan(u.d))) { 1424 return 0; 1425 } 1426 tmp = uint64_to_float64(1ULL << 32, &env->vec_status); 1427 u.d = float64_mul(u.d, tmp, &env->vec_status); 1428 1429 return float64_to_int32(u.d, &env->vec_status); 1430 } 1431 1432 uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val) 1433 { 1434 CPU_DoubleU u; 1435 float64 tmp; 1436 1437 u.ll = val; 1438 /* NaN are not treated the same way IEEE 754 does */ 1439 if (unlikely(float64_is_any_nan(u.d))) { 1440 return 0; 1441 } 1442 tmp = uint64_to_float64(1ULL << 32, &env->vec_status); 1443 u.d = float64_mul(u.d, tmp, &env->vec_status); 1444 1445 return float64_to_uint32(u.d, &env->vec_status); 1446 } 1447 1448 uint32_t helper_efscfd(CPUPPCState *env, uint64_t val) 1449 { 1450 CPU_DoubleU u1; 1451 CPU_FloatU u2; 1452 1453 u1.ll = val; 1454 u2.f = float64_to_float32(u1.d, &env->vec_status); 1455 1456 return u2.l; 1457 } 1458 1459 uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val) 1460 { 1461 CPU_DoubleU u2; 1462 CPU_FloatU u1; 1463 1464 u1.l = val; 1465 u2.d = float32_to_float64(u1.f, &env->vec_status); 1466 1467 return u2.ll; 1468 } 1469 1470 /* Double precision fixed-point arithmetic */ 1471 uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2) 1472 { 1473 CPU_DoubleU u1, u2; 1474 1475 u1.ll = op1; 1476 u2.ll = op2; 1477 u1.d = float64_add(u1.d, u2.d, &env->vec_status); 1478 return u1.ll; 1479 } 1480 1481 uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2) 1482 { 1483 CPU_DoubleU u1, u2; 1484 1485 u1.ll = op1; 1486 u2.ll = op2; 1487 u1.d = float64_sub(u1.d, u2.d, &env->vec_status); 1488 return u1.ll; 1489 } 1490 1491 uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2) 1492 { 1493 CPU_DoubleU u1, u2; 1494 1495 u1.ll = op1; 1496 u2.ll = op2; 1497 u1.d = float64_mul(u1.d, u2.d, &env->vec_status); 1498 return u1.ll; 1499 } 1500 1501 uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2) 1502 { 1503 CPU_DoubleU u1, u2; 1504 1505 u1.ll = op1; 1506 u2.ll = op2; 1507 u1.d = float64_div(u1.d, u2.d, &env->vec_status); 1508 return u1.ll; 1509 } 1510 1511 /* Double precision floating point helpers */ 1512 uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2) 1513 { 1514 CPU_DoubleU u1, u2; 1515 1516 u1.ll = op1; 1517 u2.ll = op2; 1518 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; 1519 } 1520 1521 uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2) 1522 { 1523 CPU_DoubleU u1, u2; 1524 1525 u1.ll = op1; 1526 u2.ll = op2; 1527 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; 1528 } 1529 1530 uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2) 1531 { 1532 CPU_DoubleU u1, u2; 1533 1534 u1.ll = op1; 1535 u2.ll = op2; 1536 return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; 1537 } 1538 1539 uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2) 1540 { 1541 /* XXX: TODO: test special values (NaN, infinites, ...) */ 1542 return helper_efdtstlt(env, op1, op2); 1543 } 1544 1545 uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2) 1546 { 1547 /* XXX: TODO: test special values (NaN, infinites, ...) */ 1548 return helper_efdtstgt(env, op1, op2); 1549 } 1550 1551 uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) 1552 { 1553 /* XXX: TODO: test special values (NaN, infinites, ...) */ 1554 return helper_efdtsteq(env, op1, op2); 1555 } 1556 1557 #define float64_to_float64(x, env) x 1558 1559 1560 /* 1561 * VSX_ADD_SUB - VSX floating point add/subtract 1562 * name - instruction mnemonic 1563 * op - operation (add or sub) 1564 * nels - number of elements (1, 2 or 4) 1565 * tp - type (float32 or float64) 1566 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1567 * sfifprf - set FI and FPRF 1568 */ 1569 #define VSX_ADD_SUB(name, op, nels, tp, fld, sfifprf, r2sp) \ 1570 void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ 1571 ppc_vsr_t *xa, ppc_vsr_t *xb) \ 1572 { \ 1573 ppc_vsr_t t = { }; \ 1574 int i; \ 1575 \ 1576 helper_reset_fpstatus(env); \ 1577 \ 1578 for (i = 0; i < nels; i++) { \ 1579 float_status tstat = env->fp_status; \ 1580 set_float_exception_flags(0, &tstat); \ 1581 t.fld = tp##_##op(xa->fld, xb->fld, &tstat); \ 1582 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ 1583 \ 1584 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ 1585 float_invalid_op_addsub(env, tstat.float_exception_flags, \ 1586 sfifprf, GETPC()); \ 1587 } \ 1588 \ 1589 if (r2sp) { \ 1590 t.fld = do_frsp(env, t.fld, GETPC()); \ 1591 } \ 1592 \ 1593 if (sfifprf) { \ 1594 helper_compute_fprf_float64(env, t.fld); \ 1595 } \ 1596 } \ 1597 *xt = t; \ 1598 do_float_check_status(env, sfifprf, GETPC()); \ 1599 } 1600 1601 VSX_ADD_SUB(XSADDDP, add, 1, float64, VsrD(0), 1, 0) 1602 VSX_ADD_SUB(XSADDSP, add, 1, float64, VsrD(0), 1, 1) 1603 VSX_ADD_SUB(XVADDDP, add, 2, float64, VsrD(i), 0, 0) 1604 VSX_ADD_SUB(XVADDSP, add, 4, float32, VsrW(i), 0, 0) 1605 VSX_ADD_SUB(XSSUBDP, sub, 1, float64, VsrD(0), 1, 0) 1606 VSX_ADD_SUB(XSSUBSP, sub, 1, float64, VsrD(0), 1, 1) 1607 VSX_ADD_SUB(XVSUBDP, sub, 2, float64, VsrD(i), 0, 0) 1608 VSX_ADD_SUB(XVSUBSP, sub, 4, float32, VsrW(i), 0, 0) 1609 1610 void helper_xsaddqp(CPUPPCState *env, uint32_t opcode, 1611 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) 1612 { 1613 ppc_vsr_t t = *xt; 1614 float_status tstat; 1615 1616 helper_reset_fpstatus(env); 1617 1618 tstat = env->fp_status; 1619 if (unlikely(Rc(opcode) != 0)) { 1620 tstat.float_rounding_mode = float_round_to_odd; 1621 } 1622 1623 set_float_exception_flags(0, &tstat); 1624 t.f128 = float128_add(xa->f128, xb->f128, &tstat); 1625 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 1626 1627 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { 1628 float_invalid_op_addsub(env, tstat.float_exception_flags, 1, GETPC()); 1629 } 1630 1631 helper_compute_fprf_float128(env, t.f128); 1632 1633 *xt = t; 1634 do_float_check_status(env, true, GETPC()); 1635 } 1636 1637 /* 1638 * VSX_MUL - VSX floating point multiply 1639 * op - instruction mnemonic 1640 * nels - number of elements (1, 2 or 4) 1641 * tp - type (float32 or float64) 1642 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1643 * sfifprf - set FI and FPRF 1644 */ 1645 #define VSX_MUL(op, nels, tp, fld, sfifprf, r2sp) \ 1646 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ 1647 ppc_vsr_t *xa, ppc_vsr_t *xb) \ 1648 { \ 1649 ppc_vsr_t t = { }; \ 1650 int i; \ 1651 \ 1652 helper_reset_fpstatus(env); \ 1653 \ 1654 for (i = 0; i < nels; i++) { \ 1655 float_status tstat = env->fp_status; \ 1656 set_float_exception_flags(0, &tstat); \ 1657 t.fld = tp##_mul(xa->fld, xb->fld, &tstat); \ 1658 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ 1659 \ 1660 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ 1661 float_invalid_op_mul(env, tstat.float_exception_flags, \ 1662 sfifprf, GETPC()); \ 1663 } \ 1664 \ 1665 if (r2sp) { \ 1666 t.fld = do_frsp(env, t.fld, GETPC()); \ 1667 } \ 1668 \ 1669 if (sfifprf) { \ 1670 helper_compute_fprf_float64(env, t.fld); \ 1671 } \ 1672 } \ 1673 \ 1674 *xt = t; \ 1675 do_float_check_status(env, sfifprf, GETPC()); \ 1676 } 1677 1678 VSX_MUL(XSMULDP, 1, float64, VsrD(0), 1, 0) 1679 VSX_MUL(XSMULSP, 1, float64, VsrD(0), 1, 1) 1680 VSX_MUL(XVMULDP, 2, float64, VsrD(i), 0, 0) 1681 VSX_MUL(XVMULSP, 4, float32, VsrW(i), 0, 0) 1682 1683 void helper_xsmulqp(CPUPPCState *env, uint32_t opcode, 1684 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) 1685 { 1686 ppc_vsr_t t = *xt; 1687 float_status tstat; 1688 1689 helper_reset_fpstatus(env); 1690 tstat = env->fp_status; 1691 if (unlikely(Rc(opcode) != 0)) { 1692 tstat.float_rounding_mode = float_round_to_odd; 1693 } 1694 1695 set_float_exception_flags(0, &tstat); 1696 t.f128 = float128_mul(xa->f128, xb->f128, &tstat); 1697 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 1698 1699 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { 1700 float_invalid_op_mul(env, tstat.float_exception_flags, 1, GETPC()); 1701 } 1702 helper_compute_fprf_float128(env, t.f128); 1703 1704 *xt = t; 1705 do_float_check_status(env, true, GETPC()); 1706 } 1707 1708 /* 1709 * VSX_DIV - VSX floating point divide 1710 * op - instruction mnemonic 1711 * nels - number of elements (1, 2 or 4) 1712 * tp - type (float32 or float64) 1713 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1714 * sfifprf - set FI and FPRF 1715 */ 1716 #define VSX_DIV(op, nels, tp, fld, sfifprf, r2sp) \ 1717 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ 1718 ppc_vsr_t *xa, ppc_vsr_t *xb) \ 1719 { \ 1720 ppc_vsr_t t = { }; \ 1721 int i; \ 1722 \ 1723 helper_reset_fpstatus(env); \ 1724 \ 1725 for (i = 0; i < nels; i++) { \ 1726 float_status tstat = env->fp_status; \ 1727 set_float_exception_flags(0, &tstat); \ 1728 t.fld = tp##_div(xa->fld, xb->fld, &tstat); \ 1729 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ 1730 \ 1731 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ 1732 float_invalid_op_div(env, tstat.float_exception_flags, \ 1733 sfifprf, GETPC()); \ 1734 } \ 1735 if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ 1736 float_zero_divide_excp(env, GETPC()); \ 1737 } \ 1738 \ 1739 if (r2sp) { \ 1740 t.fld = do_frsp(env, t.fld, GETPC()); \ 1741 } \ 1742 \ 1743 if (sfifprf) { \ 1744 helper_compute_fprf_float64(env, t.fld); \ 1745 } \ 1746 } \ 1747 \ 1748 *xt = t; \ 1749 do_float_check_status(env, sfifprf, GETPC()); \ 1750 } 1751 1752 VSX_DIV(XSDIVDP, 1, float64, VsrD(0), 1, 0) 1753 VSX_DIV(XSDIVSP, 1, float64, VsrD(0), 1, 1) 1754 VSX_DIV(XVDIVDP, 2, float64, VsrD(i), 0, 0) 1755 VSX_DIV(XVDIVSP, 4, float32, VsrW(i), 0, 0) 1756 1757 void helper_xsdivqp(CPUPPCState *env, uint32_t opcode, 1758 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) 1759 { 1760 ppc_vsr_t t = *xt; 1761 float_status tstat; 1762 1763 helper_reset_fpstatus(env); 1764 tstat = env->fp_status; 1765 if (unlikely(Rc(opcode) != 0)) { 1766 tstat.float_rounding_mode = float_round_to_odd; 1767 } 1768 1769 set_float_exception_flags(0, &tstat); 1770 t.f128 = float128_div(xa->f128, xb->f128, &tstat); 1771 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 1772 1773 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { 1774 float_invalid_op_div(env, tstat.float_exception_flags, 1, GETPC()); 1775 } 1776 if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { 1777 float_zero_divide_excp(env, GETPC()); 1778 } 1779 1780 helper_compute_fprf_float128(env, t.f128); 1781 *xt = t; 1782 do_float_check_status(env, true, GETPC()); 1783 } 1784 1785 /* 1786 * VSX_RE - VSX floating point reciprocal estimate 1787 * op - instruction mnemonic 1788 * nels - number of elements (1, 2 or 4) 1789 * tp - type (float32 or float64) 1790 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1791 * sfifprf - set FI and FPRF 1792 */ 1793 #define VSX_RE(op, nels, tp, fld, sfifprf, r2sp) \ 1794 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 1795 { \ 1796 ppc_vsr_t t = { }; \ 1797 int i; \ 1798 \ 1799 helper_reset_fpstatus(env); \ 1800 \ 1801 for (i = 0; i < nels; i++) { \ 1802 if (unlikely(tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \ 1803 float_invalid_op_vxsnan(env, GETPC()); \ 1804 } \ 1805 t.fld = tp##_div(tp##_one, xb->fld, &env->fp_status); \ 1806 \ 1807 if (r2sp) { \ 1808 t.fld = do_frsp(env, t.fld, GETPC()); \ 1809 } \ 1810 \ 1811 if (sfifprf) { \ 1812 helper_compute_fprf_float64(env, t.fld); \ 1813 } \ 1814 } \ 1815 \ 1816 *xt = t; \ 1817 do_float_check_status(env, sfifprf, GETPC()); \ 1818 } 1819 1820 VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) 1821 VSX_RE(xsresp, 1, float64, VsrD(0), 1, 1) 1822 VSX_RE(xvredp, 2, float64, VsrD(i), 0, 0) 1823 VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0) 1824 1825 /* 1826 * VSX_SQRT - VSX floating point square root 1827 * op - instruction mnemonic 1828 * nels - number of elements (1, 2 or 4) 1829 * tp - type (float32 or float64) 1830 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1831 * sfifprf - set FI and FPRF 1832 */ 1833 #define VSX_SQRT(op, nels, tp, fld, sfifprf, r2sp) \ 1834 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 1835 { \ 1836 ppc_vsr_t t = { }; \ 1837 int i; \ 1838 \ 1839 helper_reset_fpstatus(env); \ 1840 \ 1841 for (i = 0; i < nels; i++) { \ 1842 float_status tstat = env->fp_status; \ 1843 set_float_exception_flags(0, &tstat); \ 1844 t.fld = tp##_sqrt(xb->fld, &tstat); \ 1845 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ 1846 \ 1847 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ 1848 float_invalid_op_sqrt(env, tstat.float_exception_flags, \ 1849 sfifprf, GETPC()); \ 1850 } \ 1851 \ 1852 if (r2sp) { \ 1853 t.fld = do_frsp(env, t.fld, GETPC()); \ 1854 } \ 1855 \ 1856 if (sfifprf) { \ 1857 helper_compute_fprf_float64(env, t.fld); \ 1858 } \ 1859 } \ 1860 \ 1861 *xt = t; \ 1862 do_float_check_status(env, sfifprf, GETPC()); \ 1863 } 1864 1865 VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) 1866 VSX_SQRT(xssqrtsp, 1, float64, VsrD(0), 1, 1) 1867 VSX_SQRT(xvsqrtdp, 2, float64, VsrD(i), 0, 0) 1868 VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0) 1869 1870 /* 1871 *VSX_RSQRTE - VSX floating point reciprocal square root estimate 1872 * op - instruction mnemonic 1873 * nels - number of elements (1, 2 or 4) 1874 * tp - type (float32 or float64) 1875 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1876 * sfifprf - set FI and FPRF 1877 */ 1878 #define VSX_RSQRTE(op, nels, tp, fld, sfifprf, r2sp) \ 1879 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 1880 { \ 1881 ppc_vsr_t t = { }; \ 1882 int i; \ 1883 \ 1884 helper_reset_fpstatus(env); \ 1885 \ 1886 for (i = 0; i < nels; i++) { \ 1887 float_status tstat = env->fp_status; \ 1888 set_float_exception_flags(0, &tstat); \ 1889 t.fld = tp##_sqrt(xb->fld, &tstat); \ 1890 t.fld = tp##_div(tp##_one, t.fld, &tstat); \ 1891 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ 1892 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ 1893 float_invalid_op_sqrt(env, tstat.float_exception_flags, \ 1894 sfifprf, GETPC()); \ 1895 } \ 1896 if (r2sp) { \ 1897 t.fld = do_frsp(env, t.fld, GETPC()); \ 1898 } \ 1899 \ 1900 if (sfifprf) { \ 1901 helper_compute_fprf_float64(env, t.fld); \ 1902 } \ 1903 } \ 1904 \ 1905 *xt = t; \ 1906 do_float_check_status(env, sfifprf, GETPC()); \ 1907 } 1908 1909 VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) 1910 VSX_RSQRTE(xsrsqrtesp, 1, float64, VsrD(0), 1, 1) 1911 VSX_RSQRTE(xvrsqrtedp, 2, float64, VsrD(i), 0, 0) 1912 VSX_RSQRTE(xvrsqrtesp, 4, float32, VsrW(i), 0, 0) 1913 1914 /* 1915 * VSX_TDIV - VSX floating point test for divide 1916 * op - instruction mnemonic 1917 * nels - number of elements (1, 2 or 4) 1918 * tp - type (float32 or float64) 1919 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1920 * emin - minimum unbiased exponent 1921 * emax - maximum unbiased exponent 1922 * nbits - number of fraction bits 1923 */ 1924 #define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \ 1925 void helper_##op(CPUPPCState *env, uint32_t opcode, \ 1926 ppc_vsr_t *xa, ppc_vsr_t *xb) \ 1927 { \ 1928 int i; \ 1929 int fe_flag = 0; \ 1930 int fg_flag = 0; \ 1931 \ 1932 for (i = 0; i < nels; i++) { \ 1933 if (unlikely(tp##_is_infinity(xa->fld) || \ 1934 tp##_is_infinity(xb->fld) || \ 1935 tp##_is_zero(xb->fld))) { \ 1936 fe_flag = 1; \ 1937 fg_flag = 1; \ 1938 } else { \ 1939 int e_a = ppc_##tp##_get_unbiased_exp(xa->fld); \ 1940 int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \ 1941 \ 1942 if (unlikely(tp##_is_any_nan(xa->fld) || \ 1943 tp##_is_any_nan(xb->fld))) { \ 1944 fe_flag = 1; \ 1945 } else if ((e_b <= emin) || (e_b >= (emax - 2))) { \ 1946 fe_flag = 1; \ 1947 } else if (!tp##_is_zero(xa->fld) && \ 1948 (((e_a - e_b) >= emax) || \ 1949 ((e_a - e_b) <= (emin + 1)) || \ 1950 (e_a <= (emin + nbits)))) { \ 1951 fe_flag = 1; \ 1952 } \ 1953 \ 1954 if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \ 1955 /* \ 1956 * XB is not zero because of the above check and so \ 1957 * must be denormalized. \ 1958 */ \ 1959 fg_flag = 1; \ 1960 } \ 1961 } \ 1962 } \ 1963 \ 1964 env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \ 1965 } 1966 1967 VSX_TDIV(xstdivdp, 1, float64, VsrD(0), -1022, 1023, 52) 1968 VSX_TDIV(xvtdivdp, 2, float64, VsrD(i), -1022, 1023, 52) 1969 VSX_TDIV(xvtdivsp, 4, float32, VsrW(i), -126, 127, 23) 1970 1971 /* 1972 * VSX_TSQRT - VSX floating point test for square root 1973 * op - instruction mnemonic 1974 * nels - number of elements (1, 2 or 4) 1975 * tp - type (float32 or float64) 1976 * fld - vsr_t field (VsrD(*) or VsrW(*)) 1977 * emin - minimum unbiased exponent 1978 * emax - maximum unbiased exponent 1979 * nbits - number of fraction bits 1980 */ 1981 #define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \ 1982 void helper_##op(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) \ 1983 { \ 1984 int i; \ 1985 int fe_flag = 0; \ 1986 int fg_flag = 0; \ 1987 \ 1988 for (i = 0; i < nels; i++) { \ 1989 if (unlikely(tp##_is_infinity(xb->fld) || \ 1990 tp##_is_zero(xb->fld))) { \ 1991 fe_flag = 1; \ 1992 fg_flag = 1; \ 1993 } else { \ 1994 int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \ 1995 \ 1996 if (unlikely(tp##_is_any_nan(xb->fld))) { \ 1997 fe_flag = 1; \ 1998 } else if (unlikely(tp##_is_zero(xb->fld))) { \ 1999 fe_flag = 1; \ 2000 } else if (unlikely(tp##_is_neg(xb->fld))) { \ 2001 fe_flag = 1; \ 2002 } else if (!tp##_is_zero(xb->fld) && \ 2003 (e_b <= (emin + nbits))) { \ 2004 fe_flag = 1; \ 2005 } \ 2006 \ 2007 if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \ 2008 /* \ 2009 * XB is not zero because of the above check and \ 2010 * therefore must be denormalized. \ 2011 */ \ 2012 fg_flag = 1; \ 2013 } \ 2014 } \ 2015 } \ 2016 \ 2017 env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \ 2018 } 2019 2020 VSX_TSQRT(xstsqrtdp, 1, float64, VsrD(0), -1022, 52) 2021 VSX_TSQRT(xvtsqrtdp, 2, float64, VsrD(i), -1022, 52) 2022 VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23) 2023 2024 /* 2025 * VSX_MADD - VSX floating point muliply/add variations 2026 * op - instruction mnemonic 2027 * nels - number of elements (1, 2 or 4) 2028 * tp - type (float32 or float64) 2029 * fld - vsr_t field (VsrD(*) or VsrW(*)) 2030 * maddflgs - flags for the float*muladd routine that control the 2031 * various forms (madd, msub, nmadd, nmsub) 2032 * sfifprf - set FI and FPRF 2033 */ 2034 #define VSX_MADD(op, nels, tp, fld, maddflgs, sfifprf) \ 2035 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ 2036 ppc_vsr_t *s1, ppc_vsr_t *s2, ppc_vsr_t *s3) \ 2037 { \ 2038 ppc_vsr_t t = { }; \ 2039 int i; \ 2040 \ 2041 helper_reset_fpstatus(env); \ 2042 \ 2043 for (i = 0; i < nels; i++) { \ 2044 float_status tstat = env->fp_status; \ 2045 set_float_exception_flags(0, &tstat); \ 2046 t.fld = tp##_muladd(s1->fld, s3->fld, s2->fld, maddflgs, &tstat); \ 2047 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ 2048 \ 2049 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ 2050 float_invalid_op_madd(env, tstat.float_exception_flags, \ 2051 sfifprf, GETPC()); \ 2052 } \ 2053 \ 2054 if (sfifprf) { \ 2055 helper_compute_fprf_float64(env, t.fld); \ 2056 } \ 2057 } \ 2058 *xt = t; \ 2059 do_float_check_status(env, sfifprf, GETPC()); \ 2060 } 2061 2062 VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1) 2063 VSX_MADD(XSMSUBDP, 1, float64, VsrD(0), MSUB_FLGS, 1) 2064 VSX_MADD(XSNMADDDP, 1, float64, VsrD(0), NMADD_FLGS, 1) 2065 VSX_MADD(XSNMSUBDP, 1, float64, VsrD(0), NMSUB_FLGS, 1) 2066 VSX_MADD(XSMADDSP, 1, float64r32, VsrD(0), MADD_FLGS, 1) 2067 VSX_MADD(XSMSUBSP, 1, float64r32, VsrD(0), MSUB_FLGS, 1) 2068 VSX_MADD(XSNMADDSP, 1, float64r32, VsrD(0), NMADD_FLGS, 1) 2069 VSX_MADD(XSNMSUBSP, 1, float64r32, VsrD(0), NMSUB_FLGS, 1) 2070 2071 VSX_MADD(xvmadddp, 2, float64, VsrD(i), MADD_FLGS, 0) 2072 VSX_MADD(xvmsubdp, 2, float64, VsrD(i), MSUB_FLGS, 0) 2073 VSX_MADD(xvnmadddp, 2, float64, VsrD(i), NMADD_FLGS, 0) 2074 VSX_MADD(xvnmsubdp, 2, float64, VsrD(i), NMSUB_FLGS, 0) 2075 2076 VSX_MADD(xvmaddsp, 4, float32, VsrW(i), MADD_FLGS, 0) 2077 VSX_MADD(xvmsubsp, 4, float32, VsrW(i), MSUB_FLGS, 0) 2078 VSX_MADD(xvnmaddsp, 4, float32, VsrW(i), NMADD_FLGS, 0) 2079 VSX_MADD(xvnmsubsp, 4, float32, VsrW(i), NMSUB_FLGS, 0) 2080 2081 /* 2082 * VSX_MADDQ - VSX floating point quad-precision muliply/add 2083 * op - instruction mnemonic 2084 * maddflgs - flags for the float*muladd routine that control the 2085 * various forms (madd, msub, nmadd, nmsub) 2086 * ro - round to odd 2087 */ 2088 #define VSX_MADDQ(op, maddflgs, ro) \ 2089 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *s1, ppc_vsr_t *s2,\ 2090 ppc_vsr_t *s3) \ 2091 { \ 2092 ppc_vsr_t t = *xt; \ 2093 \ 2094 helper_reset_fpstatus(env); \ 2095 \ 2096 float_status tstat = env->fp_status; \ 2097 set_float_exception_flags(0, &tstat); \ 2098 if (ro) { \ 2099 tstat.float_rounding_mode = float_round_to_odd; \ 2100 } \ 2101 t.f128 = float128_muladd(s1->f128, s3->f128, s2->f128, maddflgs, &tstat); \ 2102 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ 2103 \ 2104 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ 2105 float_invalid_op_madd(env, tstat.float_exception_flags, \ 2106 false, GETPC()); \ 2107 } \ 2108 \ 2109 helper_compute_fprf_float128(env, t.f128); \ 2110 *xt = t; \ 2111 do_float_check_status(env, true, GETPC()); \ 2112 } 2113 2114 VSX_MADDQ(XSMADDQP, MADD_FLGS, 0) 2115 VSX_MADDQ(XSMADDQPO, MADD_FLGS, 1) 2116 VSX_MADDQ(XSMSUBQP, MSUB_FLGS, 0) 2117 VSX_MADDQ(XSMSUBQPO, MSUB_FLGS, 1) 2118 VSX_MADDQ(XSNMADDQP, NMADD_FLGS, 0) 2119 VSX_MADDQ(XSNMADDQPO, NMADD_FLGS, 1) 2120 VSX_MADDQ(XSNMSUBQP, NMSUB_FLGS, 0) 2121 VSX_MADDQ(XSNMSUBQPO, NMSUB_FLGS, 0) 2122 2123 /* 2124 * VSX_SCALAR_CMP - VSX scalar floating point compare 2125 * op - instruction mnemonic 2126 * tp - type 2127 * cmp - comparison operation 2128 * fld - vsr_t field 2129 * svxvc - set VXVC bit 2130 */ 2131 #define VSX_SCALAR_CMP(op, tp, cmp, fld, svxvc) \ 2132 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ 2133 ppc_vsr_t *xa, ppc_vsr_t *xb) \ 2134 { \ 2135 int flags; \ 2136 bool r, vxvc; \ 2137 \ 2138 helper_reset_fpstatus(env); \ 2139 \ 2140 if (svxvc) { \ 2141 r = tp##_##cmp(xb->fld, xa->fld, &env->fp_status); \ 2142 } else { \ 2143 r = tp##_##cmp##_quiet(xb->fld, xa->fld, &env->fp_status); \ 2144 } \ 2145 \ 2146 flags = get_float_exception_flags(&env->fp_status); \ 2147 if (unlikely(flags & float_flag_invalid)) { \ 2148 vxvc = svxvc; \ 2149 if (flags & float_flag_invalid_snan) { \ 2150 float_invalid_op_vxsnan(env, GETPC()); \ 2151 vxvc &= !(env->fpscr & FP_VE); \ 2152 } \ 2153 if (vxvc) { \ 2154 float_invalid_op_vxvc(env, 0, GETPC()); \ 2155 } \ 2156 } \ 2157 \ 2158 memset(xt, 0, sizeof(*xt)); \ 2159 memset(&xt->fld, -r, sizeof(xt->fld)); \ 2160 do_float_check_status(env, false, GETPC()); \ 2161 } 2162 2163 VSX_SCALAR_CMP(XSCMPEQDP, float64, eq, VsrD(0), 0) 2164 VSX_SCALAR_CMP(XSCMPGEDP, float64, le, VsrD(0), 1) 2165 VSX_SCALAR_CMP(XSCMPGTDP, float64, lt, VsrD(0), 1) 2166 VSX_SCALAR_CMP(XSCMPEQQP, float128, eq, f128, 0) 2167 VSX_SCALAR_CMP(XSCMPGEQP, float128, le, f128, 1) 2168 VSX_SCALAR_CMP(XSCMPGTQP, float128, lt, f128, 1) 2169 2170 void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode, 2171 ppc_vsr_t *xa, ppc_vsr_t *xb) 2172 { 2173 int64_t exp_a, exp_b; 2174 uint32_t cc; 2175 2176 exp_a = extract64(xa->VsrD(0), 52, 11); 2177 exp_b = extract64(xb->VsrD(0), 52, 11); 2178 2179 if (unlikely(float64_is_any_nan(xa->VsrD(0)) || 2180 float64_is_any_nan(xb->VsrD(0)))) { 2181 cc = CRF_SO; 2182 } else { 2183 if (exp_a < exp_b) { 2184 cc = CRF_LT; 2185 } else if (exp_a > exp_b) { 2186 cc = CRF_GT; 2187 } else { 2188 cc = CRF_EQ; 2189 } 2190 } 2191 2192 env->fpscr &= ~FP_FPCC; 2193 env->fpscr |= cc << FPSCR_FPCC; 2194 env->crf[BF(opcode)] = cc; 2195 2196 do_float_check_status(env, false, GETPC()); 2197 } 2198 2199 void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, 2200 ppc_vsr_t *xa, ppc_vsr_t *xb) 2201 { 2202 int64_t exp_a, exp_b; 2203 uint32_t cc; 2204 2205 exp_a = extract64(xa->VsrD(0), 48, 15); 2206 exp_b = extract64(xb->VsrD(0), 48, 15); 2207 2208 if (unlikely(float128_is_any_nan(xa->f128) || 2209 float128_is_any_nan(xb->f128))) { 2210 cc = CRF_SO; 2211 } else { 2212 if (exp_a < exp_b) { 2213 cc = CRF_LT; 2214 } else if (exp_a > exp_b) { 2215 cc = CRF_GT; 2216 } else { 2217 cc = CRF_EQ; 2218 } 2219 } 2220 2221 env->fpscr &= ~FP_FPCC; 2222 env->fpscr |= cc << FPSCR_FPCC; 2223 env->crf[BF(opcode)] = cc; 2224 2225 do_float_check_status(env, false, GETPC()); 2226 } 2227 2228 static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, 2229 int crf_idx, bool ordered) 2230 { 2231 uint32_t cc; 2232 bool vxsnan_flag = false, vxvc_flag = false; 2233 2234 helper_reset_fpstatus(env); 2235 2236 switch (float64_compare(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { 2237 case float_relation_less: 2238 cc = CRF_LT; 2239 break; 2240 case float_relation_equal: 2241 cc = CRF_EQ; 2242 break; 2243 case float_relation_greater: 2244 cc = CRF_GT; 2245 break; 2246 case float_relation_unordered: 2247 cc = CRF_SO; 2248 2249 if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || 2250 float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { 2251 vxsnan_flag = true; 2252 if (!(env->fpscr & FP_VE) && ordered) { 2253 vxvc_flag = true; 2254 } 2255 } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || 2256 float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) { 2257 if (ordered) { 2258 vxvc_flag = true; 2259 } 2260 } 2261 2262 break; 2263 default: 2264 g_assert_not_reached(); 2265 } 2266 2267 env->fpscr &= ~FP_FPCC; 2268 env->fpscr |= cc << FPSCR_FPCC; 2269 env->crf[crf_idx] = cc; 2270 2271 if (vxsnan_flag) { 2272 float_invalid_op_vxsnan(env, GETPC()); 2273 } 2274 if (vxvc_flag) { 2275 float_invalid_op_vxvc(env, 0, GETPC()); 2276 } 2277 2278 do_float_check_status(env, false, GETPC()); 2279 } 2280 2281 void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, 2282 ppc_vsr_t *xb) 2283 { 2284 do_scalar_cmp(env, xa, xb, BF(opcode), true); 2285 } 2286 2287 void helper_xscmpudp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, 2288 ppc_vsr_t *xb) 2289 { 2290 do_scalar_cmp(env, xa, xb, BF(opcode), false); 2291 } 2292 2293 static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa, 2294 ppc_vsr_t *xb, int crf_idx, bool ordered) 2295 { 2296 uint32_t cc; 2297 bool vxsnan_flag = false, vxvc_flag = false; 2298 2299 helper_reset_fpstatus(env); 2300 2301 switch (float128_compare(xa->f128, xb->f128, &env->fp_status)) { 2302 case float_relation_less: 2303 cc = CRF_LT; 2304 break; 2305 case float_relation_equal: 2306 cc = CRF_EQ; 2307 break; 2308 case float_relation_greater: 2309 cc = CRF_GT; 2310 break; 2311 case float_relation_unordered: 2312 cc = CRF_SO; 2313 2314 if (float128_is_signaling_nan(xa->f128, &env->fp_status) || 2315 float128_is_signaling_nan(xb->f128, &env->fp_status)) { 2316 vxsnan_flag = true; 2317 if (!(env->fpscr & FP_VE) && ordered) { 2318 vxvc_flag = true; 2319 } 2320 } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || 2321 float128_is_quiet_nan(xb->f128, &env->fp_status)) { 2322 if (ordered) { 2323 vxvc_flag = true; 2324 } 2325 } 2326 2327 break; 2328 default: 2329 g_assert_not_reached(); 2330 } 2331 2332 env->fpscr &= ~FP_FPCC; 2333 env->fpscr |= cc << FPSCR_FPCC; 2334 env->crf[crf_idx] = cc; 2335 2336 if (vxsnan_flag) { 2337 float_invalid_op_vxsnan(env, GETPC()); 2338 } 2339 if (vxvc_flag) { 2340 float_invalid_op_vxvc(env, 0, GETPC()); 2341 } 2342 2343 do_float_check_status(env, false, GETPC()); 2344 } 2345 2346 void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, 2347 ppc_vsr_t *xb) 2348 { 2349 do_scalar_cmpq(env, xa, xb, BF(opcode), true); 2350 } 2351 2352 void helper_xscmpuqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, 2353 ppc_vsr_t *xb) 2354 { 2355 do_scalar_cmpq(env, xa, xb, BF(opcode), false); 2356 } 2357 2358 /* 2359 * VSX_MAX_MIN - VSX floating point maximum/minimum 2360 * name - instruction mnemonic 2361 * op - operation (max or min) 2362 * nels - number of elements (1, 2 or 4) 2363 * tp - type (float32 or float64) 2364 * fld - vsr_t field (VsrD(*) or VsrW(*)) 2365 */ 2366 #define VSX_MAX_MIN(name, op, nels, tp, fld) \ 2367 void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ 2368 ppc_vsr_t *xa, ppc_vsr_t *xb) \ 2369 { \ 2370 ppc_vsr_t t = { }; \ 2371 int i; \ 2372 \ 2373 for (i = 0; i < nels; i++) { \ 2374 t.fld = tp##_##op(xa->fld, xb->fld, &env->fp_status); \ 2375 if (unlikely(tp##_is_signaling_nan(xa->fld, &env->fp_status) || \ 2376 tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \ 2377 float_invalid_op_vxsnan(env, GETPC()); \ 2378 } \ 2379 } \ 2380 \ 2381 *xt = t; \ 2382 do_float_check_status(env, false, GETPC()); \ 2383 } 2384 2385 VSX_MAX_MIN(XSMAXDP, maxnum, 1, float64, VsrD(0)) 2386 VSX_MAX_MIN(XVMAXDP, maxnum, 2, float64, VsrD(i)) 2387 VSX_MAX_MIN(XVMAXSP, maxnum, 4, float32, VsrW(i)) 2388 VSX_MAX_MIN(XSMINDP, minnum, 1, float64, VsrD(0)) 2389 VSX_MAX_MIN(XVMINDP, minnum, 2, float64, VsrD(i)) 2390 VSX_MAX_MIN(XVMINSP, minnum, 4, float32, VsrW(i)) 2391 2392 #define VSX_MAX_MINC(name, max, tp, fld) \ 2393 void helper_##name(CPUPPCState *env, \ 2394 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \ 2395 { \ 2396 ppc_vsr_t t = { }; \ 2397 bool first; \ 2398 \ 2399 helper_reset_fpstatus(env); \ 2400 \ 2401 if (max) { \ 2402 first = tp##_le_quiet(xb->fld, xa->fld, &env->fp_status); \ 2403 } else { \ 2404 first = tp##_lt_quiet(xa->fld, xb->fld, &env->fp_status); \ 2405 } \ 2406 \ 2407 if (first) { \ 2408 t.fld = xa->fld; \ 2409 } else { \ 2410 t.fld = xb->fld; \ 2411 if (env->fp_status.float_exception_flags & float_flag_invalid_snan) { \ 2412 float_invalid_op_vxsnan(env, GETPC()); \ 2413 } \ 2414 } \ 2415 \ 2416 *xt = t; \ 2417 } 2418 2419 VSX_MAX_MINC(XSMAXCDP, true, float64, VsrD(0)); 2420 VSX_MAX_MINC(XSMINCDP, false, float64, VsrD(0)); 2421 VSX_MAX_MINC(XSMAXCQP, true, float128, f128); 2422 VSX_MAX_MINC(XSMINCQP, false, float128, f128); 2423 2424 #define VSX_MAX_MINJ(name, max) \ 2425 void helper_##name(CPUPPCState *env, \ 2426 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \ 2427 { \ 2428 ppc_vsr_t t = { }; \ 2429 bool vxsnan_flag = false, vex_flag = false; \ 2430 \ 2431 if (unlikely(float64_is_any_nan(xa->VsrD(0)))) { \ 2432 if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status)) { \ 2433 vxsnan_flag = true; \ 2434 } \ 2435 t.VsrD(0) = xa->VsrD(0); \ 2436 } else if (unlikely(float64_is_any_nan(xb->VsrD(0)))) { \ 2437 if (float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \ 2438 vxsnan_flag = true; \ 2439 } \ 2440 t.VsrD(0) = xb->VsrD(0); \ 2441 } else if (float64_is_zero(xa->VsrD(0)) && \ 2442 float64_is_zero(xb->VsrD(0))) { \ 2443 if (max) { \ 2444 if (!float64_is_neg(xa->VsrD(0)) || \ 2445 !float64_is_neg(xb->VsrD(0))) { \ 2446 t.VsrD(0) = 0ULL; \ 2447 } else { \ 2448 t.VsrD(0) = 0x8000000000000000ULL; \ 2449 } \ 2450 } else { \ 2451 if (float64_is_neg(xa->VsrD(0)) || \ 2452 float64_is_neg(xb->VsrD(0))) { \ 2453 t.VsrD(0) = 0x8000000000000000ULL; \ 2454 } else { \ 2455 t.VsrD(0) = 0ULL; \ 2456 } \ 2457 } \ 2458 } else if ((max && \ 2459 !float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) || \ 2460 (!max && \ 2461 float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status))) { \ 2462 t.VsrD(0) = xa->VsrD(0); \ 2463 } else { \ 2464 t.VsrD(0) = xb->VsrD(0); \ 2465 } \ 2466 \ 2467 vex_flag = (env->fpscr & FP_VE) && vxsnan_flag; \ 2468 if (vxsnan_flag) { \ 2469 float_invalid_op_vxsnan(env, GETPC()); \ 2470 } \ 2471 if (!vex_flag) { \ 2472 *xt = t; \ 2473 } \ 2474 } \ 2475 2476 VSX_MAX_MINJ(XSMAXJDP, 1); 2477 VSX_MAX_MINJ(XSMINJDP, 0); 2478 2479 /* 2480 * VSX_CMP - VSX floating point compare 2481 * op - instruction mnemonic 2482 * nels - number of elements (1, 2 or 4) 2483 * tp - type (float32 or float64) 2484 * fld - vsr_t field (VsrD(*) or VsrW(*)) 2485 * cmp - comparison operation 2486 * svxvc - set VXVC bit 2487 * exp - expected result of comparison 2488 */ 2489 #define VSX_CMP(op, nels, tp, fld, cmp, svxvc, exp) \ 2490 uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ 2491 ppc_vsr_t *xa, ppc_vsr_t *xb) \ 2492 { \ 2493 ppc_vsr_t t = *xt; \ 2494 uint32_t crf6 = 0; \ 2495 int i; \ 2496 int all_true = 1; \ 2497 int all_false = 1; \ 2498 \ 2499 helper_reset_fpstatus(env); \ 2500 \ 2501 for (i = 0; i < nels; i++) { \ 2502 if (unlikely(tp##_is_any_nan(xa->fld) || \ 2503 tp##_is_any_nan(xb->fld))) { \ 2504 if (tp##_is_signaling_nan(xa->fld, &env->fp_status) || \ 2505 tp##_is_signaling_nan(xb->fld, &env->fp_status)) { \ 2506 float_invalid_op_vxsnan(env, GETPC()); \ 2507 } \ 2508 if (svxvc) { \ 2509 float_invalid_op_vxvc(env, 0, GETPC()); \ 2510 } \ 2511 t.fld = 0; \ 2512 all_true = 0; \ 2513 } else { \ 2514 if (tp##_##cmp(xb->fld, xa->fld, &env->fp_status) == exp) { \ 2515 t.fld = -1; \ 2516 all_false = 0; \ 2517 } else { \ 2518 t.fld = 0; \ 2519 all_true = 0; \ 2520 } \ 2521 } \ 2522 } \ 2523 \ 2524 *xt = t; \ 2525 crf6 = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \ 2526 return crf6; \ 2527 } 2528 2529 VSX_CMP(XVCMPEQDP, 2, float64, VsrD(i), eq, 0, 1) 2530 VSX_CMP(XVCMPGEDP, 2, float64, VsrD(i), le, 1, 1) 2531 VSX_CMP(XVCMPGTDP, 2, float64, VsrD(i), lt, 1, 1) 2532 VSX_CMP(XVCMPNEDP, 2, float64, VsrD(i), eq, 0, 0) 2533 VSX_CMP(XVCMPEQSP, 4, float32, VsrW(i), eq, 0, 1) 2534 VSX_CMP(XVCMPGESP, 4, float32, VsrW(i), le, 1, 1) 2535 VSX_CMP(XVCMPGTSP, 4, float32, VsrW(i), lt, 1, 1) 2536 VSX_CMP(XVCMPNESP, 4, float32, VsrW(i), eq, 0, 0) 2537 2538 /* 2539 * VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion 2540 * op - instruction mnemonic 2541 * nels - number of elements (1, 2 or 4) 2542 * stp - source type (float32 or float64) 2543 * ttp - target type (float32 or float64) 2544 * sfld - source vsr_t field 2545 * tfld - target vsr_t field (f32 or f64) 2546 * sfifprf - set FI and FPRF 2547 */ 2548 #define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf) \ 2549 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2550 { \ 2551 ppc_vsr_t t = { }; \ 2552 int i; \ 2553 \ 2554 helper_reset_fpstatus(env); \ 2555 \ 2556 for (i = 0; i < nels; i++) { \ 2557 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ 2558 if (unlikely(stp##_is_signaling_nan(xb->sfld, \ 2559 &env->fp_status))) { \ 2560 float_invalid_op_vxsnan(env, GETPC()); \ 2561 t.tfld = ttp##_snan_to_qnan(t.tfld); \ 2562 } \ 2563 if (sfifprf) { \ 2564 helper_compute_fprf_##ttp(env, t.tfld); \ 2565 } \ 2566 } \ 2567 \ 2568 *xt = t; \ 2569 do_float_check_status(env, sfifprf, GETPC()); \ 2570 } 2571 2572 VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1) 2573 VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0) 2574 2575 #define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfifprf) \ 2576 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2577 { \ 2578 ppc_vsr_t t = { }; \ 2579 int i; \ 2580 \ 2581 helper_reset_fpstatus(env); \ 2582 \ 2583 for (i = 0; i < nels; i++) { \ 2584 t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \ 2585 if (unlikely(stp##_is_signaling_nan(xb->VsrD(i), \ 2586 &env->fp_status))) { \ 2587 float_invalid_op_vxsnan(env, GETPC()); \ 2588 t.VsrW(2 * i) = ttp##_snan_to_qnan(t.VsrW(2 * i)); \ 2589 } \ 2590 if (sfifprf) { \ 2591 helper_compute_fprf_##ttp(env, t.VsrW(2 * i)); \ 2592 } \ 2593 t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ 2594 } \ 2595 \ 2596 *xt = t; \ 2597 do_float_check_status(env, sfifprf, GETPC()); \ 2598 } 2599 2600 VSX_CVT_FP_TO_FP2(xvcvdpsp, 2, float64, float32, 0) 2601 VSX_CVT_FP_TO_FP2(xscvdpsp, 1, float64, float32, 1) 2602 2603 /* 2604 * VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion 2605 * op - instruction mnemonic 2606 * nels - number of elements (1, 2 or 4) 2607 * stp - source type (float32 or float64) 2608 * ttp - target type (float32 or float64) 2609 * sfld - source vsr_t field 2610 * tfld - target vsr_t field (f32 or f64) 2611 * sfprf - set FPRF 2612 */ 2613 #define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \ 2614 void helper_##op(CPUPPCState *env, uint32_t opcode, \ 2615 ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2616 { \ 2617 ppc_vsr_t t = *xt; \ 2618 int i; \ 2619 \ 2620 helper_reset_fpstatus(env); \ 2621 \ 2622 for (i = 0; i < nels; i++) { \ 2623 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ 2624 if (unlikely(stp##_is_signaling_nan(xb->sfld, \ 2625 &env->fp_status))) { \ 2626 float_invalid_op_vxsnan(env, GETPC()); \ 2627 t.tfld = ttp##_snan_to_qnan(t.tfld); \ 2628 } \ 2629 if (sfprf) { \ 2630 helper_compute_fprf_##ttp(env, t.tfld); \ 2631 } \ 2632 } \ 2633 \ 2634 *xt = t; \ 2635 do_float_check_status(env, true, GETPC()); \ 2636 } 2637 2638 VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) 2639 2640 /* 2641 * VSX_CVT_FP_TO_FP_HP - VSX floating point/floating point conversion 2642 * involving one half precision value 2643 * op - instruction mnemonic 2644 * nels - number of elements (1, 2 or 4) 2645 * stp - source type 2646 * ttp - target type 2647 * sfld - source vsr_t field 2648 * tfld - target vsr_t field 2649 * sfifprf - set FI and FPRF 2650 */ 2651 #define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfifprf) \ 2652 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2653 { \ 2654 ppc_vsr_t t = { }; \ 2655 int i; \ 2656 \ 2657 helper_reset_fpstatus(env); \ 2658 \ 2659 for (i = 0; i < nels; i++) { \ 2660 t.tfld = stp##_to_##ttp(xb->sfld, 1, &env->fp_status); \ 2661 if (unlikely(stp##_is_signaling_nan(xb->sfld, \ 2662 &env->fp_status))) { \ 2663 float_invalid_op_vxsnan(env, GETPC()); \ 2664 t.tfld = ttp##_snan_to_qnan(t.tfld); \ 2665 } \ 2666 if (sfifprf) { \ 2667 helper_compute_fprf_##ttp(env, t.tfld); \ 2668 } \ 2669 } \ 2670 \ 2671 *xt = t; \ 2672 do_float_check_status(env, sfifprf, GETPC()); \ 2673 } 2674 2675 VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1) 2676 VSX_CVT_FP_TO_FP_HP(xscvhpdp, 1, float16, float64, VsrH(3), VsrD(0), 1) 2677 VSX_CVT_FP_TO_FP_HP(xvcvsphp, 4, float32, float16, VsrW(i), VsrH(2 * i + 1), 0) 2678 VSX_CVT_FP_TO_FP_HP(xvcvhpsp, 4, float16, float32, VsrH(2 * i + 1), VsrW(i), 0) 2679 2680 void helper_XVCVSPBF16(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) 2681 { 2682 ppc_vsr_t t = { }; 2683 int i, status; 2684 2685 helper_reset_fpstatus(env); 2686 2687 for (i = 0; i < 4; i++) { 2688 t.VsrH(2 * i + 1) = float32_to_bfloat16(xb->VsrW(i), &env->fp_status); 2689 } 2690 2691 status = get_float_exception_flags(&env->fp_status); 2692 if (unlikely(status & float_flag_invalid_snan)) { 2693 float_invalid_op_vxsnan(env, GETPC()); 2694 } 2695 2696 *xt = t; 2697 do_float_check_status(env, false, GETPC()); 2698 } 2699 2700 void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt, 2701 ppc_vsr_t *xb) 2702 { 2703 ppc_vsr_t t = { }; 2704 float_status tstat; 2705 2706 helper_reset_fpstatus(env); 2707 2708 tstat = env->fp_status; 2709 if (ro != 0) { 2710 tstat.float_rounding_mode = float_round_to_odd; 2711 } 2712 2713 t.VsrD(0) = float128_to_float64(xb->f128, &tstat); 2714 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 2715 if (unlikely(float128_is_signaling_nan(xb->f128, &tstat))) { 2716 float_invalid_op_vxsnan(env, GETPC()); 2717 t.VsrD(0) = float64_snan_to_qnan(t.VsrD(0)); 2718 } 2719 helper_compute_fprf_float64(env, t.VsrD(0)); 2720 2721 *xt = t; 2722 do_float_check_status(env, true, GETPC()); 2723 } 2724 2725 uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) 2726 { 2727 uint64_t result, sign, exp, frac; 2728 2729 helper_reset_fpstatus(env); 2730 float_status tstat = env->fp_status; 2731 set_float_exception_flags(0, &tstat); 2732 2733 sign = extract64(xb, 63, 1); 2734 exp = extract64(xb, 52, 11); 2735 frac = extract64(xb, 0, 52) | 0x10000000000000ULL; 2736 2737 if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) { 2738 /* DP denormal operand. */ 2739 /* Exponent override to DP min exp. */ 2740 exp = 1; 2741 /* Implicit bit override to 0. */ 2742 frac = deposit64(frac, 53, 1, 0); 2743 } 2744 2745 if (unlikely(exp < 897 && frac != 0)) { 2746 /* SP tiny operand. */ 2747 if (897 - exp > 63) { 2748 frac = 0; 2749 } else { 2750 /* Denormalize until exp = SP min exp. */ 2751 frac >>= (897 - exp); 2752 } 2753 /* Exponent override to SP min exp - 1. */ 2754 exp = 896; 2755 } 2756 2757 result = sign << 31; 2758 result |= extract64(exp, 10, 1) << 30; 2759 result |= extract64(exp, 0, 7) << 23; 2760 result |= extract64(frac, 29, 23); 2761 2762 /* hardware replicates result to both words of the doubleword result. */ 2763 return (result << 32) | result; 2764 } 2765 2766 uint64_t helper_XSCVSPDPN(uint64_t xb) 2767 { 2768 return helper_todouble(xb >> 32); 2769 } 2770 2771 /* 2772 * VSX_CVT_FP_TO_INT - VSX floating point to integer conversion 2773 * op - instruction mnemonic 2774 * nels - number of elements (1, 2 or 4) 2775 * stp - source type (float32 or float64) 2776 * ttp - target type (int32, uint32, int64 or uint64) 2777 * sfld - source vsr_t field 2778 * tfld - target vsr_t field 2779 * sfi - set FI 2780 * rnan - resulting NaN 2781 */ 2782 #define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, sfi, rnan) \ 2783 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2784 { \ 2785 int all_flags = 0; \ 2786 ppc_vsr_t t = { }; \ 2787 int i, flags; \ 2788 \ 2789 for (i = 0; i < nels; i++) { \ 2790 helper_reset_fpstatus(env); \ 2791 t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \ 2792 flags = env->fp_status.float_exception_flags; \ 2793 all_flags |= flags; \ 2794 if (unlikely(flags & float_flag_invalid)) { \ 2795 t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC());\ 2796 } \ 2797 } \ 2798 \ 2799 *xt = t; \ 2800 env->fp_status.float_exception_flags = all_flags; \ 2801 do_float_check_status(env, sfi, GETPC()); \ 2802 } 2803 2804 VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), true, \ 2805 0x8000000000000000ULL) 2806 VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), true, 0ULL) 2807 VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), false, \ 2808 0x8000000000000000ULL) 2809 VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), false, \ 2810 0ULL) 2811 VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), false, \ 2812 0x8000000000000000ULL) 2813 VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), false, \ 2814 0x80000000ULL) 2815 VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), \ 2816 false, 0ULL) 2817 VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), false, 0U) 2818 2819 #define VSX_CVT_FP_TO_INT128(op, tp, rnan) \ 2820 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2821 { \ 2822 ppc_vsr_t t; \ 2823 int flags; \ 2824 \ 2825 helper_reset_fpstatus(env); \ 2826 t.s128 = float128_to_##tp##_round_to_zero(xb->f128, &env->fp_status); \ 2827 flags = get_float_exception_flags(&env->fp_status); \ 2828 if (unlikely(flags & float_flag_invalid)) { \ 2829 t.VsrD(0) = float_invalid_cvt(env, flags, t.VsrD(0), rnan, 0, GETPC());\ 2830 t.VsrD(1) = -(t.VsrD(0) & 1); \ 2831 } \ 2832 \ 2833 *xt = t; \ 2834 do_float_check_status(env, true, GETPC()); \ 2835 } 2836 2837 VSX_CVT_FP_TO_INT128(XSCVQPUQZ, uint128, 0) 2838 VSX_CVT_FP_TO_INT128(XSCVQPSQZ, int128, 0x8000000000000000ULL); 2839 2840 /* 2841 * Likewise, except that the result is duplicated into both subwords. 2842 * Power ISA v3.1 has Programming Notes for these insns: 2843 * Previous versions of the architecture allowed the contents of 2844 * word 0 of the result register to be undefined. However, all 2845 * processors that support this instruction write the result into 2846 * words 0 and 1 (and words 2 and 3) of the result register, as 2847 * is required by this version of the architecture. 2848 */ 2849 #define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, sfi, rnan) \ 2850 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2851 { \ 2852 int all_flags = 0; \ 2853 ppc_vsr_t t = { }; \ 2854 int i, flags; \ 2855 \ 2856 for (i = 0; i < nels; i++) { \ 2857 helper_reset_fpstatus(env); \ 2858 t.VsrW(2 * i) = stp##_to_##ttp##_round_to_zero(xb->VsrD(i), \ 2859 &env->fp_status); \ 2860 flags = env->fp_status.float_exception_flags; \ 2861 all_flags |= flags; \ 2862 if (unlikely(flags & float_flag_invalid)) { \ 2863 t.VsrW(2 * i) = float_invalid_cvt(env, flags, t.VsrW(2 * i), \ 2864 rnan, 0, GETPC()); \ 2865 } \ 2866 t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ 2867 } \ 2868 \ 2869 *xt = t; \ 2870 env->fp_status.float_exception_flags = all_flags; \ 2871 do_float_check_status(env, sfi, GETPC()); \ 2872 } 2873 2874 VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, true, 0x80000000U) 2875 VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, true, 0U) 2876 VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, false, 0x80000000U) 2877 VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, false, 0U) 2878 2879 /* 2880 * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion 2881 * op - instruction mnemonic 2882 * stp - source type (float32 or float64) 2883 * ttp - target type (int32, uint32, int64 or uint64) 2884 * sfld - source vsr_t field 2885 * tfld - target vsr_t field 2886 * rnan - resulting NaN 2887 */ 2888 #define VSX_CVT_FP_TO_INT_VECTOR(op, stp, ttp, sfld, tfld, rnan) \ 2889 void helper_##op(CPUPPCState *env, uint32_t opcode, \ 2890 ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2891 { \ 2892 ppc_vsr_t t = { }; \ 2893 int flags; \ 2894 \ 2895 helper_reset_fpstatus(env); \ 2896 \ 2897 t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \ 2898 flags = get_float_exception_flags(&env->fp_status); \ 2899 if (flags & float_flag_invalid) { \ 2900 t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC()); \ 2901 } \ 2902 \ 2903 *xt = t; \ 2904 do_float_check_status(env, true, GETPC()); \ 2905 } 2906 2907 VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \ 2908 0x8000000000000000ULL) 2909 VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0), \ 2910 0xffffffff80000000ULL) 2911 VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL) 2912 VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL) 2913 2914 /* 2915 * VSX_CVT_INT_TO_FP - VSX integer to floating point conversion 2916 * op - instruction mnemonic 2917 * nels - number of elements (1, 2 or 4) 2918 * stp - source type (int32, uint32, int64 or uint64) 2919 * ttp - target type (float32 or float64) 2920 * sfld - source vsr_t field 2921 * tfld - target vsr_t field 2922 * jdef - definition of the j index (i or 2*i) 2923 * sfifprf - set FI and FPRF 2924 */ 2925 #define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf, r2sp)\ 2926 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2927 { \ 2928 ppc_vsr_t t = { }; \ 2929 int i; \ 2930 \ 2931 helper_reset_fpstatus(env); \ 2932 \ 2933 for (i = 0; i < nels; i++) { \ 2934 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ 2935 if (r2sp) { \ 2936 t.tfld = do_frsp(env, t.tfld, GETPC()); \ 2937 } \ 2938 if (sfifprf) { \ 2939 helper_compute_fprf_float64(env, t.tfld); \ 2940 } \ 2941 } \ 2942 \ 2943 *xt = t; \ 2944 do_float_check_status(env, sfifprf, GETPC()); \ 2945 } 2946 2947 VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) 2948 VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 0) 2949 VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, VsrD(0), VsrD(0), 1, 1) 2950 VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 1) 2951 VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, VsrD(i), VsrD(i), 0, 0) 2952 VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, VsrD(i), VsrD(i), 0, 0) 2953 VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2 * i), VsrD(i), 0, 0) 2954 VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2 * i), VsrD(i), 0, 0) 2955 VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0) 2956 VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0) 2957 2958 #define VSX_CVT_INT_TO_FP2(op, stp, ttp) \ 2959 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2960 { \ 2961 ppc_vsr_t t = { }; \ 2962 int i; \ 2963 \ 2964 for (i = 0; i < 2; i++) { \ 2965 t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \ 2966 t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ 2967 } \ 2968 \ 2969 *xt = t; \ 2970 do_float_check_status(env, false, GETPC()); \ 2971 } 2972 2973 VSX_CVT_INT_TO_FP2(xvcvsxdsp, int64, float32) 2974 VSX_CVT_INT_TO_FP2(xvcvuxdsp, uint64, float32) 2975 2976 #define VSX_CVT_INT128_TO_FP(op, tp) \ 2977 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)\ 2978 { \ 2979 helper_reset_fpstatus(env); \ 2980 xt->f128 = tp##_to_float128(xb->s128, &env->fp_status); \ 2981 helper_compute_fprf_float128(env, xt->f128); \ 2982 do_float_check_status(env, true, GETPC()); \ 2983 } 2984 2985 VSX_CVT_INT128_TO_FP(XSCVUQQP, uint128); 2986 VSX_CVT_INT128_TO_FP(XSCVSQQP, int128); 2987 2988 /* 2989 * VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion 2990 * op - instruction mnemonic 2991 * stp - source type (int32, uint32, int64 or uint64) 2992 * ttp - target type (float32 or float64) 2993 * sfld - source vsr_t field 2994 * tfld - target vsr_t field 2995 */ 2996 #define VSX_CVT_INT_TO_FP_VECTOR(op, stp, ttp, sfld, tfld) \ 2997 void helper_##op(CPUPPCState *env, uint32_t opcode, \ 2998 ppc_vsr_t *xt, ppc_vsr_t *xb) \ 2999 { \ 3000 ppc_vsr_t t = *xt; \ 3001 \ 3002 helper_reset_fpstatus(env); \ 3003 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ 3004 helper_compute_fprf_##ttp(env, t.tfld); \ 3005 \ 3006 *xt = t; \ 3007 do_float_check_status(env, true, GETPC()); \ 3008 } 3009 3010 VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128) 3011 VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128) 3012 3013 /* 3014 * For "use current rounding mode", define a value that will not be 3015 * one of the existing rounding model enums. 3016 */ 3017 #define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \ 3018 float_round_up + float_round_to_zero) 3019 3020 /* 3021 * VSX_ROUND - VSX floating point round 3022 * op - instruction mnemonic 3023 * nels - number of elements (1, 2 or 4) 3024 * tp - type (float32 or float64) 3025 * fld - vsr_t field (VsrD(*) or VsrW(*)) 3026 * rmode - rounding mode 3027 * sfifprf - set FI and FPRF 3028 */ 3029 #define VSX_ROUND(op, nels, tp, fld, rmode, sfifprf) \ 3030 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ 3031 { \ 3032 ppc_vsr_t t = { }; \ 3033 int i; \ 3034 FloatRoundMode curr_rounding_mode; \ 3035 \ 3036 helper_reset_fpstatus(env); \ 3037 \ 3038 if (rmode != FLOAT_ROUND_CURRENT) { \ 3039 curr_rounding_mode = get_float_rounding_mode(&env->fp_status); \ 3040 set_float_rounding_mode(rmode, &env->fp_status); \ 3041 } \ 3042 \ 3043 for (i = 0; i < nels; i++) { \ 3044 if (unlikely(tp##_is_signaling_nan(xb->fld, \ 3045 &env->fp_status))) { \ 3046 float_invalid_op_vxsnan(env, GETPC()); \ 3047 t.fld = tp##_snan_to_qnan(xb->fld); \ 3048 } else { \ 3049 t.fld = tp##_round_to_int(xb->fld, &env->fp_status); \ 3050 } \ 3051 if (sfifprf) { \ 3052 helper_compute_fprf_float64(env, t.fld); \ 3053 } \ 3054 } \ 3055 \ 3056 /* \ 3057 * If this is not a "use current rounding mode" instruction, \ 3058 * then inhibit setting of the XX bit and restore rounding \ 3059 * mode from FPSCR \ 3060 */ \ 3061 if (rmode != FLOAT_ROUND_CURRENT) { \ 3062 set_float_rounding_mode(curr_rounding_mode, &env->fp_status); \ 3063 env->fp_status.float_exception_flags &= ~float_flag_inexact; \ 3064 } \ 3065 \ 3066 *xt = t; \ 3067 do_float_check_status(env, sfifprf, GETPC()); \ 3068 } 3069 3070 VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) 3071 VSX_ROUND(xsrdpic, 1, float64, VsrD(0), FLOAT_ROUND_CURRENT, 1) 3072 VSX_ROUND(xsrdpim, 1, float64, VsrD(0), float_round_down, 1) 3073 VSX_ROUND(xsrdpip, 1, float64, VsrD(0), float_round_up, 1) 3074 VSX_ROUND(xsrdpiz, 1, float64, VsrD(0), float_round_to_zero, 1) 3075 3076 VSX_ROUND(xvrdpi, 2, float64, VsrD(i), float_round_ties_away, 0) 3077 VSX_ROUND(xvrdpic, 2, float64, VsrD(i), FLOAT_ROUND_CURRENT, 0) 3078 VSX_ROUND(xvrdpim, 2, float64, VsrD(i), float_round_down, 0) 3079 VSX_ROUND(xvrdpip, 2, float64, VsrD(i), float_round_up, 0) 3080 VSX_ROUND(xvrdpiz, 2, float64, VsrD(i), float_round_to_zero, 0) 3081 3082 VSX_ROUND(xvrspi, 4, float32, VsrW(i), float_round_ties_away, 0) 3083 VSX_ROUND(xvrspic, 4, float32, VsrW(i), FLOAT_ROUND_CURRENT, 0) 3084 VSX_ROUND(xvrspim, 4, float32, VsrW(i), float_round_down, 0) 3085 VSX_ROUND(xvrspip, 4, float32, VsrW(i), float_round_up, 0) 3086 VSX_ROUND(xvrspiz, 4, float32, VsrW(i), float_round_to_zero, 0) 3087 3088 uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) 3089 { 3090 helper_reset_fpstatus(env); 3091 3092 uint64_t xt = do_frsp(env, xb, GETPC()); 3093 3094 helper_compute_fprf_float64(env, xt); 3095 do_float_check_status(env, true, GETPC()); 3096 return xt; 3097 } 3098 3099 void helper_XVXSIGSP(ppc_vsr_t *xt, ppc_vsr_t *xb) 3100 { 3101 ppc_vsr_t t = { }; 3102 uint32_t exp, i, fraction; 3103 3104 for (i = 0; i < 4; i++) { 3105 exp = (xb->VsrW(i) >> 23) & 0xFF; 3106 fraction = xb->VsrW(i) & 0x7FFFFF; 3107 if (exp != 0 && exp != 255) { 3108 t.VsrW(i) = fraction | 0x00800000; 3109 } else { 3110 t.VsrW(i) = fraction; 3111 } 3112 } 3113 *xt = t; 3114 } 3115 3116 #define VSX_TSTDC(tp) \ 3117 static int32_t tp##_tstdc(tp b, uint32_t dcmx) \ 3118 { \ 3119 uint32_t match = 0; \ 3120 uint32_t sign = tp##_is_neg(b); \ 3121 if (tp##_is_any_nan(b)) { \ 3122 match = extract32(dcmx, 6, 1); \ 3123 } else if (tp##_is_infinity(b)) { \ 3124 match = extract32(dcmx, 4 + !sign, 1); \ 3125 } else if (tp##_is_zero(b)) { \ 3126 match = extract32(dcmx, 2 + !sign, 1); \ 3127 } else if (tp##_is_zero_or_denormal(b)) { \ 3128 match = extract32(dcmx, 0 + !sign, 1); \ 3129 } \ 3130 return (match != 0); \ 3131 } 3132 3133 VSX_TSTDC(float32) 3134 VSX_TSTDC(float64) 3135 VSX_TSTDC(float128) 3136 #undef VSX_TSTDC 3137 3138 void helper_XVTSTDCDP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) 3139 { 3140 int i; 3141 for (i = 0; i < 2; i++) { 3142 t->s64[i] = (int64_t)-float64_tstdc(b->f64[i], dcmx); 3143 } 3144 } 3145 3146 void helper_XVTSTDCSP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) 3147 { 3148 int i; 3149 for (i = 0; i < 4; i++) { 3150 t->s32[i] = (int32_t)-float32_tstdc(b->f32[i], dcmx); 3151 } 3152 } 3153 3154 static bool not_SP_value(float64 val) 3155 { 3156 return val != helper_todouble(helper_tosingle(val)); 3157 } 3158 3159 /* 3160 * VSX_XS_TSTDC - VSX Scalar Test Data Class 3161 * NAME - instruction name 3162 * FLD - vsr_t field (VsrD(0) or f128) 3163 * TP - type (float64 or float128) 3164 */ 3165 #define VSX_XS_TSTDC(NAME, FLD, TP) \ 3166 void helper_##NAME(CPUPPCState *env, uint32_t bf, \ 3167 uint32_t dcmx, ppc_vsr_t *b) \ 3168 { \ 3169 uint32_t cc, match, sign = TP##_is_neg(b->FLD); \ 3170 match = TP##_tstdc(b->FLD, dcmx); \ 3171 cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ 3172 env->fpscr &= ~FP_FPCC; \ 3173 env->fpscr |= cc << FPSCR_FPCC; \ 3174 env->crf[bf] = cc; \ 3175 } 3176 3177 VSX_XS_TSTDC(XSTSTDCDP, VsrD(0), float64) 3178 VSX_XS_TSTDC(XSTSTDCQP, f128, float128) 3179 #undef VSX_XS_TSTDC 3180 3181 void helper_XSTSTDCSP(CPUPPCState *env, uint32_t bf, 3182 uint32_t dcmx, ppc_vsr_t *b) 3183 { 3184 uint32_t cc, match, sign = float64_is_neg(b->VsrD(0)); 3185 uint32_t exp = (b->VsrD(0) >> 52) & 0x7FF; 3186 int not_sp = (int)not_SP_value(b->VsrD(0)); 3187 match = float64_tstdc(b->VsrD(0), dcmx) || (exp > 0 && exp < 0x381); 3188 cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT; 3189 env->fpscr &= ~FP_FPCC; 3190 env->fpscr |= cc << FPSCR_FPCC; 3191 env->crf[bf] = cc; 3192 } 3193 3194 void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, 3195 ppc_vsr_t *xt, ppc_vsr_t *xb) 3196 { 3197 ppc_vsr_t t = { }; 3198 uint8_t r = Rrm(opcode); 3199 uint8_t ex = Rc(opcode); 3200 uint8_t rmc = RMC(opcode); 3201 uint8_t rmode = 0; 3202 float_status tstat; 3203 3204 helper_reset_fpstatus(env); 3205 3206 if (r == 0 && rmc == 0) { 3207 rmode = float_round_ties_away; 3208 } else if (r == 0 && rmc == 0x3) { 3209 rmode = env->fpscr & FP_RN; 3210 } else if (r == 1) { 3211 switch (rmc) { 3212 case 0: 3213 rmode = float_round_nearest_even; 3214 break; 3215 case 1: 3216 rmode = float_round_to_zero; 3217 break; 3218 case 2: 3219 rmode = float_round_up; 3220 break; 3221 case 3: 3222 rmode = float_round_down; 3223 break; 3224 default: 3225 abort(); 3226 } 3227 } 3228 3229 tstat = env->fp_status; 3230 set_float_exception_flags(0, &tstat); 3231 set_float_rounding_mode(rmode, &tstat); 3232 t.f128 = float128_round_to_int(xb->f128, &tstat); 3233 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 3234 3235 if (unlikely(tstat.float_exception_flags & float_flag_invalid_snan)) { 3236 float_invalid_op_vxsnan(env, GETPC()); 3237 } 3238 3239 if (ex == 0 && (tstat.float_exception_flags & float_flag_inexact)) { 3240 env->fp_status.float_exception_flags &= ~float_flag_inexact; 3241 } 3242 3243 helper_compute_fprf_float128(env, t.f128); 3244 do_float_check_status(env, true, GETPC()); 3245 *xt = t; 3246 } 3247 3248 void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode, 3249 ppc_vsr_t *xt, ppc_vsr_t *xb) 3250 { 3251 ppc_vsr_t t = { }; 3252 uint8_t r = Rrm(opcode); 3253 uint8_t rmc = RMC(opcode); 3254 uint8_t rmode = 0; 3255 floatx80 round_res; 3256 float_status tstat; 3257 3258 helper_reset_fpstatus(env); 3259 3260 if (r == 0 && rmc == 0) { 3261 rmode = float_round_ties_away; 3262 } else if (r == 0 && rmc == 0x3) { 3263 rmode = env->fpscr & FP_RN; 3264 } else if (r == 1) { 3265 switch (rmc) { 3266 case 0: 3267 rmode = float_round_nearest_even; 3268 break; 3269 case 1: 3270 rmode = float_round_to_zero; 3271 break; 3272 case 2: 3273 rmode = float_round_up; 3274 break; 3275 case 3: 3276 rmode = float_round_down; 3277 break; 3278 default: 3279 abort(); 3280 } 3281 } 3282 3283 tstat = env->fp_status; 3284 set_float_exception_flags(0, &tstat); 3285 set_float_rounding_mode(rmode, &tstat); 3286 round_res = float128_to_floatx80(xb->f128, &tstat); 3287 t.f128 = floatx80_to_float128(round_res, &tstat); 3288 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 3289 3290 if (unlikely(tstat.float_exception_flags & float_flag_invalid_snan)) { 3291 float_invalid_op_vxsnan(env, GETPC()); 3292 t.f128 = float128_snan_to_qnan(t.f128); 3293 } 3294 3295 helper_compute_fprf_float128(env, t.f128); 3296 *xt = t; 3297 do_float_check_status(env, true, GETPC()); 3298 } 3299 3300 void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode, 3301 ppc_vsr_t *xt, ppc_vsr_t *xb) 3302 { 3303 ppc_vsr_t t = { }; 3304 float_status tstat; 3305 3306 helper_reset_fpstatus(env); 3307 3308 tstat = env->fp_status; 3309 if (unlikely(Rc(opcode) != 0)) { 3310 tstat.float_rounding_mode = float_round_to_odd; 3311 } 3312 3313 set_float_exception_flags(0, &tstat); 3314 t.f128 = float128_sqrt(xb->f128, &tstat); 3315 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 3316 3317 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { 3318 float_invalid_op_sqrt(env, tstat.float_exception_flags, 1, GETPC()); 3319 } 3320 3321 helper_compute_fprf_float128(env, t.f128); 3322 *xt = t; 3323 do_float_check_status(env, true, GETPC()); 3324 } 3325 3326 void helper_xssubqp(CPUPPCState *env, uint32_t opcode, 3327 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) 3328 { 3329 ppc_vsr_t t = *xt; 3330 float_status tstat; 3331 3332 helper_reset_fpstatus(env); 3333 3334 tstat = env->fp_status; 3335 if (unlikely(Rc(opcode) != 0)) { 3336 tstat.float_rounding_mode = float_round_to_odd; 3337 } 3338 3339 set_float_exception_flags(0, &tstat); 3340 t.f128 = float128_sub(xa->f128, xb->f128, &tstat); 3341 env->fp_status.float_exception_flags |= tstat.float_exception_flags; 3342 3343 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { 3344 float_invalid_op_addsub(env, tstat.float_exception_flags, 1, GETPC()); 3345 } 3346 3347 helper_compute_fprf_float128(env, t.f128); 3348 *xt = t; 3349 do_float_check_status(env, true, GETPC()); 3350 } 3351 3352 static inline void vsxger_excp(CPUPPCState *env, uintptr_t retaddr) 3353 { 3354 /* 3355 * XV*GER instructions execute and set the FPSCR as if exceptions 3356 * are disabled and only at the end throw an exception 3357 */ 3358 target_ulong enable; 3359 enable = env->fpscr & (FP_ENABLES | FP_FI | FP_FR); 3360 env->fpscr &= ~(FP_ENABLES | FP_FI | FP_FR); 3361 int status = get_float_exception_flags(&env->fp_status); 3362 if (unlikely(status & float_flag_invalid)) { 3363 if (status & float_flag_invalid_snan) { 3364 float_invalid_op_vxsnan(env, 0); 3365 } 3366 if (status & float_flag_invalid_imz) { 3367 float_invalid_op_vximz(env, false, 0); 3368 } 3369 if (status & float_flag_invalid_isi) { 3370 float_invalid_op_vxisi(env, false, 0); 3371 } 3372 } 3373 do_float_check_status(env, false, retaddr); 3374 env->fpscr |= enable; 3375 do_fpscr_check_status(env, retaddr); 3376 } 3377 3378 typedef float64 extract_f16(float16, float_status *); 3379 3380 static float64 extract_hf16(float16 in, float_status *fp_status) 3381 { 3382 return float16_to_float64(in, true, fp_status); 3383 } 3384 3385 static float64 extract_bf16(bfloat16 in, float_status *fp_status) 3386 { 3387 return bfloat16_to_float64(in, fp_status); 3388 } 3389 3390 static void vsxger16(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3391 ppc_acc_t *at, uint32_t mask, bool acc, 3392 bool neg_mul, bool neg_acc, extract_f16 extract) 3393 { 3394 float32 r, aux_acc; 3395 float64 psum, va, vb, vc, vd; 3396 int i, j, xmsk_bit, ymsk_bit; 3397 uint8_t pmsk = FIELD_EX32(mask, GER_MSK, PMSK), 3398 xmsk = FIELD_EX32(mask, GER_MSK, XMSK), 3399 ymsk = FIELD_EX32(mask, GER_MSK, YMSK); 3400 float_status *excp_ptr = &env->fp_status; 3401 for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { 3402 for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { 3403 if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { 3404 va = !(pmsk & 2) ? float64_zero : 3405 extract(a->VsrHF(2 * i), excp_ptr); 3406 vb = !(pmsk & 2) ? float64_zero : 3407 extract(b->VsrHF(2 * j), excp_ptr); 3408 vc = !(pmsk & 1) ? float64_zero : 3409 extract(a->VsrHF(2 * i + 1), excp_ptr); 3410 vd = !(pmsk & 1) ? float64_zero : 3411 extract(b->VsrHF(2 * j + 1), excp_ptr); 3412 psum = float64_mul(va, vb, excp_ptr); 3413 psum = float64r32_muladd(vc, vd, psum, 0, excp_ptr); 3414 r = float64_to_float32(psum, excp_ptr); 3415 if (acc) { 3416 aux_acc = at[i].VsrSF(j); 3417 if (neg_mul) { 3418 r = bfp32_neg(r); 3419 } 3420 if (neg_acc) { 3421 aux_acc = bfp32_neg(aux_acc); 3422 } 3423 r = float32_add(r, aux_acc, excp_ptr); 3424 } 3425 at[i].VsrSF(j) = r; 3426 } else { 3427 at[i].VsrSF(j) = float32_zero; 3428 } 3429 } 3430 } 3431 vsxger_excp(env, GETPC()); 3432 } 3433 3434 typedef void vsxger_zero(ppc_vsr_t *at, int, int); 3435 3436 typedef void vsxger_muladd_f(ppc_vsr_t *, ppc_vsr_t *, ppc_vsr_t *, int, int, 3437 int flags, float_status *s); 3438 3439 static void vsxger_muladd32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, 3440 int j, int flags, float_status *s) 3441 { 3442 at[i].VsrSF(j) = float32_muladd(a->VsrSF(i), b->VsrSF(j), 3443 at[i].VsrSF(j), flags, s); 3444 } 3445 3446 static void vsxger_mul32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, 3447 int j, int flags, float_status *s) 3448 { 3449 at[i].VsrSF(j) = float32_mul(a->VsrSF(i), b->VsrSF(j), s); 3450 } 3451 3452 static void vsxger_zero32(ppc_vsr_t *at, int i, int j) 3453 { 3454 at[i].VsrSF(j) = float32_zero; 3455 } 3456 3457 static void vsxger_muladd64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, 3458 int j, int flags, float_status *s) 3459 { 3460 if (j >= 2) { 3461 j -= 2; 3462 at[i].VsrDF(j) = float64_muladd(a[i / 2].VsrDF(i % 2), b->VsrDF(j), 3463 at[i].VsrDF(j), flags, s); 3464 } 3465 } 3466 3467 static void vsxger_mul64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i, 3468 int j, int flags, float_status *s) 3469 { 3470 if (j >= 2) { 3471 j -= 2; 3472 at[i].VsrDF(j) = float64_mul(a[i / 2].VsrDF(i % 2), b->VsrDF(j), s); 3473 } 3474 } 3475 3476 static void vsxger_zero64(ppc_vsr_t *at, int i, int j) 3477 { 3478 if (j >= 2) { 3479 j -= 2; 3480 at[i].VsrDF(j) = float64_zero; 3481 } 3482 } 3483 3484 static void vsxger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3485 ppc_acc_t *at, uint32_t mask, bool acc, bool neg_mul, 3486 bool neg_acc, vsxger_muladd_f mul, vsxger_muladd_f muladd, 3487 vsxger_zero zero) 3488 { 3489 int i, j, xmsk_bit, ymsk_bit, op_flags; 3490 uint8_t xmsk = mask & 0x0F; 3491 uint8_t ymsk = (mask >> 4) & 0x0F; 3492 float_status *excp_ptr = &env->fp_status; 3493 op_flags = (neg_acc ^ neg_mul) ? float_muladd_negate_c : 0; 3494 op_flags |= (neg_mul) ? float_muladd_negate_result : 0; 3495 helper_reset_fpstatus(env); 3496 for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) { 3497 for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) { 3498 if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) { 3499 if (acc) { 3500 muladd(at, a, b, i, j, op_flags, excp_ptr); 3501 } else { 3502 mul(at, a, b, i, j, op_flags, excp_ptr); 3503 } 3504 } else { 3505 zero(at, i, j); 3506 } 3507 } 3508 } 3509 vsxger_excp(env, GETPC()); 3510 } 3511 3512 QEMU_FLATTEN 3513 void helper_XVBF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3514 ppc_acc_t *at, uint32_t mask) 3515 { 3516 vsxger16(env, a, b, at, mask, false, false, false, extract_bf16); 3517 } 3518 3519 QEMU_FLATTEN 3520 void helper_XVBF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3521 ppc_acc_t *at, uint32_t mask) 3522 { 3523 vsxger16(env, a, b, at, mask, true, false, false, extract_bf16); 3524 } 3525 3526 QEMU_FLATTEN 3527 void helper_XVBF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3528 ppc_acc_t *at, uint32_t mask) 3529 { 3530 vsxger16(env, a, b, at, mask, true, false, true, extract_bf16); 3531 } 3532 3533 QEMU_FLATTEN 3534 void helper_XVBF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3535 ppc_acc_t *at, uint32_t mask) 3536 { 3537 vsxger16(env, a, b, at, mask, true, true, false, extract_bf16); 3538 } 3539 3540 QEMU_FLATTEN 3541 void helper_XVBF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3542 ppc_acc_t *at, uint32_t mask) 3543 { 3544 vsxger16(env, a, b, at, mask, true, true, true, extract_bf16); 3545 } 3546 3547 QEMU_FLATTEN 3548 void helper_XVF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3549 ppc_acc_t *at, uint32_t mask) 3550 { 3551 vsxger16(env, a, b, at, mask, false, false, false, extract_hf16); 3552 } 3553 3554 QEMU_FLATTEN 3555 void helper_XVF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3556 ppc_acc_t *at, uint32_t mask) 3557 { 3558 vsxger16(env, a, b, at, mask, true, false, false, extract_hf16); 3559 } 3560 3561 QEMU_FLATTEN 3562 void helper_XVF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3563 ppc_acc_t *at, uint32_t mask) 3564 { 3565 vsxger16(env, a, b, at, mask, true, false, true, extract_hf16); 3566 } 3567 3568 QEMU_FLATTEN 3569 void helper_XVF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3570 ppc_acc_t *at, uint32_t mask) 3571 { 3572 vsxger16(env, a, b, at, mask, true, true, false, extract_hf16); 3573 } 3574 3575 QEMU_FLATTEN 3576 void helper_XVF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3577 ppc_acc_t *at, uint32_t mask) 3578 { 3579 vsxger16(env, a, b, at, mask, true, true, true, extract_hf16); 3580 } 3581 3582 QEMU_FLATTEN 3583 void helper_XVF32GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3584 ppc_acc_t *at, uint32_t mask) 3585 { 3586 vsxger(env, a, b, at, mask, false, false, false, vsxger_mul32, 3587 vsxger_muladd32, vsxger_zero32); 3588 } 3589 3590 QEMU_FLATTEN 3591 void helper_XVF32GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3592 ppc_acc_t *at, uint32_t mask) 3593 { 3594 vsxger(env, a, b, at, mask, true, false, false, vsxger_mul32, 3595 vsxger_muladd32, vsxger_zero32); 3596 } 3597 3598 QEMU_FLATTEN 3599 void helper_XVF32GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3600 ppc_acc_t *at, uint32_t mask) 3601 { 3602 vsxger(env, a, b, at, mask, true, false, true, vsxger_mul32, 3603 vsxger_muladd32, vsxger_zero32); 3604 } 3605 3606 QEMU_FLATTEN 3607 void helper_XVF32GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3608 ppc_acc_t *at, uint32_t mask) 3609 { 3610 vsxger(env, a, b, at, mask, true, true, false, vsxger_mul32, 3611 vsxger_muladd32, vsxger_zero32); 3612 } 3613 3614 QEMU_FLATTEN 3615 void helper_XVF32GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3616 ppc_acc_t *at, uint32_t mask) 3617 { 3618 vsxger(env, a, b, at, mask, true, true, true, vsxger_mul32, 3619 vsxger_muladd32, vsxger_zero32); 3620 } 3621 3622 QEMU_FLATTEN 3623 void helper_XVF64GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3624 ppc_acc_t *at, uint32_t mask) 3625 { 3626 vsxger(env, a, b, at, mask, false, false, false, vsxger_mul64, 3627 vsxger_muladd64, vsxger_zero64); 3628 } 3629 3630 QEMU_FLATTEN 3631 void helper_XVF64GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3632 ppc_acc_t *at, uint32_t mask) 3633 { 3634 vsxger(env, a, b, at, mask, true, false, false, vsxger_mul64, 3635 vsxger_muladd64, vsxger_zero64); 3636 } 3637 3638 QEMU_FLATTEN 3639 void helper_XVF64GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3640 ppc_acc_t *at, uint32_t mask) 3641 { 3642 vsxger(env, a, b, at, mask, true, false, true, vsxger_mul64, 3643 vsxger_muladd64, vsxger_zero64); 3644 } 3645 3646 QEMU_FLATTEN 3647 void helper_XVF64GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3648 ppc_acc_t *at, uint32_t mask) 3649 { 3650 vsxger(env, a, b, at, mask, true, true, false, vsxger_mul64, 3651 vsxger_muladd64, vsxger_zero64); 3652 } 3653 3654 QEMU_FLATTEN 3655 void helper_XVF64GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b, 3656 ppc_acc_t *at, uint32_t mask) 3657 { 3658 vsxger(env, a, b, at, mask, true, true, true, vsxger_mul64, 3659 vsxger_muladd64, vsxger_zero64); 3660 } 3661