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