xref: /qemu/target/s390x/tcg/fpu_helper.c (revision dce0a58fd6427e4c9d1399ced70a04276db71a5f)
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 
173*dce0a58fSDavid Hildenbrand static inline uint8_t round_from_m34(uint32_t m34)
174*dce0a58fSDavid Hildenbrand {
175*dce0a58fSDavid Hildenbrand     return extract32(m34, 0, 4);
176*dce0a58fSDavid Hildenbrand }
177*dce0a58fSDavid Hildenbrand 
178*dce0a58fSDavid Hildenbrand static inline bool xxc_from_m34(uint32_t m34)
179*dce0a58fSDavid Hildenbrand {
180*dce0a58fSDavid Hildenbrand     /* XxC is bit 1 of m4 */
181*dce0a58fSDavid Hildenbrand     return extract32(m34, 4 + 3 - 1, 1);
182*dce0a58fSDavid Hildenbrand }
183*dce0a58fSDavid 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 */
320587626f8SRichard Henderson uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
321e72ca652SBlue Swirl {
322587626f8SRichard Henderson     float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
323cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
324d0cfecb5SRichard Henderson     return ret;
325e72ca652SBlue Swirl }
326e72ca652SBlue Swirl 
327e72ca652SBlue Swirl /* convert 64-bit float to 128-bit float */
328587626f8SRichard Henderson uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
329e72ca652SBlue Swirl {
330587626f8SRichard Henderson     float128 ret = float64_to_float128(f2, &env->fpu_status);
331cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
332d0cfecb5SRichard Henderson     return RET128(ret);
333587626f8SRichard Henderson }
334e72ca652SBlue Swirl 
335587626f8SRichard Henderson /* convert 32-bit float to 128-bit float */
336587626f8SRichard Henderson uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
337587626f8SRichard Henderson {
338587626f8SRichard Henderson     float128 ret = float32_to_float128(f2, &env->fpu_status);
339cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
340d0cfecb5SRichard Henderson     return RET128(ret);
341e72ca652SBlue Swirl }
342e72ca652SBlue Swirl 
343e72ca652SBlue Swirl /* convert 64-bit float to 32-bit float */
344587626f8SRichard Henderson uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
345e72ca652SBlue Swirl {
346587626f8SRichard Henderson     float32 ret = float64_to_float32(f2, &env->fpu_status);
347cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
348d0cfecb5SRichard Henderson     return ret;
349e72ca652SBlue Swirl }
350e72ca652SBlue Swirl 
351e72ca652SBlue Swirl /* convert 128-bit float to 32-bit float */
352587626f8SRichard Henderson uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
353e72ca652SBlue Swirl {
354587626f8SRichard Henderson     float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
355cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
356d0cfecb5SRichard Henderson     return ret;
357e72ca652SBlue Swirl }
358e72ca652SBlue Swirl 
359587626f8SRichard Henderson /* 32-bit FP compare */
360587626f8SRichard Henderson uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
361e72ca652SBlue Swirl {
362587626f8SRichard Henderson     int cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
363cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
364587626f8SRichard Henderson     return float_comp_to_cc(env, cmp);
365e72ca652SBlue Swirl }
366e72ca652SBlue Swirl 
367587626f8SRichard Henderson /* 64-bit FP compare */
368587626f8SRichard Henderson uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
369e72ca652SBlue Swirl {
370587626f8SRichard Henderson     int cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
371cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
372587626f8SRichard Henderson     return float_comp_to_cc(env, cmp);
373e72ca652SBlue Swirl }
374e72ca652SBlue Swirl 
375587626f8SRichard Henderson /* 128-bit FP compare */
376587626f8SRichard Henderson uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
377587626f8SRichard Henderson                      uint64_t bh, uint64_t bl)
378e72ca652SBlue Swirl {
379587626f8SRichard Henderson     int cmp = float128_compare_quiet(make_float128(ah, al),
380587626f8SRichard Henderson                                      make_float128(bh, bl),
381587626f8SRichard Henderson                                      &env->fpu_status);
382cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
383587626f8SRichard Henderson     return float_comp_to_cc(env, cmp);
384e72ca652SBlue Swirl }
385e72ca652SBlue Swirl 
386c0ee7015SDavid Hildenbrand int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3)
387e72ca652SBlue Swirl {
38868c8bd93SRichard Henderson     int ret = env->fpu_status.float_rounding_mode;
389e72ca652SBlue Swirl     switch (m3) {
390e72ca652SBlue Swirl     case 0:
391e72ca652SBlue Swirl         /* current mode */
392e72ca652SBlue Swirl         break;
393e72ca652SBlue Swirl     case 1:
394e72ca652SBlue Swirl         /* biased round no nearest */
395e72ca652SBlue Swirl     case 4:
396e72ca652SBlue Swirl         /* round to nearest */
397e72ca652SBlue Swirl         set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
398e72ca652SBlue Swirl         break;
399e72ca652SBlue Swirl     case 5:
400e72ca652SBlue Swirl         /* round to zero */
401e72ca652SBlue Swirl         set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
402e72ca652SBlue Swirl         break;
403e72ca652SBlue Swirl     case 6:
404e72ca652SBlue Swirl         /* round to +inf */
405e72ca652SBlue Swirl         set_float_rounding_mode(float_round_up, &env->fpu_status);
406e72ca652SBlue Swirl         break;
407e72ca652SBlue Swirl     case 7:
408e72ca652SBlue Swirl         /* round to -inf */
409e72ca652SBlue Swirl         set_float_rounding_mode(float_round_down, &env->fpu_status);
410e72ca652SBlue Swirl         break;
411e72ca652SBlue Swirl     }
41268c8bd93SRichard Henderson     return ret;
413e72ca652SBlue Swirl }
414e72ca652SBlue Swirl 
415c0ee7015SDavid Hildenbrand void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode)
416c0ee7015SDavid Hildenbrand {
417c0ee7015SDavid Hildenbrand     set_float_rounding_mode(old_mode, &env->fpu_status);
418c0ee7015SDavid Hildenbrand }
419c0ee7015SDavid Hildenbrand 
420683bb9a8SRichard Henderson /* convert 64-bit int to 32-bit float */
421*dce0a58fSDavid Hildenbrand uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34)
422683bb9a8SRichard Henderson {
423*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
424683bb9a8SRichard Henderson     float32 ret = int64_to_float32(v2, &env->fpu_status);
425c0ee7015SDavid Hildenbrand 
426c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
427*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
428683bb9a8SRichard Henderson     return ret;
429683bb9a8SRichard Henderson }
430683bb9a8SRichard Henderson 
431683bb9a8SRichard Henderson /* convert 64-bit int to 64-bit float */
432*dce0a58fSDavid Hildenbrand uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
433683bb9a8SRichard Henderson {
434*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
435683bb9a8SRichard Henderson     float64 ret = int64_to_float64(v2, &env->fpu_status);
436c0ee7015SDavid Hildenbrand 
437c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
438*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
439683bb9a8SRichard Henderson     return ret;
440683bb9a8SRichard Henderson }
441683bb9a8SRichard Henderson 
442683bb9a8SRichard Henderson /* convert 64-bit int to 128-bit float */
443*dce0a58fSDavid Hildenbrand uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
444683bb9a8SRichard Henderson {
445*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
446683bb9a8SRichard Henderson     float128 ret = int64_to_float128(v2, &env->fpu_status);
447c0ee7015SDavid Hildenbrand 
448c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
449*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
450683bb9a8SRichard Henderson     return RET128(ret);
451683bb9a8SRichard Henderson }
452683bb9a8SRichard Henderson 
4532112bf1bSRichard Henderson /* convert 64-bit uint to 32-bit float */
454*dce0a58fSDavid Hildenbrand uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
4552112bf1bSRichard Henderson {
456*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
4572112bf1bSRichard Henderson     float32 ret = uint64_to_float32(v2, &env->fpu_status);
458c0ee7015SDavid Hildenbrand 
459c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
460*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
4612112bf1bSRichard Henderson     return ret;
4622112bf1bSRichard Henderson }
4632112bf1bSRichard Henderson 
4642112bf1bSRichard Henderson /* convert 64-bit uint to 64-bit float */
465*dce0a58fSDavid Hildenbrand uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
4662112bf1bSRichard Henderson {
467*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
4682112bf1bSRichard Henderson     float64 ret = uint64_to_float64(v2, &env->fpu_status);
469c0ee7015SDavid Hildenbrand 
470c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
471*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
4722112bf1bSRichard Henderson     return ret;
4732112bf1bSRichard Henderson }
4742112bf1bSRichard Henderson 
4752112bf1bSRichard Henderson /* convert 64-bit uint to 128-bit float */
476*dce0a58fSDavid Hildenbrand uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
4772112bf1bSRichard Henderson {
478*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
479d2d9feacSRichard Henderson     float128 ret = uint64_to_float128(v2, &env->fpu_status);
480c0ee7015SDavid Hildenbrand 
481c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
482*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
4832112bf1bSRichard Henderson     return RET128(ret);
4842112bf1bSRichard Henderson }
4852112bf1bSRichard Henderson 
486e72ca652SBlue Swirl /* convert 32-bit float to 64-bit int */
487*dce0a58fSDavid Hildenbrand uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
488e72ca652SBlue Swirl {
489*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
49068c8bd93SRichard Henderson     int64_t ret = float32_to_int64(v2, &env->fpu_status);
491c0ee7015SDavid Hildenbrand 
492c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
493*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
49468c8bd93SRichard Henderson     return ret;
495e72ca652SBlue Swirl }
496e72ca652SBlue Swirl 
497e72ca652SBlue Swirl /* convert 64-bit float to 64-bit int */
498*dce0a58fSDavid Hildenbrand uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
499e72ca652SBlue Swirl {
500*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
50168c8bd93SRichard Henderson     int64_t ret = float64_to_int64(v2, &env->fpu_status);
502c0ee7015SDavid Hildenbrand 
503c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
504*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
50568c8bd93SRichard Henderson     return ret;
506e72ca652SBlue Swirl }
507e72ca652SBlue Swirl 
508e72ca652SBlue Swirl /* convert 128-bit float to 64-bit int */
509*dce0a58fSDavid Hildenbrand uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
510e72ca652SBlue Swirl {
511*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
51268c8bd93SRichard Henderson     float128 v2 = make_float128(h, l);
51368c8bd93SRichard Henderson     int64_t ret = float128_to_int64(v2, &env->fpu_status);
514c0ee7015SDavid Hildenbrand 
515c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
516*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
51768c8bd93SRichard Henderson     return ret;
518e72ca652SBlue Swirl }
519e72ca652SBlue Swirl 
520e72ca652SBlue Swirl /* convert 32-bit float to 32-bit int */
521*dce0a58fSDavid Hildenbrand uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
522e72ca652SBlue Swirl {
523*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
52468c8bd93SRichard Henderson     int32_t ret = float32_to_int32(v2, &env->fpu_status);
525c0ee7015SDavid Hildenbrand 
526c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
527*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
52868c8bd93SRichard Henderson     return ret;
529e72ca652SBlue Swirl }
530e72ca652SBlue Swirl 
531e72ca652SBlue Swirl /* convert 64-bit float to 32-bit int */
532*dce0a58fSDavid Hildenbrand uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
533e72ca652SBlue Swirl {
534*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
53568c8bd93SRichard Henderson     int32_t ret = float64_to_int32(v2, &env->fpu_status);
536c0ee7015SDavid Hildenbrand 
537c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
538*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
53968c8bd93SRichard Henderson     return ret;
540e72ca652SBlue Swirl }
541e72ca652SBlue Swirl 
542e72ca652SBlue Swirl /* convert 128-bit float to 32-bit int */
543*dce0a58fSDavid Hildenbrand uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
544e72ca652SBlue Swirl {
545*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
54668c8bd93SRichard Henderson     float128 v2 = make_float128(h, l);
54768c8bd93SRichard Henderson     int32_t ret = float128_to_int32(v2, &env->fpu_status);
548c0ee7015SDavid Hildenbrand 
549c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
550*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
55168c8bd93SRichard Henderson     return ret;
552e72ca652SBlue Swirl }
553e72ca652SBlue Swirl 
5546ac1b45fSRichard Henderson /* convert 32-bit float to 64-bit uint */
555*dce0a58fSDavid Hildenbrand uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
5566ac1b45fSRichard Henderson {
557*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
5586ac1b45fSRichard Henderson     uint64_t ret;
559c0ee7015SDavid Hildenbrand 
5606ac1b45fSRichard Henderson     v2 = float32_to_float64(v2, &env->fpu_status);
5616ac1b45fSRichard Henderson     ret = float64_to_uint64(v2, &env->fpu_status);
562c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
563*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
5646ac1b45fSRichard Henderson     return ret;
5656ac1b45fSRichard Henderson }
5666ac1b45fSRichard Henderson 
5676ac1b45fSRichard Henderson /* convert 64-bit float to 64-bit uint */
568*dce0a58fSDavid Hildenbrand uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
5696ac1b45fSRichard Henderson {
570*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
5716ac1b45fSRichard Henderson     uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
572c0ee7015SDavid Hildenbrand 
573c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
574*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
5756ac1b45fSRichard Henderson     return ret;
5766ac1b45fSRichard Henderson }
5776ac1b45fSRichard Henderson 
5786ac1b45fSRichard Henderson /* convert 128-bit float to 64-bit uint */
579*dce0a58fSDavid Hildenbrand uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
5806ac1b45fSRichard Henderson {
581*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
5823af471f9SDavid Hildenbrand     uint64_t ret = float128_to_uint64(make_float128(h, l), &env->fpu_status);
583c0ee7015SDavid Hildenbrand 
584c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
585*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
5866ac1b45fSRichard Henderson     return ret;
5876ac1b45fSRichard Henderson }
5886ac1b45fSRichard Henderson 
5896ac1b45fSRichard Henderson /* convert 32-bit float to 32-bit uint */
590*dce0a58fSDavid Hildenbrand uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
5916ac1b45fSRichard Henderson {
592*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
5936ac1b45fSRichard Henderson     uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
594c0ee7015SDavid Hildenbrand 
595c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
596*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
5976ac1b45fSRichard Henderson     return ret;
5986ac1b45fSRichard Henderson }
5996ac1b45fSRichard Henderson 
6006ac1b45fSRichard Henderson /* convert 64-bit float to 32-bit uint */
601*dce0a58fSDavid Hildenbrand uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
6026ac1b45fSRichard Henderson {
603*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
6046ac1b45fSRichard Henderson     uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
605c0ee7015SDavid Hildenbrand 
606c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
607*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
6086ac1b45fSRichard Henderson     return ret;
6096ac1b45fSRichard Henderson }
6106ac1b45fSRichard Henderson 
6116ac1b45fSRichard Henderson /* convert 128-bit float to 32-bit uint */
612*dce0a58fSDavid Hildenbrand uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
6136ac1b45fSRichard Henderson {
614*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
6153af471f9SDavid Hildenbrand     uint32_t ret = float128_to_uint32(make_float128(h, l), &env->fpu_status);
616c0ee7015SDavid Hildenbrand 
617c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
618*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
6196ac1b45fSRichard Henderson     return ret;
6206ac1b45fSRichard Henderson }
6216ac1b45fSRichard Henderson 
622ed0bceceSAurelien Jarno /* round to integer 32-bit */
623*dce0a58fSDavid Hildenbrand uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
624ed0bceceSAurelien Jarno {
625*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
626ed0bceceSAurelien Jarno     float32 ret = float32_round_to_int(f2, &env->fpu_status);
627c0ee7015SDavid Hildenbrand 
628c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
629*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
630ed0bceceSAurelien Jarno     return ret;
631ed0bceceSAurelien Jarno }
632ed0bceceSAurelien Jarno 
633ed0bceceSAurelien Jarno /* round to integer 64-bit */
634*dce0a58fSDavid Hildenbrand uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
635ed0bceceSAurelien Jarno {
636*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
637ed0bceceSAurelien Jarno     float64 ret = float64_round_to_int(f2, &env->fpu_status);
638c0ee7015SDavid Hildenbrand 
639c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
640*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
641ed0bceceSAurelien Jarno     return ret;
642ed0bceceSAurelien Jarno }
643ed0bceceSAurelien Jarno 
644ed0bceceSAurelien Jarno /* round to integer 128-bit */
645*dce0a58fSDavid Hildenbrand uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al,
646*dce0a58fSDavid Hildenbrand                       uint32_t m34)
647ed0bceceSAurelien Jarno {
648*dce0a58fSDavid Hildenbrand     int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
649ed0bceceSAurelien Jarno     float128 ret = float128_round_to_int(make_float128(ah, al),
650ed0bceceSAurelien Jarno                                          &env->fpu_status);
651cf97f9ffSDavid Hildenbrand 
652c0ee7015SDavid Hildenbrand     s390_restore_bfp_rounding_mode(env, old_mode);
653*dce0a58fSDavid Hildenbrand     handle_exceptions(env, xxc_from_m34(m34), GETPC());
654ed0bceceSAurelien Jarno     return RET128(ret);
655ed0bceceSAurelien Jarno }
656ed0bceceSAurelien Jarno 
6579c8be598SAurelien Jarno /* 32-bit FP compare and signal */
6589c8be598SAurelien Jarno uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
6599c8be598SAurelien Jarno {
6609c8be598SAurelien Jarno     int cmp = float32_compare(f1, f2, &env->fpu_status);
661cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
6629c8be598SAurelien Jarno     return float_comp_to_cc(env, cmp);
6639c8be598SAurelien Jarno }
6649c8be598SAurelien Jarno 
6659c8be598SAurelien Jarno /* 64-bit FP compare and signal */
6669c8be598SAurelien Jarno uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
6679c8be598SAurelien Jarno {
6689c8be598SAurelien Jarno     int cmp = float64_compare(f1, f2, &env->fpu_status);
669cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
6709c8be598SAurelien Jarno     return float_comp_to_cc(env, cmp);
6719c8be598SAurelien Jarno }
6729c8be598SAurelien Jarno 
6739c8be598SAurelien Jarno /* 128-bit FP compare and signal */
6749c8be598SAurelien Jarno uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
6759c8be598SAurelien Jarno                      uint64_t bh, uint64_t bl)
6769c8be598SAurelien Jarno {
6779c8be598SAurelien Jarno     int cmp = float128_compare(make_float128(ah, al),
6789c8be598SAurelien Jarno                                make_float128(bh, bl),
6799c8be598SAurelien Jarno                                &env->fpu_status);
680cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
6819c8be598SAurelien Jarno     return float_comp_to_cc(env, cmp);
6829c8be598SAurelien Jarno }
6839c8be598SAurelien Jarno 
684722bfec3SRichard Henderson /* 32-bit FP multiply and add */
685722bfec3SRichard Henderson uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
686722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
687e72ca652SBlue Swirl {
688722bfec3SRichard Henderson     float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
689cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
690722bfec3SRichard Henderson     return ret;
691722bfec3SRichard Henderson }
692e72ca652SBlue Swirl 
693722bfec3SRichard Henderson /* 64-bit FP multiply and add */
694722bfec3SRichard Henderson uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
695722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
696722bfec3SRichard Henderson {
697722bfec3SRichard Henderson     float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
698cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
699722bfec3SRichard Henderson     return ret;
700722bfec3SRichard Henderson }
701722bfec3SRichard Henderson 
702722bfec3SRichard Henderson /* 32-bit FP multiply and subtract */
703722bfec3SRichard Henderson uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
704722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
705722bfec3SRichard Henderson {
706722bfec3SRichard Henderson     float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
707e72ca652SBlue Swirl                                  &env->fpu_status);
708cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
709722bfec3SRichard Henderson     return ret;
710e72ca652SBlue Swirl }
711e72ca652SBlue Swirl 
712722bfec3SRichard Henderson /* 64-bit FP multiply and subtract */
713722bfec3SRichard Henderson uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
714722bfec3SRichard Henderson                       uint64_t f2, uint64_t f3)
715e72ca652SBlue Swirl {
716722bfec3SRichard Henderson     float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
717e72ca652SBlue Swirl                                  &env->fpu_status);
718cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
719722bfec3SRichard Henderson     return ret;
720e72ca652SBlue Swirl }
721e72ca652SBlue Swirl 
722fc7cc951SDavid Hildenbrand /* The rightmost bit has the number 11. */
723fc7cc951SDavid Hildenbrand static inline uint16_t dcmask(int bit, bool neg)
724fc7cc951SDavid Hildenbrand {
725fc7cc951SDavid Hildenbrand     return 1 << (11 - bit - neg);
726fc7cc951SDavid Hildenbrand }
727fc7cc951SDavid Hildenbrand 
728fc7cc951SDavid Hildenbrand #define DEF_FLOAT_DCMASK(_TYPE) \
729fc7cc951SDavid Hildenbrand static uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1)       \
730fc7cc951SDavid Hildenbrand {                                                                  \
731fc7cc951SDavid Hildenbrand     const bool neg = _TYPE##_is_neg(f1);                           \
732fc7cc951SDavid Hildenbrand                                                                    \
733fc7cc951SDavid Hildenbrand     /* Sorted by most common cases - only one class is possible */ \
734fc7cc951SDavid Hildenbrand     if (_TYPE##_is_normal(f1)) {                                   \
735fc7cc951SDavid Hildenbrand         return dcmask(2, neg);                                     \
736fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_zero(f1)) {                              \
737fc7cc951SDavid Hildenbrand         return dcmask(0, neg);                                     \
738fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_denormal(f1)) {                          \
739fc7cc951SDavid Hildenbrand         return dcmask(4, neg);                                     \
740fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_infinity(f1)) {                          \
741fc7cc951SDavid Hildenbrand         return dcmask(6, neg);                                     \
742fc7cc951SDavid Hildenbrand     } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) {       \
743fc7cc951SDavid Hildenbrand         return dcmask(8, neg);                                     \
744fc7cc951SDavid Hildenbrand     }                                                              \
745fc7cc951SDavid Hildenbrand     /* signaling nan, as last remaining case */                    \
746fc7cc951SDavid Hildenbrand     return dcmask(10, neg);                                        \
747fc7cc951SDavid Hildenbrand }
748fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float32)
749fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float64)
750fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float128)
751fc7cc951SDavid Hildenbrand 
752e72ca652SBlue Swirl /* test data class 32-bit */
753af39bc8cSAleksandar Markovic uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2)
754e72ca652SBlue Swirl {
755fc7cc951SDavid Hildenbrand     return (m2 & float32_dcmask(env, f1)) != 0;
756e72ca652SBlue Swirl }
757e72ca652SBlue Swirl 
758e72ca652SBlue Swirl /* test data class 64-bit */
759af39bc8cSAleksandar Markovic uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2)
760e72ca652SBlue Swirl {
761fc7cc951SDavid Hildenbrand     return (m2 & float64_dcmask(env, v1)) != 0;
762e72ca652SBlue Swirl }
763e72ca652SBlue Swirl 
764e72ca652SBlue Swirl /* test data class 128-bit */
765fc7cc951SDavid Hildenbrand uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2)
766e72ca652SBlue Swirl {
767fc7cc951SDavid Hildenbrand     return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0;
768e72ca652SBlue Swirl }
769e72ca652SBlue Swirl 
77016d7b2a4SRichard Henderson /* square root 32-bit */
77116d7b2a4SRichard Henderson uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
772e72ca652SBlue Swirl {
77316d7b2a4SRichard Henderson     float32 ret = float32_sqrt(f2, &env->fpu_status);
774cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
77516d7b2a4SRichard Henderson     return ret;
77616d7b2a4SRichard Henderson }
77716d7b2a4SRichard Henderson 
77816d7b2a4SRichard Henderson /* square root 64-bit */
77916d7b2a4SRichard Henderson uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
78016d7b2a4SRichard Henderson {
78116d7b2a4SRichard Henderson     float64 ret = float64_sqrt(f2, &env->fpu_status);
782cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
78316d7b2a4SRichard Henderson     return ret;
78416d7b2a4SRichard Henderson }
78516d7b2a4SRichard Henderson 
78616d7b2a4SRichard Henderson /* square root 128-bit */
78716d7b2a4SRichard Henderson uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
78816d7b2a4SRichard Henderson {
78916d7b2a4SRichard Henderson     float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
790cf97f9ffSDavid Hildenbrand     handle_exceptions(env, false, GETPC());
79116d7b2a4SRichard Henderson     return RET128(ret);
792e72ca652SBlue Swirl }
7938379bfdbSRichard Henderson 
7942aea83c6SDavid Hildenbrand static const int fpc_to_rnd[8] = {
7958379bfdbSRichard Henderson     float_round_nearest_even,
7968379bfdbSRichard Henderson     float_round_to_zero,
7978379bfdbSRichard Henderson     float_round_up,
7982aea83c6SDavid Hildenbrand     float_round_down,
7992aea83c6SDavid Hildenbrand     -1,
8002aea83c6SDavid Hildenbrand     -1,
8012aea83c6SDavid Hildenbrand     -1,
8022aea83c6SDavid Hildenbrand     float_round_to_odd,
8038379bfdbSRichard Henderson };
8048379bfdbSRichard Henderson 
805411edc22SRichard Henderson /* set fpc */
806411edc22SRichard Henderson void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
807411edc22SRichard Henderson {
8082aea83c6SDavid Hildenbrand     if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
8092aea83c6SDavid Hildenbrand         (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
8102aea83c6SDavid Hildenbrand         s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
8112aea83c6SDavid Hildenbrand     }
8122aea83c6SDavid Hildenbrand 
8138379bfdbSRichard Henderson     /* Install everything in the main FPC.  */
8148379bfdbSRichard Henderson     env->fpc = fpc;
8158379bfdbSRichard Henderson 
8168379bfdbSRichard Henderson     /* Install the rounding mode in the shadow fpu_status.  */
8172aea83c6SDavid Hildenbrand     set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
818411edc22SRichard Henderson }
819411edc22SRichard Henderson 
820411edc22SRichard Henderson /* set fpc and signal */
821f66a0ecfSDavid Hildenbrand void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
822411edc22SRichard Henderson {
823411edc22SRichard Henderson     uint32_t signalling = env->fpc;
824411edc22SRichard Henderson     uint32_t s390_exc;
825411edc22SRichard Henderson 
8262aea83c6SDavid Hildenbrand     if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
8272aea83c6SDavid Hildenbrand         (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
8282aea83c6SDavid Hildenbrand         s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
8292aea83c6SDavid Hildenbrand     }
8302aea83c6SDavid Hildenbrand 
831f66a0ecfSDavid Hildenbrand     /*
832f66a0ecfSDavid Hildenbrand      * FPC is set to the FPC operand with a bitwise OR of the signalling
833f66a0ecfSDavid Hildenbrand      * flags.
834f66a0ecfSDavid Hildenbrand      */
835f66a0ecfSDavid Hildenbrand     env->fpc = fpc | (signalling & 0x00ff0000);
8362aea83c6SDavid Hildenbrand     set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
837411edc22SRichard Henderson 
838f66a0ecfSDavid Hildenbrand     /*
839f66a0ecfSDavid Hildenbrand      * If any signaling flag is enabled in the new FPC mask, a
840f66a0ecfSDavid Hildenbrand      * simulated-iee-exception exception occurs.
841f66a0ecfSDavid Hildenbrand      */
842f66a0ecfSDavid Hildenbrand     s390_exc = (signalling >> 16) & (fpc >> 24);
843411edc22SRichard Henderson     if (s390_exc) {
8448772bbe4SDavid Hildenbrand         if (s390_exc & S390_IEEE_MASK_INVALID) {
8458772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_INVALID;
8468772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) {
8478772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_DIVBYZERO;
8488772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) {
8498772bbe4SDavid Hildenbrand             s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT);
8508772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) {
8518772bbe4SDavid Hildenbrand             s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT);
8528772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_INEXACT) {
8538772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_INEXACT;
8548772bbe4SDavid Hildenbrand         } else if (s390_exc & S390_IEEE_MASK_QUANTUM) {
8558772bbe4SDavid Hildenbrand             s390_exc = S390_IEEE_MASK_QUANTUM;
8568772bbe4SDavid Hildenbrand         }
857bbf6ea3bSDavid Hildenbrand         tcg_s390_data_exception(env, s390_exc | 3, GETPC());
858411edc22SRichard Henderson     }
8598379bfdbSRichard Henderson }
860b9c737f5SDavid Hildenbrand 
861b9c737f5SDavid Hildenbrand /* set bfp rounding mode */
862b9c737f5SDavid Hildenbrand void HELPER(srnm)(CPUS390XState *env, uint64_t rnd)
863b9c737f5SDavid Hildenbrand {
864b9c737f5SDavid Hildenbrand     if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) {
865b9c737f5SDavid Hildenbrand         s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
866b9c737f5SDavid Hildenbrand     }
867b9c737f5SDavid Hildenbrand 
868b9c737f5SDavid Hildenbrand     env->fpc = deposit32(env->fpc, 0, 3, rnd);
869b9c737f5SDavid Hildenbrand     set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status);
870b9c737f5SDavid Hildenbrand }
871