qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

fpu_helper.c (31174B)


      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 
     39 uint8_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.  */
     53 static 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 separately.
     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 
    115 int 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 */
    132 uint32_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 
    145 uint32_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 
    158 uint32_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 */
    172 static 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 
    181 static 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 
    190 static 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 
    199 static inline uint8_t round_from_m34(uint32_t m34)
    200 {
    201     return extract32(m34, 0, 4);
    202 }
    203 
    204 static 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 */
    211 uint64_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 */
    219 uint64_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 */
    227 uint64_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 */
    238 uint64_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 */
    246 uint64_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 */
    254 uint64_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 */
    265 uint64_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 */
    273 uint64_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 */
    281 uint64_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 */
    292 uint64_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 */
    300 uint64_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 */
    308 uint64_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 */
    317 uint64_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 */
    328 uint64_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 */
    338 uint64_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 */
    346 uint64_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 */
    358 uint64_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 */
    366 uint64_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 */
    374 uint64_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 */
    385 uint64_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 */
    397 uint32_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 */
    405 uint32_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 */
    413 uint32_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 
    423 int 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 
    461 void 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 */
    467 uint64_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 */
    478 uint64_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 */
    489 uint64_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 */
    500 uint64_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 */
    511 uint64_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 */
    522 uint64_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 */
    533 uint64_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 */
    549 uint64_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 */
    565 uint64_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 */
    582 uint64_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 */
    598 uint64_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 */
    614 uint64_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 */
    631 uint64_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 */
    647 uint64_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 */
    663 uint64_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 */
    680 uint64_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 */
    696 uint64_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 */
    712 uint64_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 */
    729 uint64_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 */
    740 uint64_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 */
    751 uint64_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 */
    764 uint32_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 */
    772 uint32_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 */
    780 uint32_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 */
    791 uint64_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 */
    800 uint64_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 */
    809 uint64_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 */
    819 uint64_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. */
    829 static inline uint16_t dcmask(int bit, bool neg)
    830 {
    831     return 1 << (11 - bit - neg);
    832 }
    833 
    834 #define DEF_FLOAT_DCMASK(_TYPE) \
    835 uint16_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 }
    854 DEF_FLOAT_DCMASK(float32)
    855 DEF_FLOAT_DCMASK(float64)
    856 DEF_FLOAT_DCMASK(float128)
    857 
    858 /* test data class 32-bit */
    859 uint32_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 */
    865 uint32_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 */
    871 uint32_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 */
    877 uint64_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 */
    885 uint64_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 */
    893 uint64_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 
    900 static 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 */
    912 void 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 */
    927 void 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 */
    968 void 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 }