cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

fpu_helper.c (31173B)


      1/*
      2 *  S/390 FPU helper routines
      3 *
      4 *  Copyright (c) 2009 Ulrich Hecht
      5 *  Copyright (c) 2009 Alexander Graf
      6 *
      7 * This library is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU Lesser General Public
      9 * License as published by the Free Software Foundation; either
     10 * version 2.1 of the License, or (at your option) any later version.
     11 *
     12 * This library is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15 * Lesser General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU Lesser General Public
     18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "cpu.h"
     23#include "s390x-internal.h"
     24#include "tcg_s390x.h"
     25#include "exec/exec-all.h"
     26#include "exec/cpu_ldst.h"
     27#include "exec/helper-proto.h"
     28#include "fpu/softfloat.h"
     29
     30/* #define DEBUG_HELPER */
     31#ifdef DEBUG_HELPER
     32#define HELPER_LOG(x...) qemu_log(x)
     33#else
     34#define HELPER_LOG(x...)
     35#endif
     36
     37#define RET128(F) (env->retxl = F.low, F.high)
     38
     39uint8_t s390_softfloat_exc_to_ieee(unsigned int exc)
     40{
     41    uint8_t s390_exc = 0;
     42
     43    s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0;
     44    s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0;
     45    s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0;
     46    s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0;
     47    s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0;
     48
     49    return s390_exc;
     50}
     51
     52/* Should be called after any operation that may raise IEEE exceptions.  */
     53static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr)
     54{
     55    unsigned s390_exc, qemu_exc;
     56
     57    /* Get the exceptions raised by the current operation.  Reset the
     58       fpu_status contents so that the next operation has a clean slate.  */
     59    qemu_exc = env->fpu_status.float_exception_flags;
     60    if (qemu_exc == 0) {
     61        return;
     62    }
     63    env->fpu_status.float_exception_flags = 0;
     64    s390_exc = s390_softfloat_exc_to_ieee(qemu_exc);
     65
     66    /*
     67     * IEEE-Underflow exception recognition exists if a tininess condition
     68     * (underflow) exists and
     69     * - The mask bit in the FPC is zero and the result is inexact
     70     * - The mask bit in the FPC is one
     71     * So tininess conditions that are not inexact don't trigger any
     72     * underflow action in case the mask bit is not one.
     73     */
     74    if (!(s390_exc & S390_IEEE_MASK_INEXACT) &&
     75        !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) {
     76        s390_exc &= ~S390_IEEE_MASK_UNDERFLOW;
     77    }
     78
     79    /*
     80     * FIXME:
     81     * 1. Right now, all inexact conditions are inidicated as
     82     *    "truncated" (0) and never as "incremented" (1) in the DXC.
     83     * 2. Only traps due to invalid/divbyzero are suppressing. Other traps
     84     *    are completing, meaning the target register has to be written!
     85     *    This, however will mean that we have to write the register before
     86     *    triggering the trap - impossible right now.
     87     */
     88
     89    /*
     90     * invalid/divbyzero cannot coexist with other conditions.
     91     * overflow/underflow however can coexist with inexact, we have to
     92     * handle it separatly.
     93     */
     94    if (s390_exc & ~S390_IEEE_MASK_INEXACT) {
     95        if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
     96            /* trap condition - inexact reported along */
     97            tcg_s390_data_exception(env, s390_exc, retaddr);
     98        }
     99        /* nontrap condition - inexact handled differently */
    100        env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16;
    101    }
    102
    103    /* inexact handling */
    104    if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) {
    105        /* trap condition - overflow/underflow _not_ reported along */
    106        if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
    107            tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT,
    108                                    retaddr);
    109        }
    110        /* nontrap condition */
    111        env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16;
    112    }
    113}
    114
    115int float_comp_to_cc(CPUS390XState *env, FloatRelation float_compare)
    116{
    117    switch (float_compare) {
    118    case float_relation_equal:
    119        return 0;
    120    case float_relation_less:
    121        return 1;
    122    case float_relation_greater:
    123        return 2;
    124    case float_relation_unordered:
    125        return 3;
    126    default:
    127        cpu_abort(env_cpu(env), "unknown return value for float compare\n");
    128    }
    129}
    130
    131/* condition codes for unary FP ops */
    132uint32_t set_cc_nz_f32(float32 v)
    133{
    134    if (float32_is_any_nan(v)) {
    135        return 3;
    136    } else if (float32_is_zero(v)) {
    137        return 0;
    138    } else if (float32_is_neg(v)) {
    139        return 1;
    140    } else {
    141        return 2;
    142    }
    143}
    144
    145uint32_t set_cc_nz_f64(float64 v)
    146{
    147    if (float64_is_any_nan(v)) {
    148        return 3;
    149    } else if (float64_is_zero(v)) {
    150        return 0;
    151    } else if (float64_is_neg(v)) {
    152        return 1;
    153    } else {
    154        return 2;
    155    }
    156}
    157
    158uint32_t set_cc_nz_f128(float128 v)
    159{
    160    if (float128_is_any_nan(v)) {
    161        return 3;
    162    } else if (float128_is_zero(v)) {
    163        return 0;
    164    } else if (float128_is_neg(v)) {
    165        return 1;
    166    } else {
    167        return 2;
    168    }
    169}
    170
    171/* condition codes for FP to integer conversion ops */
    172static uint32_t set_cc_conv_f32(float32 v, float_status *stat)
    173{
    174    if (stat->float_exception_flags & float_flag_invalid) {
    175        return 3;
    176    } else {
    177        return set_cc_nz_f32(v);
    178    }
    179}
    180
    181static uint32_t set_cc_conv_f64(float64 v, float_status *stat)
    182{
    183    if (stat->float_exception_flags & float_flag_invalid) {
    184        return 3;
    185    } else {
    186        return set_cc_nz_f64(v);
    187    }
    188}
    189
    190static uint32_t set_cc_conv_f128(float128 v, float_status *stat)
    191{
    192    if (stat->float_exception_flags & float_flag_invalid) {
    193        return 3;
    194    } else {
    195        return set_cc_nz_f128(v);
    196    }
    197}
    198
    199static inline uint8_t round_from_m34(uint32_t m34)
    200{
    201    return extract32(m34, 0, 4);
    202}
    203
    204static inline bool xxc_from_m34(uint32_t m34)
    205{
    206    /* XxC is bit 1 of m4 */
    207    return extract32(m34, 4 + 3 - 1, 1);
    208}
    209
    210/* 32-bit FP addition */
    211uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    212{
    213    float32 ret = float32_add(f1, f2, &env->fpu_status);
    214    handle_exceptions(env, false, GETPC());
    215    return ret;
    216}
    217
    218/* 64-bit FP addition */
    219uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    220{
    221    float64 ret = float64_add(f1, f2, &env->fpu_status);
    222    handle_exceptions(env, false, GETPC());
    223    return ret;
    224}
    225
    226/* 128-bit FP addition */
    227uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    228                     uint64_t bh, uint64_t bl)
    229{
    230    float128 ret = float128_add(make_float128(ah, al),
    231                                make_float128(bh, bl),
    232                                &env->fpu_status);
    233    handle_exceptions(env, false, GETPC());
    234    return RET128(ret);
    235}
    236
    237/* 32-bit FP subtraction */
    238uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    239{
    240    float32 ret = float32_sub(f1, f2, &env->fpu_status);
    241    handle_exceptions(env, false, GETPC());
    242    return ret;
    243}
    244
    245/* 64-bit FP subtraction */
    246uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    247{
    248    float64 ret = float64_sub(f1, f2, &env->fpu_status);
    249    handle_exceptions(env, false, GETPC());
    250    return ret;
    251}
    252
    253/* 128-bit FP subtraction */
    254uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    255                     uint64_t bh, uint64_t bl)
    256{
    257    float128 ret = float128_sub(make_float128(ah, al),
    258                                make_float128(bh, bl),
    259                                &env->fpu_status);
    260    handle_exceptions(env, false, GETPC());
    261    return RET128(ret);
    262}
    263
    264/* 32-bit FP division */
    265uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    266{
    267    float32 ret = float32_div(f1, f2, &env->fpu_status);
    268    handle_exceptions(env, false, GETPC());
    269    return ret;
    270}
    271
    272/* 64-bit FP division */
    273uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    274{
    275    float64 ret = float64_div(f1, f2, &env->fpu_status);
    276    handle_exceptions(env, false, GETPC());
    277    return ret;
    278}
    279
    280/* 128-bit FP division */
    281uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    282                     uint64_t bh, uint64_t bl)
    283{
    284    float128 ret = float128_div(make_float128(ah, al),
    285                                make_float128(bh, bl),
    286                                &env->fpu_status);
    287    handle_exceptions(env, false, GETPC());
    288    return RET128(ret);
    289}
    290
    291/* 32-bit FP multiplication */
    292uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    293{
    294    float32 ret = float32_mul(f1, f2, &env->fpu_status);
    295    handle_exceptions(env, false, GETPC());
    296    return ret;
    297}
    298
    299/* 64-bit FP multiplication */
    300uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    301{
    302    float64 ret = float64_mul(f1, f2, &env->fpu_status);
    303    handle_exceptions(env, false, GETPC());
    304    return ret;
    305}
    306
    307/* 64/32-bit FP multiplication */
    308uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    309{
    310    float64 ret = float32_to_float64(f2, &env->fpu_status);
    311    ret = float64_mul(f1, ret, &env->fpu_status);
    312    handle_exceptions(env, false, GETPC());
    313    return ret;
    314}
    315
    316/* 128-bit FP multiplication */
    317uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    318                     uint64_t bh, uint64_t bl)
    319{
    320    float128 ret = float128_mul(make_float128(ah, al),
    321                                make_float128(bh, bl),
    322                                &env->fpu_status);
    323    handle_exceptions(env, false, GETPC());
    324    return RET128(ret);
    325}
    326
    327/* 128/64-bit FP multiplication */
    328uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    329                      uint64_t f2)
    330{
    331    float128 ret = float64_to_float128(f2, &env->fpu_status);
    332    ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status);
    333    handle_exceptions(env, false, GETPC());
    334    return RET128(ret);
    335}
    336
    337/* convert 32-bit float to 64-bit float */
    338uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
    339{
    340    float64 ret = float32_to_float64(f2, &env->fpu_status);
    341    handle_exceptions(env, false, GETPC());
    342    return ret;
    343}
    344
    345/* convert 128-bit float to 64-bit float */
    346uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    347                      uint32_t m34)
    348{
    349    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    350    float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
    351
    352    s390_restore_bfp_rounding_mode(env, old_mode);
    353    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    354    return ret;
    355}
    356
    357/* convert 64-bit float to 128-bit float */
    358uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
    359{
    360    float128 ret = float64_to_float128(f2, &env->fpu_status);
    361    handle_exceptions(env, false, GETPC());
    362    return RET128(ret);
    363}
    364
    365/* convert 32-bit float to 128-bit float */
    366uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
    367{
    368    float128 ret = float32_to_float128(f2, &env->fpu_status);
    369    handle_exceptions(env, false, GETPC());
    370    return RET128(ret);
    371}
    372
    373/* convert 64-bit float to 32-bit float */
    374uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
    375{
    376    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    377    float32 ret = float64_to_float32(f2, &env->fpu_status);
    378
    379    s390_restore_bfp_rounding_mode(env, old_mode);
    380    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    381    return ret;
    382}
    383
    384/* convert 128-bit float to 32-bit float */
    385uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    386                      uint32_t m34)
    387{
    388    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    389    float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
    390
    391    s390_restore_bfp_rounding_mode(env, old_mode);
    392    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    393    return ret;
    394}
    395
    396/* 32-bit FP compare */
    397uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    398{
    399    FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
    400    handle_exceptions(env, false, GETPC());
    401    return float_comp_to_cc(env, cmp);
    402}
    403
    404/* 64-bit FP compare */
    405uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    406{
    407    FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
    408    handle_exceptions(env, false, GETPC());
    409    return float_comp_to_cc(env, cmp);
    410}
    411
    412/* 128-bit FP compare */
    413uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    414                     uint64_t bh, uint64_t bl)
    415{
    416    FloatRelation cmp = float128_compare_quiet(make_float128(ah, al),
    417                                               make_float128(bh, bl),
    418                                               &env->fpu_status);
    419    handle_exceptions(env, false, GETPC());
    420    return float_comp_to_cc(env, cmp);
    421}
    422
    423int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3)
    424{
    425    int ret = env->fpu_status.float_rounding_mode;
    426
    427    switch (m3) {
    428    case 0:
    429        /* current mode */
    430        break;
    431    case 1:
    432        /* round to nearest with ties away from 0 */
    433        set_float_rounding_mode(float_round_ties_away, &env->fpu_status);
    434        break;
    435    case 3:
    436        /* round to prepare for shorter precision */
    437        set_float_rounding_mode(float_round_to_odd, &env->fpu_status);
    438        break;
    439    case 4:
    440        /* round to nearest with ties to even */
    441        set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
    442        break;
    443    case 5:
    444        /* round to zero */
    445        set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
    446        break;
    447    case 6:
    448        /* round to +inf */
    449        set_float_rounding_mode(float_round_up, &env->fpu_status);
    450        break;
    451    case 7:
    452        /* round to -inf */
    453        set_float_rounding_mode(float_round_down, &env->fpu_status);
    454        break;
    455    default:
    456        g_assert_not_reached();
    457    }
    458    return ret;
    459}
    460
    461void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode)
    462{
    463    set_float_rounding_mode(old_mode, &env->fpu_status);
    464}
    465
    466/* convert 64-bit int to 32-bit float */
    467uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34)
    468{
    469    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    470    float32 ret = int64_to_float32(v2, &env->fpu_status);
    471
    472    s390_restore_bfp_rounding_mode(env, old_mode);
    473    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    474    return ret;
    475}
    476
    477/* convert 64-bit int to 64-bit float */
    478uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
    479{
    480    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    481    float64 ret = int64_to_float64(v2, &env->fpu_status);
    482
    483    s390_restore_bfp_rounding_mode(env, old_mode);
    484    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    485    return ret;
    486}
    487
    488/* convert 64-bit int to 128-bit float */
    489uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
    490{
    491    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    492    float128 ret = int64_to_float128(v2, &env->fpu_status);
    493
    494    s390_restore_bfp_rounding_mode(env, old_mode);
    495    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    496    return RET128(ret);
    497}
    498
    499/* convert 64-bit uint to 32-bit float */
    500uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    501{
    502    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    503    float32 ret = uint64_to_float32(v2, &env->fpu_status);
    504
    505    s390_restore_bfp_rounding_mode(env, old_mode);
    506    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    507    return ret;
    508}
    509
    510/* convert 64-bit uint to 64-bit float */
    511uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    512{
    513    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    514    float64 ret = uint64_to_float64(v2, &env->fpu_status);
    515
    516    s390_restore_bfp_rounding_mode(env, old_mode);
    517    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    518    return ret;
    519}
    520
    521/* convert 64-bit uint to 128-bit float */
    522uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    523{
    524    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    525    float128 ret = uint64_to_float128(v2, &env->fpu_status);
    526
    527    s390_restore_bfp_rounding_mode(env, old_mode);
    528    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    529    return RET128(ret);
    530}
    531
    532/* convert 32-bit float to 64-bit int */
    533uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    534{
    535    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    536    int64_t ret = float32_to_int64(v2, &env->fpu_status);
    537    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
    538
    539    s390_restore_bfp_rounding_mode(env, old_mode);
    540    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    541    env->cc_op = cc;
    542    if (float32_is_any_nan(v2)) {
    543        return INT64_MIN;
    544    }
    545    return ret;
    546}
    547
    548/* convert 64-bit float to 64-bit int */
    549uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    550{
    551    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    552    int64_t ret = float64_to_int64(v2, &env->fpu_status);
    553    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
    554
    555    s390_restore_bfp_rounding_mode(env, old_mode);
    556    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    557    env->cc_op = cc;
    558    if (float64_is_any_nan(v2)) {
    559        return INT64_MIN;
    560    }
    561    return ret;
    562}
    563
    564/* convert 128-bit float to 64-bit int */
    565uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
    566{
    567    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    568    float128 v2 = make_float128(h, l);
    569    int64_t ret = float128_to_int64(v2, &env->fpu_status);
    570    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
    571
    572    s390_restore_bfp_rounding_mode(env, old_mode);
    573    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    574    env->cc_op = cc;
    575    if (float128_is_any_nan(v2)) {
    576        return INT64_MIN;
    577    }
    578    return ret;
    579}
    580
    581/* convert 32-bit float to 32-bit int */
    582uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    583{
    584    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    585    int32_t ret = float32_to_int32(v2, &env->fpu_status);
    586    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
    587
    588    s390_restore_bfp_rounding_mode(env, old_mode);
    589    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    590    env->cc_op = cc;
    591    if (float32_is_any_nan(v2)) {
    592        return INT32_MIN;
    593    }
    594    return ret;
    595}
    596
    597/* convert 64-bit float to 32-bit int */
    598uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    599{
    600    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    601    int32_t ret = float64_to_int32(v2, &env->fpu_status);
    602    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
    603
    604    s390_restore_bfp_rounding_mode(env, old_mode);
    605    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    606    env->cc_op = cc;
    607    if (float64_is_any_nan(v2)) {
    608        return INT32_MIN;
    609    }
    610    return ret;
    611}
    612
    613/* convert 128-bit float to 32-bit int */
    614uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
    615{
    616    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    617    float128 v2 = make_float128(h, l);
    618    int32_t ret = float128_to_int32(v2, &env->fpu_status);
    619    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
    620
    621    s390_restore_bfp_rounding_mode(env, old_mode);
    622    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    623    env->cc_op = cc;
    624    if (float128_is_any_nan(v2)) {
    625        return INT32_MIN;
    626    }
    627    return ret;
    628}
    629
    630/* convert 32-bit float to 64-bit uint */
    631uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    632{
    633    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    634    uint64_t ret = float32_to_uint64(v2, &env->fpu_status);
    635    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
    636
    637    s390_restore_bfp_rounding_mode(env, old_mode);
    638    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    639    env->cc_op = cc;
    640    if (float32_is_any_nan(v2)) {
    641        return 0;
    642    }
    643    return ret;
    644}
    645
    646/* convert 64-bit float to 64-bit uint */
    647uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    648{
    649    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    650    uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
    651    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
    652
    653    s390_restore_bfp_rounding_mode(env, old_mode);
    654    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    655    env->cc_op = cc;
    656    if (float64_is_any_nan(v2)) {
    657        return 0;
    658    }
    659    return ret;
    660}
    661
    662/* convert 128-bit float to 64-bit uint */
    663uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
    664{
    665    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    666    float128 v2 = make_float128(h, l);
    667    uint64_t ret = float128_to_uint64(v2, &env->fpu_status);
    668    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
    669
    670    s390_restore_bfp_rounding_mode(env, old_mode);
    671    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    672    env->cc_op = cc;
    673    if (float128_is_any_nan(v2)) {
    674        return 0;
    675    }
    676    return ret;
    677}
    678
    679/* convert 32-bit float to 32-bit uint */
    680uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    681{
    682    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    683    uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
    684    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
    685
    686    s390_restore_bfp_rounding_mode(env, old_mode);
    687    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    688    env->cc_op = cc;
    689    if (float32_is_any_nan(v2)) {
    690        return 0;
    691    }
    692    return ret;
    693}
    694
    695/* convert 64-bit float to 32-bit uint */
    696uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
    697{
    698    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    699    uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
    700    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
    701
    702    s390_restore_bfp_rounding_mode(env, old_mode);
    703    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    704    env->cc_op = cc;
    705    if (float64_is_any_nan(v2)) {
    706        return 0;
    707    }
    708    return ret;
    709}
    710
    711/* convert 128-bit float to 32-bit uint */
    712uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
    713{
    714    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    715    float128 v2 = make_float128(h, l);
    716    uint32_t ret = float128_to_uint32(v2, &env->fpu_status);
    717    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
    718
    719    s390_restore_bfp_rounding_mode(env, old_mode);
    720    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    721    env->cc_op = cc;
    722    if (float128_is_any_nan(v2)) {
    723        return 0;
    724    }
    725    return ret;
    726}
    727
    728/* round to integer 32-bit */
    729uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
    730{
    731    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    732    float32 ret = float32_round_to_int(f2, &env->fpu_status);
    733
    734    s390_restore_bfp_rounding_mode(env, old_mode);
    735    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    736    return ret;
    737}
    738
    739/* round to integer 64-bit */
    740uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
    741{
    742    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    743    float64 ret = float64_round_to_int(f2, &env->fpu_status);
    744
    745    s390_restore_bfp_rounding_mode(env, old_mode);
    746    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    747    return ret;
    748}
    749
    750/* round to integer 128-bit */
    751uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    752                      uint32_t m34)
    753{
    754    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
    755    float128 ret = float128_round_to_int(make_float128(ah, al),
    756                                         &env->fpu_status);
    757
    758    s390_restore_bfp_rounding_mode(env, old_mode);
    759    handle_exceptions(env, xxc_from_m34(m34), GETPC());
    760    return RET128(ret);
    761}
    762
    763/* 32-bit FP compare and signal */
    764uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    765{
    766    FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status);
    767    handle_exceptions(env, false, GETPC());
    768    return float_comp_to_cc(env, cmp);
    769}
    770
    771/* 64-bit FP compare and signal */
    772uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
    773{
    774    FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status);
    775    handle_exceptions(env, false, GETPC());
    776    return float_comp_to_cc(env, cmp);
    777}
    778
    779/* 128-bit FP compare and signal */
    780uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
    781                     uint64_t bh, uint64_t bl)
    782{
    783    FloatRelation cmp = float128_compare(make_float128(ah, al),
    784                                         make_float128(bh, bl),
    785                                         &env->fpu_status);
    786    handle_exceptions(env, false, GETPC());
    787    return float_comp_to_cc(env, cmp);
    788}
    789
    790/* 32-bit FP multiply and add */
    791uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
    792                      uint64_t f2, uint64_t f3)
    793{
    794    float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
    795    handle_exceptions(env, false, GETPC());
    796    return ret;
    797}
    798
    799/* 64-bit FP multiply and add */
    800uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
    801                      uint64_t f2, uint64_t f3)
    802{
    803    float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
    804    handle_exceptions(env, false, GETPC());
    805    return ret;
    806}
    807
    808/* 32-bit FP multiply and subtract */
    809uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
    810                      uint64_t f2, uint64_t f3)
    811{
    812    float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
    813                                 &env->fpu_status);
    814    handle_exceptions(env, false, GETPC());
    815    return ret;
    816}
    817
    818/* 64-bit FP multiply and subtract */
    819uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
    820                      uint64_t f2, uint64_t f3)
    821{
    822    float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
    823                                 &env->fpu_status);
    824    handle_exceptions(env, false, GETPC());
    825    return ret;
    826}
    827
    828/* The rightmost bit has the number 11. */
    829static inline uint16_t dcmask(int bit, bool neg)
    830{
    831    return 1 << (11 - bit - neg);
    832}
    833
    834#define DEF_FLOAT_DCMASK(_TYPE) \
    835uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1)              \
    836{                                                                  \
    837    const bool neg = _TYPE##_is_neg(f1);                           \
    838                                                                   \
    839    /* Sorted by most common cases - only one class is possible */ \
    840    if (_TYPE##_is_normal(f1)) {                                   \
    841        return dcmask(2, neg);                                     \
    842    } else if (_TYPE##_is_zero(f1)) {                              \
    843        return dcmask(0, neg);                                     \
    844    } else if (_TYPE##_is_denormal(f1)) {                          \
    845        return dcmask(4, neg);                                     \
    846    } else if (_TYPE##_is_infinity(f1)) {                          \
    847        return dcmask(6, neg);                                     \
    848    } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) {       \
    849        return dcmask(8, neg);                                     \
    850    }                                                              \
    851    /* signaling nan, as last remaining case */                    \
    852    return dcmask(10, neg);                                        \
    853}
    854DEF_FLOAT_DCMASK(float32)
    855DEF_FLOAT_DCMASK(float64)
    856DEF_FLOAT_DCMASK(float128)
    857
    858/* test data class 32-bit */
    859uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2)
    860{
    861    return (m2 & float32_dcmask(env, f1)) != 0;
    862}
    863
    864/* test data class 64-bit */
    865uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2)
    866{
    867    return (m2 & float64_dcmask(env, v1)) != 0;
    868}
    869
    870/* test data class 128-bit */
    871uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2)
    872{
    873    return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0;
    874}
    875
    876/* square root 32-bit */
    877uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
    878{
    879    float32 ret = float32_sqrt(f2, &env->fpu_status);
    880    handle_exceptions(env, false, GETPC());
    881    return ret;
    882}
    883
    884/* square root 64-bit */
    885uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
    886{
    887    float64 ret = float64_sqrt(f2, &env->fpu_status);
    888    handle_exceptions(env, false, GETPC());
    889    return ret;
    890}
    891
    892/* square root 128-bit */
    893uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
    894{
    895    float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
    896    handle_exceptions(env, false, GETPC());
    897    return RET128(ret);
    898}
    899
    900static const int fpc_to_rnd[8] = {
    901    float_round_nearest_even,
    902    float_round_to_zero,
    903    float_round_up,
    904    float_round_down,
    905    -1,
    906    -1,
    907    -1,
    908    float_round_to_odd,
    909};
    910
    911/* set fpc */
    912void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
    913{
    914    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
    915        (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
    916        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
    917    }
    918
    919    /* Install everything in the main FPC.  */
    920    env->fpc = fpc;
    921
    922    /* Install the rounding mode in the shadow fpu_status.  */
    923    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
    924}
    925
    926/* set fpc and signal */
    927void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
    928{
    929    uint32_t signalling = env->fpc;
    930    uint32_t s390_exc;
    931
    932    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
    933        (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
    934        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
    935    }
    936
    937    /*
    938     * FPC is set to the FPC operand with a bitwise OR of the signalling
    939     * flags.
    940     */
    941    env->fpc = fpc | (signalling & 0x00ff0000);
    942    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
    943
    944    /*
    945     * If any signaling flag is enabled in the new FPC mask, a
    946     * simulated-iee-exception exception occurs.
    947     */
    948    s390_exc = (signalling >> 16) & (fpc >> 24);
    949    if (s390_exc) {
    950        if (s390_exc & S390_IEEE_MASK_INVALID) {
    951            s390_exc = S390_IEEE_MASK_INVALID;
    952        } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) {
    953            s390_exc = S390_IEEE_MASK_DIVBYZERO;
    954        } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) {
    955            s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT);
    956        } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) {
    957            s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT);
    958        } else if (s390_exc & S390_IEEE_MASK_INEXACT) {
    959            s390_exc = S390_IEEE_MASK_INEXACT;
    960        } else if (s390_exc & S390_IEEE_MASK_QUANTUM) {
    961            s390_exc = S390_IEEE_MASK_QUANTUM;
    962        }
    963        tcg_s390_data_exception(env, s390_exc | 3, GETPC());
    964    }
    965}
    966
    967/* set bfp rounding mode */
    968void HELPER(srnm)(CPUS390XState *env, uint64_t rnd)
    969{
    970    if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) {
    971        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
    972    }
    973
    974    env->fpc = deposit32(env->fpc, 0, 3, rnd);
    975    set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status);
    976}