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