xref: /qemu/target/s390x/tcg/fpu_helper.c (revision bdcfcd445dd4f07e4df5345f1cdd0da5a5e6ba5f)
1e72ca652SBlue Swirl /*
2e72ca652SBlue Swirl  *  S/390 FPU helper routines
3e72ca652SBlue Swirl  *
4e72ca652SBlue Swirl  *  Copyright (c) 2009 Ulrich Hecht
5e72ca652SBlue Swirl  *  Copyright (c) 2009 Alexander Graf
6e72ca652SBlue Swirl  *
7e72ca652SBlue Swirl  * This library is free software; you can redistribute it and/or
8e72ca652SBlue Swirl  * modify it under the terms of the GNU Lesser General Public
9e72ca652SBlue Swirl  * License as published by the Free Software Foundation; either
1041c6a6ddSThomas Huth  * version 2.1 of the License, or (at your option) any later version.
11e72ca652SBlue Swirl  *
12e72ca652SBlue Swirl  * This library is distributed in the hope that it will be useful,
13e72ca652SBlue Swirl  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14e72ca652SBlue Swirl  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15e72ca652SBlue Swirl  * Lesser General Public License for more details.
16e72ca652SBlue Swirl  *
17e72ca652SBlue Swirl  * You should have received a copy of the GNU Lesser General Public
18e72ca652SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19e72ca652SBlue Swirl  */
20e72ca652SBlue Swirl 
219615495aSPeter Maydell #include "qemu/osdep.h"
22e72ca652SBlue Swirl #include "cpu.h"
234e58b838SDavid Hildenbrand #include "internal.h"
24bbf6ea3bSDavid Hildenbrand #include "tcg_s390x.h"
2563c91552SPaolo Bonzini #include "exec/exec-all.h"
26f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
272ef6175aSRichard Henderson #include "exec/helper-proto.h"
2824f91e81SAlex Bennée #include "fpu/softfloat.h"
29e72ca652SBlue Swirl 
30e72ca652SBlue Swirl /* #define DEBUG_HELPER */
31e72ca652SBlue Swirl #ifdef DEBUG_HELPER
32e72ca652SBlue Swirl #define HELPER_LOG(x...) qemu_log(x)
33e72ca652SBlue Swirl #else
34e72ca652SBlue Swirl #define HELPER_LOG(x...)
35e72ca652SBlue Swirl #endif
36e72ca652SBlue Swirl 
37587626f8SRichard Henderson #define RET128(F) (env->retxl = F.low, F.high)
38587626f8SRichard Henderson 
394b70fc54SDavid Hildenbrand uint8_t s390_softfloat_exc_to_ieee(unsigned int exc)
404b70fc54SDavid Hildenbrand {
414b70fc54SDavid Hildenbrand     uint8_t s390_exc = 0;
424b70fc54SDavid Hildenbrand 
434b70fc54SDavid Hildenbrand     s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0;
444b70fc54SDavid Hildenbrand     s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0;
454b70fc54SDavid Hildenbrand     s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0;
464b70fc54SDavid Hildenbrand     s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0;
474b70fc54SDavid Hildenbrand     s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0;
484b70fc54SDavid Hildenbrand 
494b70fc54SDavid Hildenbrand     return s390_exc;
504b70fc54SDavid Hildenbrand }
51587626f8SRichard Henderson 
52587626f8SRichard Henderson /* Should be called after any operation that may raise IEEE exceptions.  */
53cf97f9ffSDavid Hildenbrand static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr)
54587626f8SRichard Henderson {
55587626f8SRichard Henderson     unsigned s390_exc, qemu_exc;
56587626f8SRichard Henderson 
57587626f8SRichard Henderson     /* Get the exceptions raised by the current operation.  Reset the
58587626f8SRichard Henderson        fpu_status contents so that the next operation has a clean slate.  */
59587626f8SRichard Henderson     qemu_exc = env->fpu_status.float_exception_flags;
60587626f8SRichard Henderson     if (qemu_exc == 0) {
61587626f8SRichard Henderson         return;
62587626f8SRichard Henderson     }
63587626f8SRichard Henderson     env->fpu_status.float_exception_flags = 0;
644b70fc54SDavid Hildenbrand     s390_exc = s390_softfloat_exc_to_ieee(qemu_exc);
65587626f8SRichard Henderson 
66fcb9e9f2SDavid Hildenbrand     /*
676d6ad1d1SDavid Hildenbrand      * IEEE-Underflow exception recognition exists if a tininess condition
686d6ad1d1SDavid Hildenbrand      * (underflow) exists and
696d6ad1d1SDavid Hildenbrand      * - The mask bit in the FPC is zero and the result is inexact
706d6ad1d1SDavid Hildenbrand      * - The mask bit in the FPC is one
716d6ad1d1SDavid Hildenbrand      * So tininess conditions that are not inexact don't trigger any
726d6ad1d1SDavid Hildenbrand      * underflow action in case the mask bit is not one.
736d6ad1d1SDavid Hildenbrand      */
746d6ad1d1SDavid Hildenbrand     if (!(s390_exc & S390_IEEE_MASK_INEXACT) &&
756d6ad1d1SDavid Hildenbrand         !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) {
766d6ad1d1SDavid Hildenbrand         s390_exc &= ~S390_IEEE_MASK_UNDERFLOW;
776d6ad1d1SDavid Hildenbrand     }
786d6ad1d1SDavid Hildenbrand 
796d6ad1d1SDavid Hildenbrand     /*
80fcb9e9f2SDavid Hildenbrand      * FIXME:
81fcb9e9f2SDavid Hildenbrand      * 1. Right now, all inexact conditions are inidicated as
82fcb9e9f2SDavid Hildenbrand      *    "truncated" (0) and never as "incremented" (1) in the DXC.
83fcb9e9f2SDavid Hildenbrand      * 2. Only traps due to invalid/divbyzero are suppressing. Other traps
84fcb9e9f2SDavid Hildenbrand      *    are completing, meaning the target register has to be written!
85fcb9e9f2SDavid Hildenbrand      *    This, however will mean that we have to write the register before
86fcb9e9f2SDavid Hildenbrand      *    triggering the trap - impossible right now.
87fcb9e9f2SDavid Hildenbrand      */
88587626f8SRichard Henderson 
89fcb9e9f2SDavid Hildenbrand     /*
90fcb9e9f2SDavid Hildenbrand      * invalid/divbyzero cannot coexist with other conditions.
91fcb9e9f2SDavid Hildenbrand      * overflow/underflow however can coexist with inexact, we have to
92fcb9e9f2SDavid Hildenbrand      * handle it separatly.
93fcb9e9f2SDavid Hildenbrand      */
94fcb9e9f2SDavid Hildenbrand     if (s390_exc & ~S390_IEEE_MASK_INEXACT) {
95fcb9e9f2SDavid Hildenbrand         if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
96fcb9e9f2SDavid Hildenbrand             /* trap condition - inexact reported along */
97bbf6ea3bSDavid Hildenbrand             tcg_s390_data_exception(env, s390_exc, retaddr);
98587626f8SRichard Henderson         }
99fcb9e9f2SDavid Hildenbrand         /* nontrap condition - inexact handled differently */
100fcb9e9f2SDavid Hildenbrand         env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16;
101fcb9e9f2SDavid Hildenbrand     }
102fcb9e9f2SDavid Hildenbrand 
103fcb9e9f2SDavid Hildenbrand     /* inexact handling */
104cf97f9ffSDavid Hildenbrand     if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) {
105fcb9e9f2SDavid Hildenbrand         /* trap condition - overflow/underflow _not_ reported along */
106fcb9e9f2SDavid Hildenbrand         if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
107fcb9e9f2SDavid Hildenbrand             tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT,
108fcb9e9f2SDavid Hildenbrand                                     retaddr);
109fcb9e9f2SDavid Hildenbrand         }
110fcb9e9f2SDavid Hildenbrand         /* nontrap condition */
111fcb9e9f2SDavid Hildenbrand         env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16;
112fcb9e9f2SDavid Hildenbrand     }
113587626f8SRichard Henderson }
114587626f8SRichard Henderson 
115449c0d70SBlue Swirl static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
116e72ca652SBlue Swirl {
117a47dddd7SAndreas Färber     S390CPU *cpu = s390_env_get_cpu(env);
118a47dddd7SAndreas Färber 
119e72ca652SBlue Swirl     switch (float_compare) {
120e72ca652SBlue Swirl     case float_relation_equal:
121e72ca652SBlue Swirl         return 0;
122e72ca652SBlue Swirl     case float_relation_less:
123e72ca652SBlue Swirl         return 1;
124e72ca652SBlue Swirl     case float_relation_greater:
125e72ca652SBlue Swirl         return 2;
126e72ca652SBlue Swirl     case float_relation_unordered:
127e72ca652SBlue Swirl         return 3;
128e72ca652SBlue Swirl     default:
129a47dddd7SAndreas Färber         cpu_abort(CPU(cpu), "unknown return value for float compare\n");
130e72ca652SBlue Swirl     }
131e72ca652SBlue Swirl }
132e72ca652SBlue Swirl 
133e72ca652SBlue Swirl /* condition codes for unary FP ops */
134e72ca652SBlue Swirl uint32_t set_cc_nz_f32(float32 v)
135e72ca652SBlue Swirl {
136e72ca652SBlue Swirl     if (float32_is_any_nan(v)) {
137e72ca652SBlue Swirl         return 3;
138e72ca652SBlue Swirl     } else if (float32_is_zero(v)) {
139e72ca652SBlue Swirl         return 0;
140e72ca652SBlue Swirl     } else if (float32_is_neg(v)) {
141e72ca652SBlue Swirl         return 1;
142e72ca652SBlue Swirl     } else {
143e72ca652SBlue Swirl         return 2;
144e72ca652SBlue Swirl     }
145e72ca652SBlue Swirl }
146e72ca652SBlue Swirl 
147e72ca652SBlue Swirl uint32_t set_cc_nz_f64(float64 v)
148e72ca652SBlue Swirl {
149e72ca652SBlue Swirl     if (float64_is_any_nan(v)) {
150e72ca652SBlue Swirl         return 3;
151e72ca652SBlue Swirl     } else if (float64_is_zero(v)) {
152e72ca652SBlue Swirl         return 0;
153e72ca652SBlue Swirl     } else if (float64_is_neg(v)) {
154e72ca652SBlue Swirl         return 1;
155e72ca652SBlue Swirl     } else {
156e72ca652SBlue Swirl         return 2;
157e72ca652SBlue Swirl     }
158e72ca652SBlue Swirl }
159e72ca652SBlue Swirl 
160587626f8SRichard Henderson uint32_t set_cc_nz_f128(float128 v)
161e72ca652SBlue Swirl {
162e72ca652SBlue Swirl     if (float128_is_any_nan(v)) {
163e72ca652SBlue Swirl         return 3;
164e72ca652SBlue Swirl     } else if (float128_is_zero(v)) {
165e72ca652SBlue Swirl         return 0;
166e72ca652SBlue Swirl     } else if (float128_is_neg(v)) {
167e72ca652SBlue Swirl         return 1;
168e72ca652SBlue Swirl     } else {
169e72ca652SBlue Swirl         return 2;
170e72ca652SBlue Swirl     }
171e72ca652SBlue Swirl }
172e72ca652SBlue Swirl 
173dce0a58fSDavid Hildenbrand static inline uint8_t round_from_m34(uint32_t m34)
174dce0a58fSDavid Hildenbrand {
175dce0a58fSDavid Hildenbrand     return extract32(m34, 0, 4);
176dce0a58fSDavid Hildenbrand }
177dce0a58fSDavid Hildenbrand 
178dce0a58fSDavid Hildenbrand static inline bool xxc_from_m34(uint32_t m34)
179dce0a58fSDavid Hildenbrand {
180dce0a58fSDavid Hildenbrand     /* XxC is bit 1 of m4 */
181dce0a58fSDavid Hildenbrand     return extract32(m34, 4 + 3 - 1, 1);
182dce0a58fSDavid Hildenbrand }
183dce0a58fSDavid Hildenbrand 
184587626f8SRichard Henderson /* 32-bit FP addition */
185587626f8SRichard Henderson uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
186e72ca652SBlue Swirl {
187587626f8SRichard Henderson     float32 ret = float32_add(f1, f2, &env->fpu_status);
188cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
189587626f8SRichard Henderson     return ret;
190e72ca652SBlue Swirl }
191e72ca652SBlue Swirl 
192587626f8SRichard Henderson /* 64-bit FP addition */
193587626f8SRichard Henderson uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
194e72ca652SBlue Swirl {
195587626f8SRichard Henderson     float64 ret = float64_add(f1, f2, &env->fpu_status);
196cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
197587626f8SRichard Henderson     return ret;
198587626f8SRichard Henderson }
199e72ca652SBlue Swirl 
200587626f8SRichard Henderson /* 128-bit FP addition */
201587626f8SRichard Henderson uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
202587626f8SRichard Henderson                      uint64_t bh, uint64_t bl)
203587626f8SRichard Henderson {
204587626f8SRichard Henderson     float128 ret = float128_add(make_float128(ah, al),
205587626f8SRichard Henderson                                 make_float128(bh, bl),
206587626f8SRichard Henderson                                 &env->fpu_status);
207cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
208587626f8SRichard Henderson     return RET128(ret);
209e72ca652SBlue Swirl }
210e72ca652SBlue Swirl 
2111a800a2dSRichard Henderson /* 32-bit FP subtraction */
2121a800a2dSRichard Henderson uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
213e72ca652SBlue Swirl {
2141a800a2dSRichard Henderson     float32 ret = float32_sub(f1, f2, &env->fpu_status);
215cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
2161a800a2dSRichard Henderson     return ret;
217e72ca652SBlue Swirl }
218e72ca652SBlue Swirl 
2191a800a2dSRichard Henderson /* 64-bit FP subtraction */
2201a800a2dSRichard Henderson uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
221e72ca652SBlue Swirl {
2221a800a2dSRichard Henderson     float64 ret = float64_sub(f1, f2, &env->fpu_status);
223cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
2241a800a2dSRichard Henderson     return ret;
2251a800a2dSRichard Henderson }
226e72ca652SBlue Swirl 
2271a800a2dSRichard Henderson /* 128-bit FP subtraction */
2281a800a2dSRichard Henderson uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
2291a800a2dSRichard Henderson                      uint64_t bh, uint64_t bl)
2301a800a2dSRichard Henderson {
2311a800a2dSRichard Henderson     float128 ret = float128_sub(make_float128(ah, al),
2321a800a2dSRichard Henderson                                 make_float128(bh, bl),
2331a800a2dSRichard Henderson                                 &env->fpu_status);
234cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
2351a800a2dSRichard Henderson     return RET128(ret);
236e72ca652SBlue Swirl }
237e72ca652SBlue Swirl 
238f08a5c31SRichard Henderson /* 32-bit FP division */
239f08a5c31SRichard Henderson uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
240e72ca652SBlue Swirl {
241f08a5c31SRichard Henderson     float32 ret = float32_div(f1, f2, &env->fpu_status);
242cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
243f08a5c31SRichard Henderson     return ret;
244e72ca652SBlue Swirl }
245e72ca652SBlue Swirl 
246f08a5c31SRichard Henderson /* 64-bit FP division */
247f08a5c31SRichard Henderson uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
248e72ca652SBlue Swirl {
249f08a5c31SRichard Henderson     float64 ret = float64_div(f1, f2, &env->fpu_status);
250cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
251f08a5c31SRichard Henderson     return ret;
252f08a5c31SRichard Henderson }
253e72ca652SBlue Swirl 
254f08a5c31SRichard Henderson /* 128-bit FP division */
255f08a5c31SRichard Henderson uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
256f08a5c31SRichard Henderson                      uint64_t bh, uint64_t bl)
257f08a5c31SRichard Henderson {
258f08a5c31SRichard Henderson     float128 ret = float128_div(make_float128(ah, al),
259f08a5c31SRichard Henderson                                 make_float128(bh, bl),
260f08a5c31SRichard Henderson                                 &env->fpu_status);
261cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
262f08a5c31SRichard Henderson     return RET128(ret);
263e72ca652SBlue Swirl }
264e72ca652SBlue Swirl 
26583b00736SRichard Henderson /* 32-bit FP multiplication */
26683b00736SRichard Henderson uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
267e72ca652SBlue Swirl {
26883b00736SRichard Henderson     float32 ret = float32_mul(f1, f2, &env->fpu_status);
269cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
27083b00736SRichard Henderson     return ret;
271e72ca652SBlue Swirl }
272e72ca652SBlue Swirl 
27383b00736SRichard Henderson /* 64-bit FP multiplication */
27483b00736SRichard Henderson uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
275e72ca652SBlue Swirl {
27683b00736SRichard Henderson     float64 ret = float64_mul(f1, f2, &env->fpu_status);
277cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
27883b00736SRichard Henderson     return ret;
27983b00736SRichard Henderson }
280e72ca652SBlue Swirl 
28183b00736SRichard Henderson /* 64/32-bit FP multiplication */
28283b00736SRichard Henderson uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
28383b00736SRichard Henderson {
28483b00736SRichard Henderson     float64 ret = float32_to_float64(f2, &env->fpu_status);
28583b00736SRichard Henderson     ret = float64_mul(f1, ret, &env->fpu_status);
286cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
28783b00736SRichard Henderson     return ret;
28883b00736SRichard Henderson }
28983b00736SRichard Henderson 
29083b00736SRichard Henderson /* 128-bit FP multiplication */
29183b00736SRichard Henderson uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
29283b00736SRichard Henderson                      uint64_t bh, uint64_t bl)
29383b00736SRichard Henderson {
29483b00736SRichard Henderson     float128 ret = float128_mul(make_float128(ah, al),
29583b00736SRichard Henderson                                 make_float128(bh, bl),
29683b00736SRichard Henderson                                 &env->fpu_status);
297cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
29883b00736SRichard Henderson     return RET128(ret);
29983b00736SRichard Henderson }
30083b00736SRichard Henderson 
30183b00736SRichard Henderson /* 128/64-bit FP multiplication */
30283b00736SRichard Henderson uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al,
30383b00736SRichard Henderson                       uint64_t f2)
30483b00736SRichard Henderson {
30583b00736SRichard Henderson     float128 ret = float64_to_float128(f2, &env->fpu_status);
30683b00736SRichard Henderson     ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status);
307cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
30883b00736SRichard Henderson     return RET128(ret);
309e72ca652SBlue Swirl }
310e72ca652SBlue Swirl 
311e72ca652SBlue Swirl /* convert 32-bit float to 64-bit float */
312587626f8SRichard Henderson uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
313e72ca652SBlue Swirl {
314587626f8SRichard Henderson     float64 ret = float32_to_float64(f2, &env->fpu_status);
315cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
316d0cfecb5SRichard Henderson     return ret;
317e72ca652SBlue Swirl }
318e72ca652SBlue Swirl 
319e72ca652SBlue Swirl /* convert 128-bit float to 64-bit float */
320*bdcfcd44SDavid Hildenbrand uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
321*bdcfcd44SDavid Hildenbrand                       uint32_t m34)
322e72ca652SBlue Swirl {
323*bdcfcd44SDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
324587626f8SRichard Henderson     float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
325*bdcfcd44SDavid Hildenbrand 
326*bdcfcd44SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
327*bdcfcd44SDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
328d0cfecb5SRichard Henderson     return ret;
329e72ca652SBlue Swirl }
330e72ca652SBlue Swirl 
331e72ca652SBlue Swirl /* convert 64-bit float to 128-bit float */
332587626f8SRichard Henderson uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
333e72ca652SBlue Swirl {
334587626f8SRichard Henderson     float128 ret = float64_to_float128(f2, &env->fpu_status);
335cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
336d0cfecb5SRichard Henderson     return RET128(ret);
337587626f8SRichard Henderson }
338e72ca652SBlue Swirl 
339587626f8SRichard Henderson /* convert 32-bit float to 128-bit float */
340587626f8SRichard Henderson uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
341587626f8SRichard Henderson {
342587626f8SRichard Henderson     float128 ret = float32_to_float128(f2, &env->fpu_status);
343cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
344d0cfecb5SRichard Henderson     return RET128(ret);
345e72ca652SBlue Swirl }
346e72ca652SBlue Swirl 
347e72ca652SBlue Swirl /* convert 64-bit float to 32-bit float */
348*bdcfcd44SDavid Hildenbrand uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
349e72ca652SBlue Swirl {
350*bdcfcd44SDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
351587626f8SRichard Henderson     float32 ret = float64_to_float32(f2, &env->fpu_status);
352*bdcfcd44SDavid Hildenbrand 
353*bdcfcd44SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
354*bdcfcd44SDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
355d0cfecb5SRichard Henderson     return ret;
356e72ca652SBlue Swirl }
357e72ca652SBlue Swirl 
358e72ca652SBlue Swirl /* convert 128-bit float to 32-bit float */
359*bdcfcd44SDavid Hildenbrand uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al,
360*bdcfcd44SDavid Hildenbrand                       uint32_t m34)
361e72ca652SBlue Swirl {
362*bdcfcd44SDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
363587626f8SRichard Henderson     float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
364*bdcfcd44SDavid Hildenbrand 
365*bdcfcd44SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
366*bdcfcd44SDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
367d0cfecb5SRichard Henderson     return ret;
368e72ca652SBlue Swirl }
369e72ca652SBlue Swirl 
370587626f8SRichard Henderson /* 32-bit FP compare */
371587626f8SRichard Henderson uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
372e72ca652SBlue Swirl {
373587626f8SRichard Henderson     int cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
374cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
375587626f8SRichard Henderson     return float_comp_to_cc(env, cmp);
376e72ca652SBlue Swirl }
377e72ca652SBlue Swirl 
378587626f8SRichard Henderson /* 64-bit FP compare */
379587626f8SRichard Henderson uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
380e72ca652SBlue Swirl {
381587626f8SRichard Henderson     int cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
382cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
383587626f8SRichard Henderson     return float_comp_to_cc(env, cmp);
384e72ca652SBlue Swirl }
385e72ca652SBlue Swirl 
386587626f8SRichard Henderson /* 128-bit FP compare */
387587626f8SRichard Henderson uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
388587626f8SRichard Henderson                      uint64_t bh, uint64_t bl)
389e72ca652SBlue Swirl {
390587626f8SRichard Henderson     int cmp = float128_compare_quiet(make_float128(ah, al),
391587626f8SRichard Henderson                                      make_float128(bh, bl),
392587626f8SRichard Henderson                                      &env->fpu_status);
393cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
394587626f8SRichard Henderson     return float_comp_to_cc(env, cmp);
395e72ca652SBlue Swirl }
396e72ca652SBlue Swirl 
397c0ee7015SDavid Hildenbrand int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3)
398e72ca652SBlue Swirl {
39968c8bd93SRichard Henderson     int ret = env->fpu_status.float_rounding_mode;
400e72ca652SBlue Swirl     switch (m3) {
401e72ca652SBlue Swirl     case 0:
402e72ca652SBlue Swirl         /* current mode */
403e72ca652SBlue Swirl         break;
404e72ca652SBlue Swirl     case 1:
405e72ca652SBlue Swirl         /* biased round no nearest */
406e72ca652SBlue Swirl     case 4:
407e72ca652SBlue Swirl         /* round to nearest */
408e72ca652SBlue Swirl         set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
409e72ca652SBlue Swirl         break;
410e72ca652SBlue Swirl     case 5:
411e72ca652SBlue Swirl         /* round to zero */
412e72ca652SBlue Swirl         set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
413e72ca652SBlue Swirl         break;
414e72ca652SBlue Swirl     case 6:
415e72ca652SBlue Swirl         /* round to +inf */
416e72ca652SBlue Swirl         set_float_rounding_mode(float_round_up, &env->fpu_status);
417e72ca652SBlue Swirl         break;
418e72ca652SBlue Swirl     case 7:
419e72ca652SBlue Swirl         /* round to -inf */
420e72ca652SBlue Swirl         set_float_rounding_mode(float_round_down, &env->fpu_status);
421e72ca652SBlue Swirl         break;
422e72ca652SBlue Swirl     }
42368c8bd93SRichard Henderson     return ret;
424e72ca652SBlue Swirl }
425e72ca652SBlue Swirl 
426c0ee7015SDavid Hildenbrand void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode)
427c0ee7015SDavid Hildenbrand {
428c0ee7015SDavid Hildenbrand     set_float_rounding_mode(old_mode, &env->fpu_status);
429c0ee7015SDavid Hildenbrand }
430c0ee7015SDavid Hildenbrand 
431683bb9a8SRichard Henderson /* convert 64-bit int to 32-bit float */
432dce0a58fSDavid Hildenbrand uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34)
433683bb9a8SRichard Henderson {
434dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
435683bb9a8SRichard Henderson     float32 ret = int64_to_float32(v2, &env->fpu_status);
436c0ee7015SDavid Hildenbrand 
437c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
438dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
439683bb9a8SRichard Henderson     return ret;
440683bb9a8SRichard Henderson }
441683bb9a8SRichard Henderson 
442683bb9a8SRichard Henderson /* convert 64-bit int to 64-bit float */
443dce0a58fSDavid Hildenbrand uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
444683bb9a8SRichard Henderson {
445dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
446683bb9a8SRichard Henderson     float64 ret = int64_to_float64(v2, &env->fpu_status);
447c0ee7015SDavid Hildenbrand 
448c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
449dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
450683bb9a8SRichard Henderson     return ret;
451683bb9a8SRichard Henderson }
452683bb9a8SRichard Henderson 
453683bb9a8SRichard Henderson /* convert 64-bit int to 128-bit float */
454dce0a58fSDavid Hildenbrand uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
455683bb9a8SRichard Henderson {
456dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
457683bb9a8SRichard Henderson     float128 ret = int64_to_float128(v2, &env->fpu_status);
458c0ee7015SDavid Hildenbrand 
459c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
460dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
461683bb9a8SRichard Henderson     return RET128(ret);
462683bb9a8SRichard Henderson }
463683bb9a8SRichard Henderson 
4642112bf1bSRichard Henderson /* convert 64-bit uint to 32-bit float */
465dce0a58fSDavid Hildenbrand uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
4662112bf1bSRichard Henderson {
467dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
4682112bf1bSRichard Henderson     float32 ret = uint64_to_float32(v2, &env->fpu_status);
469c0ee7015SDavid Hildenbrand 
470c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
471dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
4722112bf1bSRichard Henderson     return ret;
4732112bf1bSRichard Henderson }
4742112bf1bSRichard Henderson 
4752112bf1bSRichard Henderson /* convert 64-bit uint to 64-bit float */
476dce0a58fSDavid Hildenbrand uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
4772112bf1bSRichard Henderson {
478dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
4792112bf1bSRichard Henderson     float64 ret = uint64_to_float64(v2, &env->fpu_status);
480c0ee7015SDavid Hildenbrand 
481c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
482dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
4832112bf1bSRichard Henderson     return ret;
4842112bf1bSRichard Henderson }
4852112bf1bSRichard Henderson 
4862112bf1bSRichard Henderson /* convert 64-bit uint to 128-bit float */
487dce0a58fSDavid Hildenbrand uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
4882112bf1bSRichard Henderson {
489dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
490d2d9feacSRichard Henderson     float128 ret = uint64_to_float128(v2, &env->fpu_status);
491c0ee7015SDavid Hildenbrand 
492c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
493dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
4942112bf1bSRichard Henderson     return RET128(ret);
4952112bf1bSRichard Henderson }
4962112bf1bSRichard Henderson 
497e72ca652SBlue Swirl /* convert 32-bit float to 64-bit int */
498dce0a58fSDavid Hildenbrand uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
499e72ca652SBlue Swirl {
500dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
50168c8bd93SRichard Henderson     int64_t ret = float32_to_int64(v2, &env->fpu_status);
502c0ee7015SDavid Hildenbrand 
503c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
504dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
50568c8bd93SRichard Henderson     return ret;
506e72ca652SBlue Swirl }
507e72ca652SBlue Swirl 
508e72ca652SBlue Swirl /* convert 64-bit float to 64-bit int */
509dce0a58fSDavid Hildenbrand uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
510e72ca652SBlue Swirl {
511dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
51268c8bd93SRichard Henderson     int64_t ret = float64_to_int64(v2, &env->fpu_status);
513c0ee7015SDavid Hildenbrand 
514c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
515dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
51668c8bd93SRichard Henderson     return ret;
517e72ca652SBlue Swirl }
518e72ca652SBlue Swirl 
519e72ca652SBlue Swirl /* convert 128-bit float to 64-bit int */
520dce0a58fSDavid Hildenbrand uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
521e72ca652SBlue Swirl {
522dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
52368c8bd93SRichard Henderson     float128 v2 = make_float128(h, l);
52468c8bd93SRichard Henderson     int64_t ret = float128_to_int64(v2, &env->fpu_status);
525c0ee7015SDavid Hildenbrand 
526c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
527dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
52868c8bd93SRichard Henderson     return ret;
529e72ca652SBlue Swirl }
530e72ca652SBlue Swirl 
531e72ca652SBlue Swirl /* convert 32-bit float to 32-bit int */
532dce0a58fSDavid Hildenbrand uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
533e72ca652SBlue Swirl {
534dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
53568c8bd93SRichard Henderson     int32_t ret = float32_to_int32(v2, &env->fpu_status);
536c0ee7015SDavid Hildenbrand 
537c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
538dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
53968c8bd93SRichard Henderson     return ret;
540e72ca652SBlue Swirl }
541e72ca652SBlue Swirl 
542e72ca652SBlue Swirl /* convert 64-bit float to 32-bit int */
543dce0a58fSDavid Hildenbrand uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
544e72ca652SBlue Swirl {
545dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
54668c8bd93SRichard Henderson     int32_t ret = float64_to_int32(v2, &env->fpu_status);
547c0ee7015SDavid Hildenbrand 
548c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
549dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
55068c8bd93SRichard Henderson     return ret;
551e72ca652SBlue Swirl }
552e72ca652SBlue Swirl 
553e72ca652SBlue Swirl /* convert 128-bit float to 32-bit int */
554dce0a58fSDavid Hildenbrand uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
555e72ca652SBlue Swirl {
556dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
55768c8bd93SRichard Henderson     float128 v2 = make_float128(h, l);
55868c8bd93SRichard Henderson     int32_t ret = float128_to_int32(v2, &env->fpu_status);
559c0ee7015SDavid Hildenbrand 
560c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
561dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
56268c8bd93SRichard Henderson     return ret;
563e72ca652SBlue Swirl }
564e72ca652SBlue Swirl 
5656ac1b45fSRichard Henderson /* convert 32-bit float to 64-bit uint */
566dce0a58fSDavid Hildenbrand uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
5676ac1b45fSRichard Henderson {
568dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
5696ac1b45fSRichard Henderson     uint64_t ret;
570c0ee7015SDavid Hildenbrand 
5716ac1b45fSRichard Henderson     v2 = float32_to_float64(v2, &env->fpu_status);
5726ac1b45fSRichard Henderson     ret = float64_to_uint64(v2, &env->fpu_status);
573c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
574dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
5756ac1b45fSRichard Henderson     return ret;
5766ac1b45fSRichard Henderson }
5776ac1b45fSRichard Henderson 
5786ac1b45fSRichard Henderson /* convert 64-bit float to 64-bit uint */
579dce0a58fSDavid Hildenbrand uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
5806ac1b45fSRichard Henderson {
581dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
5826ac1b45fSRichard Henderson     uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
583c0ee7015SDavid Hildenbrand 
584c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
585dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
5866ac1b45fSRichard Henderson     return ret;
5876ac1b45fSRichard Henderson }
5886ac1b45fSRichard Henderson 
5896ac1b45fSRichard Henderson /* convert 128-bit float to 64-bit uint */
590dce0a58fSDavid Hildenbrand uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
5916ac1b45fSRichard Henderson {
592dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
5933af471f9SDavid Hildenbrand     uint64_t ret = float128_to_uint64(make_float128(h, l), &env->fpu_status);
594c0ee7015SDavid Hildenbrand 
595c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
596dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
5976ac1b45fSRichard Henderson     return ret;
5986ac1b45fSRichard Henderson }
5996ac1b45fSRichard Henderson 
6006ac1b45fSRichard Henderson /* convert 32-bit float to 32-bit uint */
601dce0a58fSDavid Hildenbrand uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
6026ac1b45fSRichard Henderson {
603dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
6046ac1b45fSRichard Henderson     uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
605c0ee7015SDavid Hildenbrand 
606c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
607dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
6086ac1b45fSRichard Henderson     return ret;
6096ac1b45fSRichard Henderson }
6106ac1b45fSRichard Henderson 
6116ac1b45fSRichard Henderson /* convert 64-bit float to 32-bit uint */
612dce0a58fSDavid Hildenbrand uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
6136ac1b45fSRichard Henderson {
614dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
6156ac1b45fSRichard Henderson     uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
616c0ee7015SDavid Hildenbrand 
617c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
618dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
6196ac1b45fSRichard Henderson     return ret;
6206ac1b45fSRichard Henderson }
6216ac1b45fSRichard Henderson 
6226ac1b45fSRichard Henderson /* convert 128-bit float to 32-bit uint */
623dce0a58fSDavid Hildenbrand uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
6246ac1b45fSRichard Henderson {
625dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
6263af471f9SDavid Hildenbrand     uint32_t ret = float128_to_uint32(make_float128(h, l), &env->fpu_status);
627c0ee7015SDavid Hildenbrand 
628c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
629dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
6306ac1b45fSRichard Henderson     return ret;
6316ac1b45fSRichard Henderson }
6326ac1b45fSRichard Henderson 
633ed0bceceSAurelien Jarno /* round to integer 32-bit */
634dce0a58fSDavid Hildenbrand uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
635ed0bceceSAurelien Jarno {
636dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
637ed0bceceSAurelien Jarno     float32 ret = float32_round_to_int(f2, &env->fpu_status);
638c0ee7015SDavid Hildenbrand 
639c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
640dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
641ed0bceceSAurelien Jarno     return ret;
642ed0bceceSAurelien Jarno }
643ed0bceceSAurelien Jarno 
644ed0bceceSAurelien Jarno /* round to integer 64-bit */
645dce0a58fSDavid Hildenbrand uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
646ed0bceceSAurelien Jarno {
647dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
648ed0bceceSAurelien Jarno     float64 ret = float64_round_to_int(f2, &env->fpu_status);
649c0ee7015SDavid Hildenbrand 
650c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
651dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
652ed0bceceSAurelien Jarno     return ret;
653ed0bceceSAurelien Jarno }
654ed0bceceSAurelien Jarno 
655ed0bceceSAurelien Jarno /* round to integer 128-bit */
656dce0a58fSDavid Hildenbrand uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al,
657dce0a58fSDavid Hildenbrand                       uint32_t m34)
658ed0bceceSAurelien Jarno {
659dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
660ed0bceceSAurelien Jarno     float128 ret = float128_round_to_int(make_float128(ah, al),
661ed0bceceSAurelien Jarno                                          &env->fpu_status);
662cf97f9ffSDavid Hildenbrand 
663c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
664dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
665ed0bceceSAurelien Jarno     return RET128(ret);
666ed0bceceSAurelien Jarno }
667ed0bceceSAurelien Jarno 
6689c8be598SAurelien Jarno /* 32-bit FP compare and signal */
6699c8be598SAurelien Jarno uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
6709c8be598SAurelien Jarno {
6719c8be598SAurelien Jarno     int cmp = float32_compare(f1, f2, &env->fpu_status);
672cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
6739c8be598SAurelien Jarno     return float_comp_to_cc(env, cmp);
6749c8be598SAurelien Jarno }
6759c8be598SAurelien Jarno 
6769c8be598SAurelien Jarno /* 64-bit FP compare and signal */
6779c8be598SAurelien Jarno uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
6789c8be598SAurelien Jarno {
6799c8be598SAurelien Jarno     int cmp = float64_compare(f1, f2, &env->fpu_status);
680cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
6819c8be598SAurelien Jarno     return float_comp_to_cc(env, cmp);
6829c8be598SAurelien Jarno }
6839c8be598SAurelien Jarno 
6849c8be598SAurelien Jarno /* 128-bit FP compare and signal */
6859c8be598SAurelien Jarno uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
6869c8be598SAurelien Jarno                      uint64_t bh, uint64_t bl)
6879c8be598SAurelien Jarno {
6889c8be598SAurelien Jarno     int cmp = float128_compare(make_float128(ah, al),
6899c8be598SAurelien Jarno                                make_float128(bh, bl),
6909c8be598SAurelien Jarno                                &env->fpu_status);
691cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
6929c8be598SAurelien Jarno     return float_comp_to_cc(env, cmp);
6939c8be598SAurelien Jarno }
6949c8be598SAurelien Jarno 
695722bfec3SRichard Henderson /* 32-bit FP multiply and add */
696722bfec3SRichard Henderson uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
697722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
698e72ca652SBlue Swirl {
699722bfec3SRichard Henderson     float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
700cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
701722bfec3SRichard Henderson     return ret;
702722bfec3SRichard Henderson }
703e72ca652SBlue Swirl 
704722bfec3SRichard Henderson /* 64-bit FP multiply and add */
705722bfec3SRichard Henderson uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
706722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
707722bfec3SRichard Henderson {
708722bfec3SRichard Henderson     float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
709cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
710722bfec3SRichard Henderson     return ret;
711722bfec3SRichard Henderson }
712722bfec3SRichard Henderson 
713722bfec3SRichard Henderson /* 32-bit FP multiply and subtract */
714722bfec3SRichard Henderson uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
715722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
716722bfec3SRichard Henderson {
717722bfec3SRichard Henderson     float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
718e72ca652SBlue Swirl                                  &env->fpu_status);
719cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
720722bfec3SRichard Henderson     return ret;
721e72ca652SBlue Swirl }
722e72ca652SBlue Swirl 
723722bfec3SRichard Henderson /* 64-bit FP multiply and subtract */
724722bfec3SRichard Henderson uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
725722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
726e72ca652SBlue Swirl {
727722bfec3SRichard Henderson     float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
728e72ca652SBlue Swirl                                  &env->fpu_status);
729cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
730722bfec3SRichard Henderson     return ret;
731e72ca652SBlue Swirl }
732e72ca652SBlue Swirl 
733fc7cc951SDavid Hildenbrand /* The rightmost bit has the number 11. */
734fc7cc951SDavid Hildenbrand static inline uint16_t dcmask(int bit, bool neg)
735fc7cc951SDavid Hildenbrand {
736fc7cc951SDavid Hildenbrand     return 1 << (11 - bit - neg);
737fc7cc951SDavid Hildenbrand }
738fc7cc951SDavid Hildenbrand 
739fc7cc951SDavid Hildenbrand #define DEF_FLOAT_DCMASK(_TYPE) \
740fc7cc951SDavid Hildenbrand static uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1)       \
741fc7cc951SDavid Hildenbrand {                                                                  \
742fc7cc951SDavid Hildenbrand     const bool neg = _TYPE##_is_neg(f1);                           \
743fc7cc951SDavid Hildenbrand                                                                    \
744fc7cc951SDavid Hildenbrand     /* Sorted by most common cases - only one class is possible */ \
745fc7cc951SDavid Hildenbrand     if (_TYPE##_is_normal(f1)) {                                   \
746fc7cc951SDavid Hildenbrand         return dcmask(2, neg);                                     \
747fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_zero(f1)) {                              \
748fc7cc951SDavid Hildenbrand         return dcmask(0, neg);                                     \
749fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_denormal(f1)) {                          \
750fc7cc951SDavid Hildenbrand         return dcmask(4, neg);                                     \
751fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_infinity(f1)) {                          \
752fc7cc951SDavid Hildenbrand         return dcmask(6, neg);                                     \
753fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) {       \
754fc7cc951SDavid Hildenbrand         return dcmask(8, neg);                                     \
755fc7cc951SDavid Hildenbrand     }                                                              \
756fc7cc951SDavid Hildenbrand     /* signaling nan, as last remaining case */                    \
757fc7cc951SDavid Hildenbrand     return dcmask(10, neg);                                        \
758fc7cc951SDavid Hildenbrand }
759fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float32)
760fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float64)
761fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float128)
762fc7cc951SDavid Hildenbrand 
763e72ca652SBlue Swirl /* test data class 32-bit */
764af39bc8cSAleksandar Markovic uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2)
765e72ca652SBlue Swirl {
766fc7cc951SDavid Hildenbrand     return (m2 & float32_dcmask(env, f1)) != 0;
767e72ca652SBlue Swirl }
768e72ca652SBlue Swirl 
769e72ca652SBlue Swirl /* test data class 64-bit */
770af39bc8cSAleksandar Markovic uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2)
771e72ca652SBlue Swirl {
772fc7cc951SDavid Hildenbrand     return (m2 & float64_dcmask(env, v1)) != 0;
773e72ca652SBlue Swirl }
774e72ca652SBlue Swirl 
775e72ca652SBlue Swirl /* test data class 128-bit */
776fc7cc951SDavid Hildenbrand uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2)
777e72ca652SBlue Swirl {
778fc7cc951SDavid Hildenbrand     return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0;
779e72ca652SBlue Swirl }
780e72ca652SBlue Swirl 
78116d7b2a4SRichard Henderson /* square root 32-bit */
78216d7b2a4SRichard Henderson uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
783e72ca652SBlue Swirl {
78416d7b2a4SRichard Henderson     float32 ret = float32_sqrt(f2, &env->fpu_status);
785cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
78616d7b2a4SRichard Henderson     return ret;
78716d7b2a4SRichard Henderson }
78816d7b2a4SRichard Henderson 
78916d7b2a4SRichard Henderson /* square root 64-bit */
79016d7b2a4SRichard Henderson uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
79116d7b2a4SRichard Henderson {
79216d7b2a4SRichard Henderson     float64 ret = float64_sqrt(f2, &env->fpu_status);
793cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
79416d7b2a4SRichard Henderson     return ret;
79516d7b2a4SRichard Henderson }
79616d7b2a4SRichard Henderson 
79716d7b2a4SRichard Henderson /* square root 128-bit */
79816d7b2a4SRichard Henderson uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
79916d7b2a4SRichard Henderson {
80016d7b2a4SRichard Henderson     float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
801cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
80216d7b2a4SRichard Henderson     return RET128(ret);
803e72ca652SBlue Swirl }
8048379bfdbSRichard Henderson 
8052aea83c6SDavid Hildenbrand static const int fpc_to_rnd[8] = {
8068379bfdbSRichard Henderson     float_round_nearest_even,
8078379bfdbSRichard Henderson     float_round_to_zero,
8088379bfdbSRichard Henderson     float_round_up,
8092aea83c6SDavid Hildenbrand     float_round_down,
8102aea83c6SDavid Hildenbrand     -1,
8112aea83c6SDavid Hildenbrand     -1,
8122aea83c6SDavid Hildenbrand     -1,
8132aea83c6SDavid Hildenbrand     float_round_to_odd,
8148379bfdbSRichard Henderson };
8158379bfdbSRichard Henderson 
816411edc22SRichard Henderson /* set fpc */
817411edc22SRichard Henderson void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
818411edc22SRichard Henderson {
8192aea83c6SDavid Hildenbrand     if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
8202aea83c6SDavid Hildenbrand         (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
8212aea83c6SDavid Hildenbrand         s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
8222aea83c6SDavid Hildenbrand     }
8232aea83c6SDavid Hildenbrand 
8248379bfdbSRichard Henderson     /* Install everything in the main FPC.  */
8258379bfdbSRichard Henderson     env->fpc = fpc;
8268379bfdbSRichard Henderson 
8278379bfdbSRichard Henderson     /* Install the rounding mode in the shadow fpu_status.  */
8282aea83c6SDavid Hildenbrand     set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
829411edc22SRichard Henderson }
830411edc22SRichard Henderson 
831411edc22SRichard Henderson /* set fpc and signal */
832f66a0ecfSDavid Hildenbrand void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
833411edc22SRichard Henderson {
834411edc22SRichard Henderson     uint32_t signalling = env->fpc;
835411edc22SRichard Henderson     uint32_t s390_exc;
836411edc22SRichard Henderson 
8372aea83c6SDavid Hildenbrand     if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
8382aea83c6SDavid Hildenbrand         (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
8392aea83c6SDavid Hildenbrand         s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
8402aea83c6SDavid Hildenbrand     }
8412aea83c6SDavid Hildenbrand 
842f66a0ecfSDavid Hildenbrand     /*
843f66a0ecfSDavid Hildenbrand      * FPC is set to the FPC operand with a bitwise OR of the signalling
844f66a0ecfSDavid Hildenbrand      * flags.
845f66a0ecfSDavid Hildenbrand      */
846f66a0ecfSDavid Hildenbrand     env->fpc = fpc | (signalling & 0x00ff0000);
8472aea83c6SDavid Hildenbrand     set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
848411edc22SRichard Henderson 
849f66a0ecfSDavid Hildenbrand     /*
850f66a0ecfSDavid Hildenbrand      * If any signaling flag is enabled in the new FPC mask, a
851f66a0ecfSDavid Hildenbrand      * simulated-iee-exception exception occurs.
852f66a0ecfSDavid Hildenbrand      */
853f66a0ecfSDavid Hildenbrand     s390_exc = (signalling >> 16) & (fpc >> 24);
854411edc22SRichard Henderson     if (s390_exc) {
8558772bbe4SDavid Hildenbrand         if (s390_exc & S390_IEEE_MASK_INVALID) {
8568772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_INVALID;
8578772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) {
8588772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_DIVBYZERO;
8598772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) {
8608772bbe4SDavid Hildenbrand             s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT);
8618772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) {
8628772bbe4SDavid Hildenbrand             s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT);
8638772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_INEXACT) {
8648772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_INEXACT;
8658772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_QUANTUM) {
8668772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_QUANTUM;
8678772bbe4SDavid Hildenbrand         }
868bbf6ea3bSDavid Hildenbrand         tcg_s390_data_exception(env, s390_exc | 3, GETPC());
869411edc22SRichard Henderson     }
8708379bfdbSRichard Henderson }
871b9c737f5SDavid Hildenbrand 
872b9c737f5SDavid Hildenbrand /* set bfp rounding mode */
873b9c737f5SDavid Hildenbrand void HELPER(srnm)(CPUS390XState *env, uint64_t rnd)
874b9c737f5SDavid Hildenbrand {
875b9c737f5SDavid Hildenbrand     if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) {
876b9c737f5SDavid Hildenbrand         s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
877b9c737f5SDavid Hildenbrand     }
878b9c737f5SDavid Hildenbrand 
879b9c737f5SDavid Hildenbrand     env->fpc = deposit32(env->fpc, 0, 3, rnd);
880b9c737f5SDavid Hildenbrand     set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status);
881b9c737f5SDavid Hildenbrand }
882