xref: /openbmc/qemu/target/ppc/fpu_helper.c (revision ced29396)
1 /*
2  *  PowerPC floating point and SPE emulation helpers for QEMU.
3  *
4  *  Copyright (c) 2003-2007 Jocelyn Mayer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22 #include "exec/exec-all.h"
23 #include "internal.h"
24 #include "fpu/softfloat.h"
25 
26 static inline float128 float128_snan_to_qnan(float128 x)
27 {
28     float128 r;
29 
30     r.high = x.high | 0x0000800000000000;
31     r.low = x.low;
32     return r;
33 }
34 
35 #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
36 #define float32_snan_to_qnan(x) ((x) | 0x00400000)
37 #define float16_snan_to_qnan(x) ((x) | 0x0200)
38 
39 static inline float32 bfp32_neg(float32 a)
40 {
41     if (unlikely(float32_is_any_nan(a))) {
42         return a;
43     } else {
44         return float32_chs(a);
45     }
46 }
47 
48 static inline bool fp_exceptions_enabled(CPUPPCState *env)
49 {
50 #ifdef CONFIG_USER_ONLY
51     return true;
52 #else
53     return (env->msr & ((1U << MSR_FE0) | (1U << MSR_FE1))) != 0;
54 #endif
55 }
56 
57 /*****************************************************************************/
58 /* Floating point operations helpers */
59 
60 /*
61  * This is the non-arithmatic conversion that happens e.g. on loads.
62  * In the Power ISA pseudocode, this is called DOUBLE.
63  */
64 uint64_t helper_todouble(uint32_t arg)
65 {
66     uint32_t abs_arg = arg & 0x7fffffff;
67     uint64_t ret;
68 
69     if (likely(abs_arg >= 0x00800000)) {
70         if (unlikely(extract32(arg, 23, 8) == 0xff)) {
71             /* Inf or NAN.  */
72             ret  = (uint64_t)extract32(arg, 31, 1) << 63;
73             ret |= (uint64_t)0x7ff << 52;
74             ret |= (uint64_t)extract32(arg, 0, 23) << 29;
75         } else {
76             /* Normalized operand.  */
77             ret  = (uint64_t)extract32(arg, 30, 2) << 62;
78             ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59;
79             ret |= (uint64_t)extract32(arg, 0, 30) << 29;
80         }
81     } else {
82         /* Zero or Denormalized operand.  */
83         ret = (uint64_t)extract32(arg, 31, 1) << 63;
84         if (unlikely(abs_arg != 0)) {
85             /*
86              * Denormalized operand.
87              * Shift fraction so that the msb is in the implicit bit position.
88              * Thus, shift is in the range [1:23].
89              */
90             int shift = clz32(abs_arg) - 8;
91             /*
92              * The first 3 terms compute the float64 exponent.  We then bias
93              * this result by -1 so that we can swallow the implicit bit below.
94              */
95             int exp = -126 - shift + 1023 - 1;
96 
97             ret |= (uint64_t)exp << 52;
98             ret += (uint64_t)abs_arg << (52 - 23 + shift);
99         }
100     }
101     return ret;
102 }
103 
104 /*
105  * This is the non-arithmatic conversion that happens e.g. on stores.
106  * In the Power ISA pseudocode, this is called SINGLE.
107  */
108 uint32_t helper_tosingle(uint64_t arg)
109 {
110     int exp = extract64(arg, 52, 11);
111     uint32_t ret;
112 
113     if (likely(exp > 896)) {
114         /* No denormalization required (includes Inf, NaN).  */
115         ret  = extract64(arg, 62, 2) << 30;
116         ret |= extract64(arg, 29, 30);
117     } else {
118         /*
119          * Zero or Denormal result.  If the exponent is in bounds for
120          * a single-precision denormal result, extract the proper
121          * bits.  If the input is not zero, and the exponent is out of
122          * bounds, then the result is undefined; this underflows to
123          * zero.
124          */
125         ret = extract64(arg, 63, 1) << 31;
126         if (unlikely(exp >= 874)) {
127             /* Denormal result.  */
128             ret |= ((1ULL << 52) | extract64(arg, 0, 52)) >> (896 + 30 - exp);
129         }
130     }
131     return ret;
132 }
133 
134 static inline int ppc_float32_get_unbiased_exp(float32 f)
135 {
136     return ((f >> 23) & 0xFF) - 127;
137 }
138 
139 static inline int ppc_float64_get_unbiased_exp(float64 f)
140 {
141     return ((f >> 52) & 0x7FF) - 1023;
142 }
143 
144 /* Classify a floating-point number.  */
145 enum {
146     is_normal   = 1,
147     is_zero     = 2,
148     is_denormal = 4,
149     is_inf      = 8,
150     is_qnan     = 16,
151     is_snan     = 32,
152     is_neg      = 64,
153 };
154 
155 #define COMPUTE_CLASS(tp)                                      \
156 static int tp##_classify(tp arg)                               \
157 {                                                              \
158     int ret = tp##_is_neg(arg) * is_neg;                       \
159     if (unlikely(tp##_is_any_nan(arg))) {                      \
160         float_status dummy = { };  /* snan_bit_is_one = 0 */   \
161         ret |= (tp##_is_signaling_nan(arg, &dummy)             \
162                 ? is_snan : is_qnan);                          \
163     } else if (unlikely(tp##_is_infinity(arg))) {              \
164         ret |= is_inf;                                         \
165     } else if (tp##_is_zero(arg)) {                            \
166         ret |= is_zero;                                        \
167     } else if (tp##_is_zero_or_denormal(arg)) {                \
168         ret |= is_denormal;                                    \
169     } else {                                                   \
170         ret |= is_normal;                                      \
171     }                                                          \
172     return ret;                                                \
173 }
174 
175 COMPUTE_CLASS(float16)
176 COMPUTE_CLASS(float32)
177 COMPUTE_CLASS(float64)
178 COMPUTE_CLASS(float128)
179 
180 static void set_fprf_from_class(CPUPPCState *env, int class)
181 {
182     static const uint8_t fprf[6][2] = {
183         { 0x04, 0x08 },  /* normalized */
184         { 0x02, 0x12 },  /* zero */
185         { 0x14, 0x18 },  /* denormalized */
186         { 0x05, 0x09 },  /* infinity */
187         { 0x11, 0x11 },  /* qnan */
188         { 0x00, 0x00 },  /* snan -- flags are undefined */
189     };
190     bool isneg = class & is_neg;
191 
192     env->fpscr &= ~FP_FPRF;
193     env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF;
194 }
195 
196 #define COMPUTE_FPRF(tp)                                \
197 void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
198 {                                                       \
199     set_fprf_from_class(env, tp##_classify(arg));       \
200 }
201 
202 COMPUTE_FPRF(float16)
203 COMPUTE_FPRF(float32)
204 COMPUTE_FPRF(float64)
205 COMPUTE_FPRF(float128)
206 
207 /* Floating-point invalid operations exception */
208 static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr)
209 {
210     /* Update the floating-point invalid operation summary */
211     env->fpscr |= FP_VX;
212     /* Update the floating-point exception summary */
213     env->fpscr |= FP_FX;
214     if (env->fpscr & FP_VE) {
215         /* Update the floating-point enabled exception summary */
216         env->fpscr |= FP_FEX;
217         if (fp_exceptions_enabled(env)) {
218             raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
219                                    POWERPC_EXCP_FP | op, retaddr);
220         }
221     }
222 }
223 
224 static void finish_invalid_op_arith(CPUPPCState *env, int op,
225                                     bool set_fpcc, uintptr_t retaddr)
226 {
227     env->fpscr &= ~(FP_FR | FP_FI);
228     if (!(env->fpscr & FP_VE)) {
229         if (set_fpcc) {
230             env->fpscr &= ~FP_FPCC;
231             env->fpscr |= (FP_C | FP_FU);
232         }
233     }
234     finish_invalid_op_excp(env, op, retaddr);
235 }
236 
237 /* Signalling NaN */
238 static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr)
239 {
240     env->fpscr |= FP_VXSNAN;
241     finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr);
242 }
243 
244 /* Magnitude subtraction of infinities */
245 static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc,
246                                    uintptr_t retaddr)
247 {
248     env->fpscr |= FP_VXISI;
249     finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr);
250 }
251 
252 /* Division of infinity by infinity */
253 static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc,
254                                    uintptr_t retaddr)
255 {
256     env->fpscr |= FP_VXIDI;
257     finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr);
258 }
259 
260 /* Division of zero by zero */
261 static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc,
262                                    uintptr_t retaddr)
263 {
264     env->fpscr |= FP_VXZDZ;
265     finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr);
266 }
267 
268 /* Multiplication of zero by infinity */
269 static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc,
270                                    uintptr_t retaddr)
271 {
272     env->fpscr |= FP_VXIMZ;
273     finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr);
274 }
275 
276 /* Square root of a negative number */
277 static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc,
278                                     uintptr_t retaddr)
279 {
280     env->fpscr |= FP_VXSQRT;
281     finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr);
282 }
283 
284 /* Ordered comparison of NaN */
285 static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
286                                   uintptr_t retaddr)
287 {
288     env->fpscr |= FP_VXVC;
289     if (set_fpcc) {
290         env->fpscr &= ~FP_FPCC;
291         env->fpscr |= (FP_C | FP_FU);
292     }
293     /* Update the floating-point invalid operation summary */
294     env->fpscr |= FP_VX;
295     /* Update the floating-point exception summary */
296     env->fpscr |= FP_FX;
297     /* We must update the target FPR before raising the exception */
298     if (env->fpscr & FP_VE) {
299         CPUState *cs = env_cpu(env);
300 
301         cs->exception_index = POWERPC_EXCP_PROGRAM;
302         env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
303         /* Update the floating-point enabled exception summary */
304         env->fpscr |= FP_FEX;
305         /* Exception is deferred */
306     }
307 }
308 
309 /* Invalid conversion */
310 static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc,
311                                    uintptr_t retaddr)
312 {
313     env->fpscr |= FP_VXCVI;
314     env->fpscr &= ~(FP_FR | FP_FI);
315     if (!(env->fpscr & FP_VE)) {
316         if (set_fpcc) {
317             env->fpscr &= ~FP_FPCC;
318             env->fpscr |= (FP_C | FP_FU);
319         }
320     }
321     finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr);
322 }
323 
324 static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr)
325 {
326     env->fpscr |= FP_ZX;
327     env->fpscr &= ~(FP_FR | FP_FI);
328     /* Update the floating-point exception summary */
329     env->fpscr |= FP_FX;
330     if (env->fpscr & FP_ZE) {
331         /* Update the floating-point enabled exception summary */
332         env->fpscr |= FP_FEX;
333         if (fp_exceptions_enabled(env)) {
334             raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
335                                    POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX,
336                                    raddr);
337         }
338     }
339 }
340 
341 static inline int float_overflow_excp(CPUPPCState *env)
342 {
343     CPUState *cs = env_cpu(env);
344 
345     env->fpscr |= FP_OX;
346     /* Update the floating-point exception summary */
347     env->fpscr |= FP_FX;
348 
349     bool overflow_enabled = !!(env->fpscr & FP_OE);
350     if (overflow_enabled) {
351         /* Update the floating-point enabled exception summary */
352         env->fpscr |= FP_FEX;
353         /* We must update the target FPR before raising the exception */
354         cs->exception_index = POWERPC_EXCP_PROGRAM;
355         env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
356     }
357 
358     return overflow_enabled ? 0 : float_flag_inexact;
359 }
360 
361 static inline void float_underflow_excp(CPUPPCState *env)
362 {
363     CPUState *cs = env_cpu(env);
364 
365     env->fpscr |= FP_UX;
366     /* Update the floating-point exception summary */
367     env->fpscr |= FP_FX;
368     if (env->fpscr & FP_UE) {
369         /* Update the floating-point enabled exception summary */
370         env->fpscr |= FP_FEX;
371         /* We must update the target FPR before raising the exception */
372         cs->exception_index = POWERPC_EXCP_PROGRAM;
373         env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
374     }
375 }
376 
377 static inline void float_inexact_excp(CPUPPCState *env)
378 {
379     CPUState *cs = env_cpu(env);
380 
381     env->fpscr |= FP_XX;
382     /* Update the floating-point exception summary */
383     env->fpscr |= FP_FX;
384     if (env->fpscr & FP_XE) {
385         /* Update the floating-point enabled exception summary */
386         env->fpscr |= FP_FEX;
387         /* We must update the target FPR before raising the exception */
388         cs->exception_index = POWERPC_EXCP_PROGRAM;
389         env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
390     }
391 }
392 
393 void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
394 {
395     uint32_t mask = 1u << bit;
396     if (env->fpscr & mask) {
397         ppc_store_fpscr(env, env->fpscr & ~(target_ulong)mask);
398     }
399 }
400 
401 void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
402 {
403     uint32_t mask = 1u << bit;
404     if (!(env->fpscr & mask)) {
405         ppc_store_fpscr(env, env->fpscr | mask);
406     }
407 }
408 
409 void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles)
410 {
411     target_ulong mask = 0;
412     int i;
413 
414     /* TODO: push this extension back to translation time */
415     for (i = 0; i < sizeof(target_ulong) * 2; i++) {
416         if (nibbles & (1 << i)) {
417             mask |= (target_ulong) 0xf << (4 * i);
418         }
419     }
420     val = (val & mask) | (env->fpscr & ~mask);
421     ppc_store_fpscr(env, val);
422 }
423 
424 static void do_fpscr_check_status(CPUPPCState *env, uintptr_t raddr)
425 {
426     CPUState *cs = env_cpu(env);
427     target_ulong fpscr = env->fpscr;
428     int error = 0;
429 
430     if ((fpscr & FP_OX) && (fpscr & FP_OE)) {
431         error = POWERPC_EXCP_FP_OX;
432     } else if ((fpscr & FP_UX) && (fpscr & FP_UE)) {
433         error = POWERPC_EXCP_FP_UX;
434     } else if ((fpscr & FP_XX) && (fpscr & FP_XE)) {
435         error = POWERPC_EXCP_FP_XX;
436     } else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) {
437         error = POWERPC_EXCP_FP_ZX;
438     } else if (fpscr & FP_VE) {
439         if (fpscr & FP_VXSOFT) {
440             error = POWERPC_EXCP_FP_VXSOFT;
441         } else if (fpscr & FP_VXSNAN) {
442             error = POWERPC_EXCP_FP_VXSNAN;
443         } else if (fpscr & FP_VXISI) {
444             error = POWERPC_EXCP_FP_VXISI;
445         } else if (fpscr & FP_VXIDI) {
446             error = POWERPC_EXCP_FP_VXIDI;
447         } else if (fpscr & FP_VXZDZ) {
448             error = POWERPC_EXCP_FP_VXZDZ;
449         } else if (fpscr & FP_VXIMZ) {
450             error = POWERPC_EXCP_FP_VXIMZ;
451         } else if (fpscr & FP_VXVC) {
452             error = POWERPC_EXCP_FP_VXVC;
453         } else if (fpscr & FP_VXSQRT) {
454             error = POWERPC_EXCP_FP_VXSQRT;
455         } else if (fpscr & FP_VXCVI) {
456             error = POWERPC_EXCP_FP_VXCVI;
457         } else {
458             return;
459         }
460     } else {
461         return;
462     }
463     cs->exception_index = POWERPC_EXCP_PROGRAM;
464     env->error_code = error | POWERPC_EXCP_FP;
465     env->fpscr |= FP_FEX;
466     /* Deferred floating-point exception after target FPSCR update */
467     if (fp_exceptions_enabled(env)) {
468         raise_exception_err_ra(env, cs->exception_index,
469                                env->error_code, raddr);
470     }
471 }
472 
473 void helper_fpscr_check_status(CPUPPCState *env)
474 {
475     do_fpscr_check_status(env, GETPC());
476 }
477 
478 static void do_float_check_status(CPUPPCState *env, bool change_fi,
479                                   uintptr_t raddr)
480 {
481     CPUState *cs = env_cpu(env);
482     int status = get_float_exception_flags(&env->fp_status);
483 
484     if (status & float_flag_overflow) {
485         status |= float_overflow_excp(env);
486     } else if (status & float_flag_underflow) {
487         float_underflow_excp(env);
488     }
489     if (status & float_flag_inexact) {
490         float_inexact_excp(env);
491     }
492     if (change_fi) {
493         env->fpscr = FIELD_DP64(env->fpscr, FPSCR, FI,
494                                 !!(status & float_flag_inexact));
495     }
496 
497     if (cs->exception_index == POWERPC_EXCP_PROGRAM &&
498         (env->error_code & POWERPC_EXCP_FP)) {
499         /* Deferred floating-point exception after target FPR update */
500         if (fp_exceptions_enabled(env)) {
501             raise_exception_err_ra(env, cs->exception_index,
502                                    env->error_code, raddr);
503         }
504     }
505 }
506 
507 void helper_float_check_status(CPUPPCState *env)
508 {
509     do_float_check_status(env, true, GETPC());
510 }
511 
512 void helper_reset_fpstatus(CPUPPCState *env)
513 {
514     set_float_exception_flags(0, &env->fp_status);
515 }
516 
517 static void float_invalid_op_addsub(CPUPPCState *env, int flags,
518                                     bool set_fpcc, uintptr_t retaddr)
519 {
520     if (flags & float_flag_invalid_isi) {
521         float_invalid_op_vxisi(env, set_fpcc, retaddr);
522     } else if (flags & float_flag_invalid_snan) {
523         float_invalid_op_vxsnan(env, retaddr);
524     }
525 }
526 
527 /* fadd - fadd. */
528 float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2)
529 {
530     float64 ret = float64_add(arg1, arg2, &env->fp_status);
531     int flags = get_float_exception_flags(&env->fp_status);
532 
533     if (unlikely(flags & float_flag_invalid)) {
534         float_invalid_op_addsub(env, flags, 1, GETPC());
535     }
536 
537     return ret;
538 }
539 
540 /* fadds - fadds. */
541 float64 helper_fadds(CPUPPCState *env, float64 arg1, float64 arg2)
542 {
543     float64 ret = float64r32_add(arg1, arg2, &env->fp_status);
544     int flags = get_float_exception_flags(&env->fp_status);
545 
546     if (unlikely(flags & float_flag_invalid)) {
547         float_invalid_op_addsub(env, flags, 1, GETPC());
548     }
549     return ret;
550 }
551 
552 /* fsub - fsub. */
553 float64 helper_fsub(CPUPPCState *env, float64 arg1, float64 arg2)
554 {
555     float64 ret = float64_sub(arg1, arg2, &env->fp_status);
556     int flags = get_float_exception_flags(&env->fp_status);
557 
558     if (unlikely(flags & float_flag_invalid)) {
559         float_invalid_op_addsub(env, flags, 1, GETPC());
560     }
561 
562     return ret;
563 }
564 
565 /* fsubs - fsubs. */
566 float64 helper_fsubs(CPUPPCState *env, float64 arg1, float64 arg2)
567 {
568     float64 ret = float64r32_sub(arg1, arg2, &env->fp_status);
569     int flags = get_float_exception_flags(&env->fp_status);
570 
571     if (unlikely(flags & float_flag_invalid)) {
572         float_invalid_op_addsub(env, flags, 1, GETPC());
573     }
574     return ret;
575 }
576 
577 static void float_invalid_op_mul(CPUPPCState *env, int flags,
578                                  bool set_fprc, uintptr_t retaddr)
579 {
580     if (flags & float_flag_invalid_imz) {
581         float_invalid_op_vximz(env, set_fprc, retaddr);
582     } else if (flags & float_flag_invalid_snan) {
583         float_invalid_op_vxsnan(env, retaddr);
584     }
585 }
586 
587 /* fmul - fmul. */
588 float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2)
589 {
590     float64 ret = float64_mul(arg1, arg2, &env->fp_status);
591     int flags = get_float_exception_flags(&env->fp_status);
592 
593     if (unlikely(flags & float_flag_invalid)) {
594         float_invalid_op_mul(env, flags, 1, GETPC());
595     }
596 
597     return ret;
598 }
599 
600 /* fmuls - fmuls. */
601 float64 helper_fmuls(CPUPPCState *env, float64 arg1, float64 arg2)
602 {
603     float64 ret = float64r32_mul(arg1, arg2, &env->fp_status);
604     int flags = get_float_exception_flags(&env->fp_status);
605 
606     if (unlikely(flags & float_flag_invalid)) {
607         float_invalid_op_mul(env, flags, 1, GETPC());
608     }
609     return ret;
610 }
611 
612 static void float_invalid_op_div(CPUPPCState *env, int flags,
613                                  bool set_fprc, uintptr_t retaddr)
614 {
615     if (flags & float_flag_invalid_idi) {
616         float_invalid_op_vxidi(env, set_fprc, retaddr);
617     } else if (flags & float_flag_invalid_zdz) {
618         float_invalid_op_vxzdz(env, set_fprc, retaddr);
619     } else if (flags & float_flag_invalid_snan) {
620         float_invalid_op_vxsnan(env, retaddr);
621     }
622 }
623 
624 /* fdiv - fdiv. */
625 float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2)
626 {
627     float64 ret = float64_div(arg1, arg2, &env->fp_status);
628     int flags = get_float_exception_flags(&env->fp_status);
629 
630     if (unlikely(flags & float_flag_invalid)) {
631         float_invalid_op_div(env, flags, 1, GETPC());
632     }
633     if (unlikely(flags & float_flag_divbyzero)) {
634         float_zero_divide_excp(env, GETPC());
635     }
636 
637     return ret;
638 }
639 
640 /* fdivs - fdivs. */
641 float64 helper_fdivs(CPUPPCState *env, float64 arg1, float64 arg2)
642 {
643     float64 ret = float64r32_div(arg1, arg2, &env->fp_status);
644     int flags = get_float_exception_flags(&env->fp_status);
645 
646     if (unlikely(flags & float_flag_invalid)) {
647         float_invalid_op_div(env, flags, 1, GETPC());
648     }
649     if (unlikely(flags & float_flag_divbyzero)) {
650         float_zero_divide_excp(env, GETPC());
651     }
652 
653     return ret;
654 }
655 
656 static uint64_t float_invalid_cvt(CPUPPCState *env, int flags,
657                                   uint64_t ret, uint64_t ret_nan,
658                                   bool set_fprc, uintptr_t retaddr)
659 {
660     /*
661      * VXCVI is different from most in that it sets two exception bits,
662      * VXCVI and VXSNAN for an SNaN input.
663      */
664     if (flags & float_flag_invalid_snan) {
665         env->fpscr |= FP_VXSNAN;
666     }
667     float_invalid_op_vxcvi(env, set_fprc, retaddr);
668 
669     return flags & float_flag_invalid_cvti ? ret : ret_nan;
670 }
671 
672 #define FPU_FCTI(op, cvt, nanval)                                      \
673 uint64_t helper_##op(CPUPPCState *env, float64 arg)                    \
674 {                                                                      \
675     uint64_t ret = float64_to_##cvt(arg, &env->fp_status);             \
676     int flags = get_float_exception_flags(&env->fp_status);            \
677     if (unlikely(flags & float_flag_invalid)) {                        \
678         ret = float_invalid_cvt(env, flags, ret, nanval, 1, GETPC());  \
679     }                                                                  \
680     return ret;                                                        \
681 }
682 
683 FPU_FCTI(fctiw, int32, 0x80000000U)
684 FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U)
685 FPU_FCTI(fctiwu, uint32, 0x00000000U)
686 FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U)
687 FPU_FCTI(fctid, int64, 0x8000000000000000ULL)
688 FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL)
689 FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL)
690 FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL)
691 
692 #define FPU_FCFI(op, cvtr, is_single)                      \
693 uint64_t helper_##op(CPUPPCState *env, uint64_t arg)       \
694 {                                                          \
695     CPU_DoubleU farg;                                      \
696                                                            \
697     if (is_single) {                                       \
698         float32 tmp = cvtr(arg, &env->fp_status);          \
699         farg.d = float32_to_float64(tmp, &env->fp_status); \
700     } else {                                               \
701         farg.d = cvtr(arg, &env->fp_status);               \
702     }                                                      \
703     do_float_check_status(env, true, GETPC());             \
704     return farg.ll;                                        \
705 }
706 
707 FPU_FCFI(fcfid, int64_to_float64, 0)
708 FPU_FCFI(fcfids, int64_to_float32, 1)
709 FPU_FCFI(fcfidu, uint64_to_float64, 0)
710 FPU_FCFI(fcfidus, uint64_to_float32, 1)
711 
712 static uint64_t do_fri(CPUPPCState *env, uint64_t arg,
713                        FloatRoundMode rounding_mode)
714 {
715     FloatRoundMode old_rounding_mode = get_float_rounding_mode(&env->fp_status);
716     int flags;
717 
718     set_float_rounding_mode(rounding_mode, &env->fp_status);
719     arg = float64_round_to_int(arg, &env->fp_status);
720     set_float_rounding_mode(old_rounding_mode, &env->fp_status);
721 
722     flags = get_float_exception_flags(&env->fp_status);
723     if (flags & float_flag_invalid_snan) {
724         float_invalid_op_vxsnan(env, GETPC());
725     }
726 
727     /* fri* does not set FPSCR[XX] */
728     set_float_exception_flags(flags & ~float_flag_inexact, &env->fp_status);
729     do_float_check_status(env, true, GETPC());
730 
731     return arg;
732 }
733 
734 uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
735 {
736     return do_fri(env, arg, float_round_ties_away);
737 }
738 
739 uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
740 {
741     return do_fri(env, arg, float_round_to_zero);
742 }
743 
744 uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
745 {
746     return do_fri(env, arg, float_round_up);
747 }
748 
749 uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
750 {
751     return do_fri(env, arg, float_round_down);
752 }
753 
754 static void float_invalid_op_madd(CPUPPCState *env, int flags,
755                                   bool set_fpcc, uintptr_t retaddr)
756 {
757     if (flags & float_flag_invalid_imz) {
758         float_invalid_op_vximz(env, set_fpcc, retaddr);
759     } else {
760         float_invalid_op_addsub(env, flags, set_fpcc, retaddr);
761     }
762 }
763 
764 static float64 do_fmadd(CPUPPCState *env, float64 a, float64 b,
765                          float64 c, int madd_flags, uintptr_t retaddr)
766 {
767     float64 ret = float64_muladd(a, b, c, madd_flags, &env->fp_status);
768     int flags = get_float_exception_flags(&env->fp_status);
769 
770     if (unlikely(flags & float_flag_invalid)) {
771         float_invalid_op_madd(env, flags, 1, retaddr);
772     }
773     return ret;
774 }
775 
776 static uint64_t do_fmadds(CPUPPCState *env, float64 a, float64 b,
777                           float64 c, int madd_flags, uintptr_t retaddr)
778 {
779     float64 ret = float64r32_muladd(a, b, c, madd_flags, &env->fp_status);
780     int flags = get_float_exception_flags(&env->fp_status);
781 
782     if (unlikely(flags & float_flag_invalid)) {
783         float_invalid_op_madd(env, flags, 1, retaddr);
784     }
785     return ret;
786 }
787 
788 #define FPU_FMADD(op, madd_flags)                                    \
789     uint64_t helper_##op(CPUPPCState *env, uint64_t arg1,            \
790                          uint64_t arg2, uint64_t arg3)               \
791     { return do_fmadd(env, arg1, arg2, arg3, madd_flags, GETPC()); } \
792     uint64_t helper_##op##s(CPUPPCState *env, uint64_t arg1,         \
793                          uint64_t arg2, uint64_t arg3)               \
794     { return do_fmadds(env, arg1, arg2, arg3, madd_flags, GETPC()); }
795 
796 #define MADD_FLGS 0
797 #define MSUB_FLGS float_muladd_negate_c
798 #define NMADD_FLGS float_muladd_negate_result
799 #define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
800 
801 FPU_FMADD(fmadd, MADD_FLGS)
802 FPU_FMADD(fnmadd, NMADD_FLGS)
803 FPU_FMADD(fmsub, MSUB_FLGS)
804 FPU_FMADD(fnmsub, NMSUB_FLGS)
805 
806 /* frsp - frsp. */
807 static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr)
808 {
809     float32 f32 = float64_to_float32(arg, &env->fp_status);
810     int flags = get_float_exception_flags(&env->fp_status);
811 
812     if (unlikely(flags & float_flag_invalid_snan)) {
813         float_invalid_op_vxsnan(env, retaddr);
814     }
815     return helper_todouble(f32);
816 }
817 
818 uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
819 {
820     return do_frsp(env, arg, GETPC());
821 }
822 
823 static void float_invalid_op_sqrt(CPUPPCState *env, int flags,
824                                   bool set_fpcc, uintptr_t retaddr)
825 {
826     if (unlikely(flags & float_flag_invalid_sqrt)) {
827         float_invalid_op_vxsqrt(env, set_fpcc, retaddr);
828     } else if (unlikely(flags & float_flag_invalid_snan)) {
829         float_invalid_op_vxsnan(env, retaddr);
830     }
831 }
832 
833 #define FPU_FSQRT(name, op)                                                   \
834 float64 helper_##name(CPUPPCState *env, float64 arg)                          \
835 {                                                                             \
836     float64 ret = op(arg, &env->fp_status);                                   \
837     int flags = get_float_exception_flags(&env->fp_status);                   \
838                                                                               \
839     if (unlikely(flags & float_flag_invalid)) {                               \
840         float_invalid_op_sqrt(env, flags, 1, GETPC());                        \
841     }                                                                         \
842                                                                               \
843     return ret;                                                               \
844 }
845 
846 FPU_FSQRT(FSQRT, float64_sqrt)
847 FPU_FSQRT(FSQRTS, float64r32_sqrt)
848 
849 /* fre - fre. */
850 float64 helper_fre(CPUPPCState *env, float64 arg)
851 {
852     /* "Estimate" the reciprocal with actual division.  */
853     float64 ret = float64_div(float64_one, arg, &env->fp_status);
854     int flags = get_float_exception_flags(&env->fp_status);
855 
856     if (unlikely(flags & float_flag_invalid_snan)) {
857         float_invalid_op_vxsnan(env, GETPC());
858     }
859     if (unlikely(flags & float_flag_divbyzero)) {
860         float_zero_divide_excp(env, GETPC());
861         /* For FPSCR.ZE == 0, the result is 1/2.  */
862         ret = float64_set_sign(float64_half, float64_is_neg(arg));
863     }
864 
865     return ret;
866 }
867 
868 /* fres - fres. */
869 uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
870 {
871     /* "Estimate" the reciprocal with actual division.  */
872     float64 ret = float64r32_div(float64_one, arg, &env->fp_status);
873     int flags = get_float_exception_flags(&env->fp_status);
874 
875     if (unlikely(flags & float_flag_invalid_snan)) {
876         float_invalid_op_vxsnan(env, GETPC());
877     }
878     if (unlikely(flags & float_flag_divbyzero)) {
879         float_zero_divide_excp(env, GETPC());
880         /* For FPSCR.ZE == 0, the result is 1/2.  */
881         ret = float64_set_sign(float64_half, float64_is_neg(arg));
882     }
883 
884     return ret;
885 }
886 
887 /* frsqrte  - frsqrte. */
888 float64 helper_frsqrte(CPUPPCState *env, float64 arg)
889 {
890     /* "Estimate" the reciprocal with actual division.  */
891     float64 rets = float64_sqrt(arg, &env->fp_status);
892     float64 retd = float64_div(float64_one, rets, &env->fp_status);
893     int flags = get_float_exception_flags(&env->fp_status);
894 
895     if (unlikely(flags & float_flag_invalid)) {
896         float_invalid_op_sqrt(env, flags, 1, GETPC());
897     }
898     if (unlikely(flags & float_flag_divbyzero)) {
899         /* Reciprocal of (square root of) zero.  */
900         float_zero_divide_excp(env, GETPC());
901     }
902 
903     return retd;
904 }
905 
906 /* frsqrtes  - frsqrtes. */
907 float64 helper_frsqrtes(CPUPPCState *env, float64 arg)
908 {
909     /* "Estimate" the reciprocal with actual division.  */
910     float64 rets = float64_sqrt(arg, &env->fp_status);
911     float64 retd = float64r32_div(float64_one, rets, &env->fp_status);
912     int flags = get_float_exception_flags(&env->fp_status);
913 
914     if (unlikely(flags & float_flag_invalid)) {
915         float_invalid_op_sqrt(env, flags, 1, GETPC());
916     }
917     if (unlikely(flags & float_flag_divbyzero)) {
918         /* Reciprocal of (square root of) zero.  */
919         float_zero_divide_excp(env, GETPC());
920     }
921 
922     return retd;
923 }
924 
925 /* fsel - fsel. */
926 uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c)
927 {
928     CPU_DoubleU fa;
929 
930     fa.ll = a;
931 
932     if ((!float64_is_neg(fa.d) || float64_is_zero(fa.d)) &&
933         !float64_is_any_nan(fa.d)) {
934         return c;
935     } else {
936         return b;
937     }
938 }
939 
940 uint32_t helper_ftdiv(uint64_t fra, uint64_t frb)
941 {
942     int fe_flag = 0;
943     int fg_flag = 0;
944 
945     if (unlikely(float64_is_infinity(fra) ||
946                  float64_is_infinity(frb) ||
947                  float64_is_zero(frb))) {
948         fe_flag = 1;
949         fg_flag = 1;
950     } else {
951         int e_a = ppc_float64_get_unbiased_exp(fra);
952         int e_b = ppc_float64_get_unbiased_exp(frb);
953 
954         if (unlikely(float64_is_any_nan(fra) ||
955                      float64_is_any_nan(frb))) {
956             fe_flag = 1;
957         } else if ((e_b <= -1022) || (e_b >= 1021)) {
958             fe_flag = 1;
959         } else if (!float64_is_zero(fra) &&
960                    (((e_a - e_b) >= 1023) ||
961                     ((e_a - e_b) <= -1021) ||
962                     (e_a <= -970))) {
963             fe_flag = 1;
964         }
965 
966         if (unlikely(float64_is_zero_or_denormal(frb))) {
967             /* XB is not zero because of the above check and */
968             /* so must be denormalized.                      */
969             fg_flag = 1;
970         }
971     }
972 
973     return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
974 }
975 
976 uint32_t helper_ftsqrt(uint64_t frb)
977 {
978     int fe_flag = 0;
979     int fg_flag = 0;
980 
981     if (unlikely(float64_is_infinity(frb) || float64_is_zero(frb))) {
982         fe_flag = 1;
983         fg_flag = 1;
984     } else {
985         int e_b = ppc_float64_get_unbiased_exp(frb);
986 
987         if (unlikely(float64_is_any_nan(frb))) {
988             fe_flag = 1;
989         } else if (unlikely(float64_is_zero(frb))) {
990             fe_flag = 1;
991         } else if (unlikely(float64_is_neg(frb))) {
992             fe_flag = 1;
993         } else if (!float64_is_zero(frb) && (e_b <= (-1022 + 52))) {
994             fe_flag = 1;
995         }
996 
997         if (unlikely(float64_is_zero_or_denormal(frb))) {
998             /* XB is not zero because of the above check and */
999             /* therefore must be denormalized.               */
1000             fg_flag = 1;
1001         }
1002     }
1003 
1004     return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
1005 }
1006 
1007 void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
1008                   uint32_t crfD)
1009 {
1010     CPU_DoubleU farg1, farg2;
1011     uint32_t ret = 0;
1012 
1013     farg1.ll = arg1;
1014     farg2.ll = arg2;
1015 
1016     if (unlikely(float64_is_any_nan(farg1.d) ||
1017                  float64_is_any_nan(farg2.d))) {
1018         ret = 0x01UL;
1019     } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1020         ret = 0x08UL;
1021     } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1022         ret = 0x04UL;
1023     } else {
1024         ret = 0x02UL;
1025     }
1026 
1027     env->fpscr &= ~FP_FPCC;
1028     env->fpscr |= ret << FPSCR_FPCC;
1029     env->crf[crfD] = ret;
1030     if (unlikely(ret == 0x01UL
1031                  && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
1032                      float64_is_signaling_nan(farg2.d, &env->fp_status)))) {
1033         /* sNaN comparison */
1034         float_invalid_op_vxsnan(env, GETPC());
1035     }
1036 }
1037 
1038 void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
1039                   uint32_t crfD)
1040 {
1041     CPU_DoubleU farg1, farg2;
1042     uint32_t ret = 0;
1043 
1044     farg1.ll = arg1;
1045     farg2.ll = arg2;
1046 
1047     if (unlikely(float64_is_any_nan(farg1.d) ||
1048                  float64_is_any_nan(farg2.d))) {
1049         ret = 0x01UL;
1050     } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1051         ret = 0x08UL;
1052     } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1053         ret = 0x04UL;
1054     } else {
1055         ret = 0x02UL;
1056     }
1057 
1058     env->fpscr &= ~FP_FPCC;
1059     env->fpscr |= ret << FPSCR_FPCC;
1060     env->crf[crfD] = (uint32_t) ret;
1061     if (unlikely(ret == 0x01UL)) {
1062         float_invalid_op_vxvc(env, 1, GETPC());
1063         if (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
1064             float64_is_signaling_nan(farg2.d, &env->fp_status)) {
1065             /* sNaN comparison */
1066             float_invalid_op_vxsnan(env, GETPC());
1067         }
1068     }
1069 }
1070 
1071 /* Single-precision floating-point conversions */
1072 static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val)
1073 {
1074     CPU_FloatU u;
1075 
1076     u.f = int32_to_float32(val, &env->vec_status);
1077 
1078     return u.l;
1079 }
1080 
1081 static inline uint32_t efscfui(CPUPPCState *env, uint32_t val)
1082 {
1083     CPU_FloatU u;
1084 
1085     u.f = uint32_to_float32(val, &env->vec_status);
1086 
1087     return u.l;
1088 }
1089 
1090 static inline int32_t efsctsi(CPUPPCState *env, uint32_t val)
1091 {
1092     CPU_FloatU u;
1093 
1094     u.l = val;
1095     /* NaN are not treated the same way IEEE 754 does */
1096     if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1097         return 0;
1098     }
1099 
1100     return float32_to_int32(u.f, &env->vec_status);
1101 }
1102 
1103 static inline uint32_t efsctui(CPUPPCState *env, uint32_t val)
1104 {
1105     CPU_FloatU u;
1106 
1107     u.l = val;
1108     /* NaN are not treated the same way IEEE 754 does */
1109     if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1110         return 0;
1111     }
1112 
1113     return float32_to_uint32(u.f, &env->vec_status);
1114 }
1115 
1116 static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val)
1117 {
1118     CPU_FloatU u;
1119 
1120     u.l = val;
1121     /* NaN are not treated the same way IEEE 754 does */
1122     if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1123         return 0;
1124     }
1125 
1126     return float32_to_int32_round_to_zero(u.f, &env->vec_status);
1127 }
1128 
1129 static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val)
1130 {
1131     CPU_FloatU u;
1132 
1133     u.l = val;
1134     /* NaN are not treated the same way IEEE 754 does */
1135     if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1136         return 0;
1137     }
1138 
1139     return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
1140 }
1141 
1142 static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val)
1143 {
1144     CPU_FloatU u;
1145     float32 tmp;
1146 
1147     u.f = int32_to_float32(val, &env->vec_status);
1148     tmp = int64_to_float32(1ULL << 32, &env->vec_status);
1149     u.f = float32_div(u.f, tmp, &env->vec_status);
1150 
1151     return u.l;
1152 }
1153 
1154 static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val)
1155 {
1156     CPU_FloatU u;
1157     float32 tmp;
1158 
1159     u.f = uint32_to_float32(val, &env->vec_status);
1160     tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1161     u.f = float32_div(u.f, tmp, &env->vec_status);
1162 
1163     return u.l;
1164 }
1165 
1166 static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val)
1167 {
1168     CPU_FloatU u;
1169     float32 tmp;
1170 
1171     u.l = val;
1172     /* NaN are not treated the same way IEEE 754 does */
1173     if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1174         return 0;
1175     }
1176     tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1177     u.f = float32_mul(u.f, tmp, &env->vec_status);
1178 
1179     return float32_to_int32(u.f, &env->vec_status);
1180 }
1181 
1182 static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val)
1183 {
1184     CPU_FloatU u;
1185     float32 tmp;
1186 
1187     u.l = val;
1188     /* NaN are not treated the same way IEEE 754 does */
1189     if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1190         return 0;
1191     }
1192     tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1193     u.f = float32_mul(u.f, tmp, &env->vec_status);
1194 
1195     return float32_to_uint32(u.f, &env->vec_status);
1196 }
1197 
1198 #define HELPER_SPE_SINGLE_CONV(name)                              \
1199     uint32_t helper_e##name(CPUPPCState *env, uint32_t val)       \
1200     {                                                             \
1201         return e##name(env, val);                                 \
1202     }
1203 /* efscfsi */
1204 HELPER_SPE_SINGLE_CONV(fscfsi);
1205 /* efscfui */
1206 HELPER_SPE_SINGLE_CONV(fscfui);
1207 /* efscfuf */
1208 HELPER_SPE_SINGLE_CONV(fscfuf);
1209 /* efscfsf */
1210 HELPER_SPE_SINGLE_CONV(fscfsf);
1211 /* efsctsi */
1212 HELPER_SPE_SINGLE_CONV(fsctsi);
1213 /* efsctui */
1214 HELPER_SPE_SINGLE_CONV(fsctui);
1215 /* efsctsiz */
1216 HELPER_SPE_SINGLE_CONV(fsctsiz);
1217 /* efsctuiz */
1218 HELPER_SPE_SINGLE_CONV(fsctuiz);
1219 /* efsctsf */
1220 HELPER_SPE_SINGLE_CONV(fsctsf);
1221 /* efsctuf */
1222 HELPER_SPE_SINGLE_CONV(fsctuf);
1223 
1224 #define HELPER_SPE_VECTOR_CONV(name)                            \
1225     uint64_t helper_ev##name(CPUPPCState *env, uint64_t val)    \
1226     {                                                           \
1227         return ((uint64_t)e##name(env, val >> 32) << 32) |      \
1228             (uint64_t)e##name(env, val);                        \
1229     }
1230 /* evfscfsi */
1231 HELPER_SPE_VECTOR_CONV(fscfsi);
1232 /* evfscfui */
1233 HELPER_SPE_VECTOR_CONV(fscfui);
1234 /* evfscfuf */
1235 HELPER_SPE_VECTOR_CONV(fscfuf);
1236 /* evfscfsf */
1237 HELPER_SPE_VECTOR_CONV(fscfsf);
1238 /* evfsctsi */
1239 HELPER_SPE_VECTOR_CONV(fsctsi);
1240 /* evfsctui */
1241 HELPER_SPE_VECTOR_CONV(fsctui);
1242 /* evfsctsiz */
1243 HELPER_SPE_VECTOR_CONV(fsctsiz);
1244 /* evfsctuiz */
1245 HELPER_SPE_VECTOR_CONV(fsctuiz);
1246 /* evfsctsf */
1247 HELPER_SPE_VECTOR_CONV(fsctsf);
1248 /* evfsctuf */
1249 HELPER_SPE_VECTOR_CONV(fsctuf);
1250 
1251 /* Single-precision floating-point arithmetic */
1252 static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2)
1253 {
1254     CPU_FloatU u1, u2;
1255 
1256     u1.l = op1;
1257     u2.l = op2;
1258     u1.f = float32_add(u1.f, u2.f, &env->vec_status);
1259     return u1.l;
1260 }
1261 
1262 static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2)
1263 {
1264     CPU_FloatU u1, u2;
1265 
1266     u1.l = op1;
1267     u2.l = op2;
1268     u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
1269     return u1.l;
1270 }
1271 
1272 static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2)
1273 {
1274     CPU_FloatU u1, u2;
1275 
1276     u1.l = op1;
1277     u2.l = op2;
1278     u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
1279     return u1.l;
1280 }
1281 
1282 static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2)
1283 {
1284     CPU_FloatU u1, u2;
1285 
1286     u1.l = op1;
1287     u2.l = op2;
1288     u1.f = float32_div(u1.f, u2.f, &env->vec_status);
1289     return u1.l;
1290 }
1291 
1292 #define HELPER_SPE_SINGLE_ARITH(name)                                   \
1293     uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
1294     {                                                                   \
1295         return e##name(env, op1, op2);                                  \
1296     }
1297 /* efsadd */
1298 HELPER_SPE_SINGLE_ARITH(fsadd);
1299 /* efssub */
1300 HELPER_SPE_SINGLE_ARITH(fssub);
1301 /* efsmul */
1302 HELPER_SPE_SINGLE_ARITH(fsmul);
1303 /* efsdiv */
1304 HELPER_SPE_SINGLE_ARITH(fsdiv);
1305 
1306 #define HELPER_SPE_VECTOR_ARITH(name)                                   \
1307     uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
1308     {                                                                   \
1309         return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) |   \
1310             (uint64_t)e##name(env, op1, op2);                           \
1311     }
1312 /* evfsadd */
1313 HELPER_SPE_VECTOR_ARITH(fsadd);
1314 /* evfssub */
1315 HELPER_SPE_VECTOR_ARITH(fssub);
1316 /* evfsmul */
1317 HELPER_SPE_VECTOR_ARITH(fsmul);
1318 /* evfsdiv */
1319 HELPER_SPE_VECTOR_ARITH(fsdiv);
1320 
1321 /* Single-precision floating-point comparisons */
1322 static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1323 {
1324     CPU_FloatU u1, u2;
1325 
1326     u1.l = op1;
1327     u2.l = op2;
1328     return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
1329 }
1330 
1331 static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1332 {
1333     CPU_FloatU u1, u2;
1334 
1335     u1.l = op1;
1336     u2.l = op2;
1337     return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
1338 }
1339 
1340 static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
1341 {
1342     CPU_FloatU u1, u2;
1343 
1344     u1.l = op1;
1345     u2.l = op2;
1346     return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
1347 }
1348 
1349 static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1350 {
1351     /* XXX: TODO: ignore special values (NaN, infinites, ...) */
1352     return efscmplt(env, op1, op2);
1353 }
1354 
1355 static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1356 {
1357     /* XXX: TODO: ignore special values (NaN, infinites, ...) */
1358     return efscmpgt(env, op1, op2);
1359 }
1360 
1361 static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
1362 {
1363     /* XXX: TODO: ignore special values (NaN, infinites, ...) */
1364     return efscmpeq(env, op1, op2);
1365 }
1366 
1367 #define HELPER_SINGLE_SPE_CMP(name)                                     \
1368     uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
1369     {                                                                   \
1370         return e##name(env, op1, op2);                                  \
1371     }
1372 /* efststlt */
1373 HELPER_SINGLE_SPE_CMP(fststlt);
1374 /* efststgt */
1375 HELPER_SINGLE_SPE_CMP(fststgt);
1376 /* efststeq */
1377 HELPER_SINGLE_SPE_CMP(fststeq);
1378 /* efscmplt */
1379 HELPER_SINGLE_SPE_CMP(fscmplt);
1380 /* efscmpgt */
1381 HELPER_SINGLE_SPE_CMP(fscmpgt);
1382 /* efscmpeq */
1383 HELPER_SINGLE_SPE_CMP(fscmpeq);
1384 
1385 static inline uint32_t evcmp_merge(int t0, int t1)
1386 {
1387     return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
1388 }
1389 
1390 #define HELPER_VECTOR_SPE_CMP(name)                                     \
1391     uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
1392     {                                                                   \
1393         return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32),          \
1394                            e##name(env, op1, op2));                     \
1395     }
1396 /* evfststlt */
1397 HELPER_VECTOR_SPE_CMP(fststlt);
1398 /* evfststgt */
1399 HELPER_VECTOR_SPE_CMP(fststgt);
1400 /* evfststeq */
1401 HELPER_VECTOR_SPE_CMP(fststeq);
1402 /* evfscmplt */
1403 HELPER_VECTOR_SPE_CMP(fscmplt);
1404 /* evfscmpgt */
1405 HELPER_VECTOR_SPE_CMP(fscmpgt);
1406 /* evfscmpeq */
1407 HELPER_VECTOR_SPE_CMP(fscmpeq);
1408 
1409 /* Double-precision floating-point conversion */
1410 uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val)
1411 {
1412     CPU_DoubleU u;
1413 
1414     u.d = int32_to_float64(val, &env->vec_status);
1415 
1416     return u.ll;
1417 }
1418 
1419 uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val)
1420 {
1421     CPU_DoubleU u;
1422 
1423     u.d = int64_to_float64(val, &env->vec_status);
1424 
1425     return u.ll;
1426 }
1427 
1428 uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val)
1429 {
1430     CPU_DoubleU u;
1431 
1432     u.d = uint32_to_float64(val, &env->vec_status);
1433 
1434     return u.ll;
1435 }
1436 
1437 uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val)
1438 {
1439     CPU_DoubleU u;
1440 
1441     u.d = uint64_to_float64(val, &env->vec_status);
1442 
1443     return u.ll;
1444 }
1445 
1446 uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val)
1447 {
1448     CPU_DoubleU u;
1449 
1450     u.ll = val;
1451     /* NaN are not treated the same way IEEE 754 does */
1452     if (unlikely(float64_is_any_nan(u.d))) {
1453         return 0;
1454     }
1455 
1456     return float64_to_int32(u.d, &env->vec_status);
1457 }
1458 
1459 uint32_t helper_efdctui(CPUPPCState *env, uint64_t val)
1460 {
1461     CPU_DoubleU u;
1462 
1463     u.ll = val;
1464     /* NaN are not treated the same way IEEE 754 does */
1465     if (unlikely(float64_is_any_nan(u.d))) {
1466         return 0;
1467     }
1468 
1469     return float64_to_uint32(u.d, &env->vec_status);
1470 }
1471 
1472 uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val)
1473 {
1474     CPU_DoubleU u;
1475 
1476     u.ll = val;
1477     /* NaN are not treated the same way IEEE 754 does */
1478     if (unlikely(float64_is_any_nan(u.d))) {
1479         return 0;
1480     }
1481 
1482     return float64_to_int32_round_to_zero(u.d, &env->vec_status);
1483 }
1484 
1485 uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val)
1486 {
1487     CPU_DoubleU u;
1488 
1489     u.ll = val;
1490     /* NaN are not treated the same way IEEE 754 does */
1491     if (unlikely(float64_is_any_nan(u.d))) {
1492         return 0;
1493     }
1494 
1495     return float64_to_int64_round_to_zero(u.d, &env->vec_status);
1496 }
1497 
1498 uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val)
1499 {
1500     CPU_DoubleU u;
1501 
1502     u.ll = val;
1503     /* NaN are not treated the same way IEEE 754 does */
1504     if (unlikely(float64_is_any_nan(u.d))) {
1505         return 0;
1506     }
1507 
1508     return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
1509 }
1510 
1511 uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val)
1512 {
1513     CPU_DoubleU u;
1514 
1515     u.ll = val;
1516     /* NaN are not treated the same way IEEE 754 does */
1517     if (unlikely(float64_is_any_nan(u.d))) {
1518         return 0;
1519     }
1520 
1521     return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
1522 }
1523 
1524 uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val)
1525 {
1526     CPU_DoubleU u;
1527     float64 tmp;
1528 
1529     u.d = int32_to_float64(val, &env->vec_status);
1530     tmp = int64_to_float64(1ULL << 32, &env->vec_status);
1531     u.d = float64_div(u.d, tmp, &env->vec_status);
1532 
1533     return u.ll;
1534 }
1535 
1536 uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val)
1537 {
1538     CPU_DoubleU u;
1539     float64 tmp;
1540 
1541     u.d = uint32_to_float64(val, &env->vec_status);
1542     tmp = int64_to_float64(1ULL << 32, &env->vec_status);
1543     u.d = float64_div(u.d, tmp, &env->vec_status);
1544 
1545     return u.ll;
1546 }
1547 
1548 uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val)
1549 {
1550     CPU_DoubleU u;
1551     float64 tmp;
1552 
1553     u.ll = val;
1554     /* NaN are not treated the same way IEEE 754 does */
1555     if (unlikely(float64_is_any_nan(u.d))) {
1556         return 0;
1557     }
1558     tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
1559     u.d = float64_mul(u.d, tmp, &env->vec_status);
1560 
1561     return float64_to_int32(u.d, &env->vec_status);
1562 }
1563 
1564 uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val)
1565 {
1566     CPU_DoubleU u;
1567     float64 tmp;
1568 
1569     u.ll = val;
1570     /* NaN are not treated the same way IEEE 754 does */
1571     if (unlikely(float64_is_any_nan(u.d))) {
1572         return 0;
1573     }
1574     tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
1575     u.d = float64_mul(u.d, tmp, &env->vec_status);
1576 
1577     return float64_to_uint32(u.d, &env->vec_status);
1578 }
1579 
1580 uint32_t helper_efscfd(CPUPPCState *env, uint64_t val)
1581 {
1582     CPU_DoubleU u1;
1583     CPU_FloatU u2;
1584 
1585     u1.ll = val;
1586     u2.f = float64_to_float32(u1.d, &env->vec_status);
1587 
1588     return u2.l;
1589 }
1590 
1591 uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val)
1592 {
1593     CPU_DoubleU u2;
1594     CPU_FloatU u1;
1595 
1596     u1.l = val;
1597     u2.d = float32_to_float64(u1.f, &env->vec_status);
1598 
1599     return u2.ll;
1600 }
1601 
1602 /* Double precision fixed-point arithmetic */
1603 uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2)
1604 {
1605     CPU_DoubleU u1, u2;
1606 
1607     u1.ll = op1;
1608     u2.ll = op2;
1609     u1.d = float64_add(u1.d, u2.d, &env->vec_status);
1610     return u1.ll;
1611 }
1612 
1613 uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2)
1614 {
1615     CPU_DoubleU u1, u2;
1616 
1617     u1.ll = op1;
1618     u2.ll = op2;
1619     u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
1620     return u1.ll;
1621 }
1622 
1623 uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2)
1624 {
1625     CPU_DoubleU u1, u2;
1626 
1627     u1.ll = op1;
1628     u2.ll = op2;
1629     u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
1630     return u1.ll;
1631 }
1632 
1633 uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2)
1634 {
1635     CPU_DoubleU u1, u2;
1636 
1637     u1.ll = op1;
1638     u2.ll = op2;
1639     u1.d = float64_div(u1.d, u2.d, &env->vec_status);
1640     return u1.ll;
1641 }
1642 
1643 /* Double precision floating point helpers */
1644 uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1645 {
1646     CPU_DoubleU u1, u2;
1647 
1648     u1.ll = op1;
1649     u2.ll = op2;
1650     return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
1651 }
1652 
1653 uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1654 {
1655     CPU_DoubleU u1, u2;
1656 
1657     u1.ll = op1;
1658     u2.ll = op2;
1659     return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
1660 }
1661 
1662 uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2)
1663 {
1664     CPU_DoubleU u1, u2;
1665 
1666     u1.ll = op1;
1667     u2.ll = op2;
1668     return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
1669 }
1670 
1671 uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1672 {
1673     /* XXX: TODO: test special values (NaN, infinites, ...) */
1674     return helper_efdtstlt(env, op1, op2);
1675 }
1676 
1677 uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1678 {
1679     /* XXX: TODO: test special values (NaN, infinites, ...) */
1680     return helper_efdtstgt(env, op1, op2);
1681 }
1682 
1683 uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
1684 {
1685     /* XXX: TODO: test special values (NaN, infinites, ...) */
1686     return helper_efdtsteq(env, op1, op2);
1687 }
1688 
1689 #define float64_to_float64(x, env) x
1690 
1691 
1692 /*
1693  * VSX_ADD_SUB - VSX floating point add/subtract
1694  *   name  - instruction mnemonic
1695  *   op    - operation (add or sub)
1696  *   nels  - number of elements (1, 2 or 4)
1697  *   tp    - type (float32 or float64)
1698  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
1699  *   sfifprf - set FI and FPRF
1700  */
1701 #define VSX_ADD_SUB(name, op, nels, tp, fld, sfifprf, r2sp)                  \
1702 void helper_##name(CPUPPCState *env, ppc_vsr_t *xt,                          \
1703                    ppc_vsr_t *xa, ppc_vsr_t *xb)                             \
1704 {                                                                            \
1705     ppc_vsr_t t = { };                                                       \
1706     int i;                                                                   \
1707                                                                              \
1708     helper_reset_fpstatus(env);                                              \
1709                                                                              \
1710     for (i = 0; i < nels; i++) {                                             \
1711         float_status tstat = env->fp_status;                                 \
1712         set_float_exception_flags(0, &tstat);                                \
1713         t.fld = tp##_##op(xa->fld, xb->fld, &tstat);                         \
1714         env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1715                                                                              \
1716         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
1717             float_invalid_op_addsub(env, tstat.float_exception_flags,        \
1718                                     sfifprf, GETPC());                       \
1719         }                                                                    \
1720                                                                              \
1721         if (r2sp) {                                                          \
1722             t.fld = do_frsp(env, t.fld, GETPC());                            \
1723         }                                                                    \
1724                                                                              \
1725         if (sfifprf) {                                                       \
1726             helper_compute_fprf_float64(env, t.fld);                         \
1727         }                                                                    \
1728     }                                                                        \
1729     *xt = t;                                                                 \
1730     do_float_check_status(env, sfifprf, GETPC());                            \
1731 }
1732 
1733 VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
1734 VSX_ADD_SUB(xsaddsp, add, 1, float64, VsrD(0), 1, 1)
1735 VSX_ADD_SUB(xvadddp, add, 2, float64, VsrD(i), 0, 0)
1736 VSX_ADD_SUB(xvaddsp, add, 4, float32, VsrW(i), 0, 0)
1737 VSX_ADD_SUB(xssubdp, sub, 1, float64, VsrD(0), 1, 0)
1738 VSX_ADD_SUB(xssubsp, sub, 1, float64, VsrD(0), 1, 1)
1739 VSX_ADD_SUB(xvsubdp, sub, 2, float64, VsrD(i), 0, 0)
1740 VSX_ADD_SUB(xvsubsp, sub, 4, float32, VsrW(i), 0, 0)
1741 
1742 void helper_xsaddqp(CPUPPCState *env, uint32_t opcode,
1743                     ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
1744 {
1745     ppc_vsr_t t = *xt;
1746     float_status tstat;
1747 
1748     helper_reset_fpstatus(env);
1749 
1750     tstat = env->fp_status;
1751     if (unlikely(Rc(opcode) != 0)) {
1752         tstat.float_rounding_mode = float_round_to_odd;
1753     }
1754 
1755     set_float_exception_flags(0, &tstat);
1756     t.f128 = float128_add(xa->f128, xb->f128, &tstat);
1757     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
1758 
1759     if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
1760         float_invalid_op_addsub(env, tstat.float_exception_flags, 1, GETPC());
1761     }
1762 
1763     helper_compute_fprf_float128(env, t.f128);
1764 
1765     *xt = t;
1766     do_float_check_status(env, true, GETPC());
1767 }
1768 
1769 /*
1770  * VSX_MUL - VSX floating point multiply
1771  *   op    - instruction mnemonic
1772  *   nels  - number of elements (1, 2 or 4)
1773  *   tp    - type (float32 or float64)
1774  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
1775  *   sfifprf - set FI and FPRF
1776  */
1777 #define VSX_MUL(op, nels, tp, fld, sfifprf, r2sp)                            \
1778 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt,                            \
1779                  ppc_vsr_t *xa, ppc_vsr_t *xb)                               \
1780 {                                                                            \
1781     ppc_vsr_t t = { };                                                       \
1782     int i;                                                                   \
1783                                                                              \
1784     helper_reset_fpstatus(env);                                              \
1785                                                                              \
1786     for (i = 0; i < nels; i++) {                                             \
1787         float_status tstat = env->fp_status;                                 \
1788         set_float_exception_flags(0, &tstat);                                \
1789         t.fld = tp##_mul(xa->fld, xb->fld, &tstat);                          \
1790         env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1791                                                                              \
1792         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
1793             float_invalid_op_mul(env, tstat.float_exception_flags,           \
1794                                  sfifprf, GETPC());                          \
1795         }                                                                    \
1796                                                                              \
1797         if (r2sp) {                                                          \
1798             t.fld = do_frsp(env, t.fld, GETPC());                            \
1799         }                                                                    \
1800                                                                              \
1801         if (sfifprf) {                                                       \
1802             helper_compute_fprf_float64(env, t.fld);                         \
1803         }                                                                    \
1804     }                                                                        \
1805                                                                              \
1806     *xt = t;                                                                 \
1807     do_float_check_status(env, sfifprf, GETPC());                            \
1808 }
1809 
1810 VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
1811 VSX_MUL(xsmulsp, 1, float64, VsrD(0), 1, 1)
1812 VSX_MUL(xvmuldp, 2, float64, VsrD(i), 0, 0)
1813 VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0)
1814 
1815 void helper_xsmulqp(CPUPPCState *env, uint32_t opcode,
1816                     ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
1817 {
1818     ppc_vsr_t t = *xt;
1819     float_status tstat;
1820 
1821     helper_reset_fpstatus(env);
1822     tstat = env->fp_status;
1823     if (unlikely(Rc(opcode) != 0)) {
1824         tstat.float_rounding_mode = float_round_to_odd;
1825     }
1826 
1827     set_float_exception_flags(0, &tstat);
1828     t.f128 = float128_mul(xa->f128, xb->f128, &tstat);
1829     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
1830 
1831     if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
1832         float_invalid_op_mul(env, tstat.float_exception_flags, 1, GETPC());
1833     }
1834     helper_compute_fprf_float128(env, t.f128);
1835 
1836     *xt = t;
1837     do_float_check_status(env, true, GETPC());
1838 }
1839 
1840 /*
1841  * VSX_DIV - VSX floating point divide
1842  *   op    - instruction mnemonic
1843  *   nels  - number of elements (1, 2 or 4)
1844  *   tp    - type (float32 or float64)
1845  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
1846  *   sfifprf - set FI and FPRF
1847  */
1848 #define VSX_DIV(op, nels, tp, fld, sfifprf, r2sp)                             \
1849 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt,                             \
1850                  ppc_vsr_t *xa, ppc_vsr_t *xb)                                \
1851 {                                                                             \
1852     ppc_vsr_t t = { };                                                        \
1853     int i;                                                                    \
1854                                                                               \
1855     helper_reset_fpstatus(env);                                               \
1856                                                                               \
1857     for (i = 0; i < nels; i++) {                                              \
1858         float_status tstat = env->fp_status;                                  \
1859         set_float_exception_flags(0, &tstat);                                 \
1860         t.fld = tp##_div(xa->fld, xb->fld, &tstat);                           \
1861         env->fp_status.float_exception_flags |= tstat.float_exception_flags;  \
1862                                                                               \
1863         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {     \
1864             float_invalid_op_div(env, tstat.float_exception_flags,            \
1865                                  sfifprf, GETPC());                           \
1866         }                                                                     \
1867         if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) {   \
1868             float_zero_divide_excp(env, GETPC());                             \
1869         }                                                                     \
1870                                                                               \
1871         if (r2sp) {                                                           \
1872             t.fld = do_frsp(env, t.fld, GETPC());                             \
1873         }                                                                     \
1874                                                                               \
1875         if (sfifprf) {                                                        \
1876             helper_compute_fprf_float64(env, t.fld);                          \
1877         }                                                                     \
1878     }                                                                         \
1879                                                                               \
1880     *xt = t;                                                                  \
1881     do_float_check_status(env, sfifprf, GETPC());                             \
1882 }
1883 
1884 VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
1885 VSX_DIV(xsdivsp, 1, float64, VsrD(0), 1, 1)
1886 VSX_DIV(xvdivdp, 2, float64, VsrD(i), 0, 0)
1887 VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0)
1888 
1889 void helper_xsdivqp(CPUPPCState *env, uint32_t opcode,
1890                     ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
1891 {
1892     ppc_vsr_t t = *xt;
1893     float_status tstat;
1894 
1895     helper_reset_fpstatus(env);
1896     tstat = env->fp_status;
1897     if (unlikely(Rc(opcode) != 0)) {
1898         tstat.float_rounding_mode = float_round_to_odd;
1899     }
1900 
1901     set_float_exception_flags(0, &tstat);
1902     t.f128 = float128_div(xa->f128, xb->f128, &tstat);
1903     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
1904 
1905     if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
1906         float_invalid_op_div(env, tstat.float_exception_flags, 1, GETPC());
1907     }
1908     if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) {
1909         float_zero_divide_excp(env, GETPC());
1910     }
1911 
1912     helper_compute_fprf_float128(env, t.f128);
1913     *xt = t;
1914     do_float_check_status(env, true, GETPC());
1915 }
1916 
1917 /*
1918  * VSX_RE  - VSX floating point reciprocal estimate
1919  *   op    - instruction mnemonic
1920  *   nels  - number of elements (1, 2 or 4)
1921  *   tp    - type (float32 or float64)
1922  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
1923  *   sfifprf - set FI and FPRF
1924  */
1925 #define VSX_RE(op, nels, tp, fld, sfifprf, r2sp)                              \
1926 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)              \
1927 {                                                                             \
1928     ppc_vsr_t t = { };                                                        \
1929     int i;                                                                    \
1930                                                                               \
1931     helper_reset_fpstatus(env);                                               \
1932                                                                               \
1933     for (i = 0; i < nels; i++) {                                              \
1934         if (unlikely(tp##_is_signaling_nan(xb->fld, &env->fp_status))) {      \
1935             float_invalid_op_vxsnan(env, GETPC());                            \
1936         }                                                                     \
1937         t.fld = tp##_div(tp##_one, xb->fld, &env->fp_status);                 \
1938                                                                               \
1939         if (r2sp) {                                                           \
1940             t.fld = do_frsp(env, t.fld, GETPC());                             \
1941         }                                                                     \
1942                                                                               \
1943         if (sfifprf) {                                                        \
1944             helper_compute_fprf_float64(env, t.fld);                          \
1945         }                                                                     \
1946     }                                                                         \
1947                                                                               \
1948     *xt = t;                                                                  \
1949     do_float_check_status(env, sfifprf, GETPC());                             \
1950 }
1951 
1952 VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
1953 VSX_RE(xsresp, 1, float64, VsrD(0), 1, 1)
1954 VSX_RE(xvredp, 2, float64, VsrD(i), 0, 0)
1955 VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0)
1956 
1957 /*
1958  * VSX_SQRT - VSX floating point square root
1959  *   op    - instruction mnemonic
1960  *   nels  - number of elements (1, 2 or 4)
1961  *   tp    - type (float32 or float64)
1962  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
1963  *   sfifprf - set FI and FPRF
1964  */
1965 #define VSX_SQRT(op, nels, tp, fld, sfifprf, r2sp)                           \
1966 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)             \
1967 {                                                                            \
1968     ppc_vsr_t t = { };                                                       \
1969     int i;                                                                   \
1970                                                                              \
1971     helper_reset_fpstatus(env);                                              \
1972                                                                              \
1973     for (i = 0; i < nels; i++) {                                             \
1974         float_status tstat = env->fp_status;                                 \
1975         set_float_exception_flags(0, &tstat);                                \
1976         t.fld = tp##_sqrt(xb->fld, &tstat);                                  \
1977         env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1978                                                                              \
1979         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
1980             float_invalid_op_sqrt(env, tstat.float_exception_flags,          \
1981                                   sfifprf, GETPC());                         \
1982         }                                                                    \
1983                                                                              \
1984         if (r2sp) {                                                          \
1985             t.fld = do_frsp(env, t.fld, GETPC());                            \
1986         }                                                                    \
1987                                                                              \
1988         if (sfifprf) {                                                       \
1989             helper_compute_fprf_float64(env, t.fld);                         \
1990         }                                                                    \
1991     }                                                                        \
1992                                                                              \
1993     *xt = t;                                                                 \
1994     do_float_check_status(env, sfifprf, GETPC());                            \
1995 }
1996 
1997 VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
1998 VSX_SQRT(xssqrtsp, 1, float64, VsrD(0), 1, 1)
1999 VSX_SQRT(xvsqrtdp, 2, float64, VsrD(i), 0, 0)
2000 VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0)
2001 
2002 /*
2003  *VSX_RSQRTE - VSX floating point reciprocal square root estimate
2004  *   op    - instruction mnemonic
2005  *   nels  - number of elements (1, 2 or 4)
2006  *   tp    - type (float32 or float64)
2007  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
2008  *   sfifprf - set FI and FPRF
2009  */
2010 #define VSX_RSQRTE(op, nels, tp, fld, sfifprf, r2sp)                         \
2011 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)             \
2012 {                                                                            \
2013     ppc_vsr_t t = { };                                                       \
2014     int i;                                                                   \
2015                                                                              \
2016     helper_reset_fpstatus(env);                                              \
2017                                                                              \
2018     for (i = 0; i < nels; i++) {                                             \
2019         float_status tstat = env->fp_status;                                 \
2020         set_float_exception_flags(0, &tstat);                                \
2021         t.fld = tp##_sqrt(xb->fld, &tstat);                                  \
2022         t.fld = tp##_div(tp##_one, t.fld, &tstat);                           \
2023         env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
2024         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
2025             float_invalid_op_sqrt(env, tstat.float_exception_flags,          \
2026                                   sfifprf, GETPC());                         \
2027         }                                                                    \
2028         if (r2sp) {                                                          \
2029             t.fld = do_frsp(env, t.fld, GETPC());                            \
2030         }                                                                    \
2031                                                                              \
2032         if (sfifprf) {                                                       \
2033             helper_compute_fprf_float64(env, t.fld);                         \
2034         }                                                                    \
2035     }                                                                        \
2036                                                                              \
2037     *xt = t;                                                                 \
2038     do_float_check_status(env, sfifprf, GETPC());                            \
2039 }
2040 
2041 VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
2042 VSX_RSQRTE(xsrsqrtesp, 1, float64, VsrD(0), 1, 1)
2043 VSX_RSQRTE(xvrsqrtedp, 2, float64, VsrD(i), 0, 0)
2044 VSX_RSQRTE(xvrsqrtesp, 4, float32, VsrW(i), 0, 0)
2045 
2046 /*
2047  * VSX_TDIV - VSX floating point test for divide
2048  *   op    - instruction mnemonic
2049  *   nels  - number of elements (1, 2 or 4)
2050  *   tp    - type (float32 or float64)
2051  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
2052  *   emin  - minimum unbiased exponent
2053  *   emax  - maximum unbiased exponent
2054  *   nbits - number of fraction bits
2055  */
2056 #define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits)                  \
2057 void helper_##op(CPUPPCState *env, uint32_t opcode,                     \
2058                  ppc_vsr_t *xa, ppc_vsr_t *xb)                          \
2059 {                                                                       \
2060     int i;                                                              \
2061     int fe_flag = 0;                                                    \
2062     int fg_flag = 0;                                                    \
2063                                                                         \
2064     for (i = 0; i < nels; i++) {                                        \
2065         if (unlikely(tp##_is_infinity(xa->fld) ||                       \
2066                      tp##_is_infinity(xb->fld) ||                       \
2067                      tp##_is_zero(xb->fld))) {                          \
2068             fe_flag = 1;                                                \
2069             fg_flag = 1;                                                \
2070         } else {                                                        \
2071             int e_a = ppc_##tp##_get_unbiased_exp(xa->fld);             \
2072             int e_b = ppc_##tp##_get_unbiased_exp(xb->fld);             \
2073                                                                         \
2074             if (unlikely(tp##_is_any_nan(xa->fld) ||                    \
2075                          tp##_is_any_nan(xb->fld))) {                   \
2076                 fe_flag = 1;                                            \
2077             } else if ((e_b <= emin) || (e_b >= (emax - 2))) {          \
2078                 fe_flag = 1;                                            \
2079             } else if (!tp##_is_zero(xa->fld) &&                        \
2080                        (((e_a - e_b) >= emax) ||                        \
2081                         ((e_a - e_b) <= (emin + 1)) ||                  \
2082                         (e_a <= (emin + nbits)))) {                     \
2083                 fe_flag = 1;                                            \
2084             }                                                           \
2085                                                                         \
2086             if (unlikely(tp##_is_zero_or_denormal(xb->fld))) {          \
2087                 /*                                                      \
2088                  * XB is not zero because of the above check and so     \
2089                  * must be denormalized.                                \
2090                  */                                                     \
2091                 fg_flag = 1;                                            \
2092             }                                                           \
2093         }                                                               \
2094     }                                                                   \
2095                                                                         \
2096     env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
2097 }
2098 
2099 VSX_TDIV(xstdivdp, 1, float64, VsrD(0), -1022, 1023, 52)
2100 VSX_TDIV(xvtdivdp, 2, float64, VsrD(i), -1022, 1023, 52)
2101 VSX_TDIV(xvtdivsp, 4, float32, VsrW(i), -126, 127, 23)
2102 
2103 /*
2104  * VSX_TSQRT - VSX floating point test for square root
2105  *   op    - instruction mnemonic
2106  *   nels  - number of elements (1, 2 or 4)
2107  *   tp    - type (float32 or float64)
2108  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
2109  *   emin  - minimum unbiased exponent
2110  *   emax  - maximum unbiased exponent
2111  *   nbits - number of fraction bits
2112  */
2113 #define VSX_TSQRT(op, nels, tp, fld, emin, nbits)                       \
2114 void helper_##op(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb)      \
2115 {                                                                       \
2116     int i;                                                              \
2117     int fe_flag = 0;                                                    \
2118     int fg_flag = 0;                                                    \
2119                                                                         \
2120     for (i = 0; i < nels; i++) {                                        \
2121         if (unlikely(tp##_is_infinity(xb->fld) ||                       \
2122                      tp##_is_zero(xb->fld))) {                          \
2123             fe_flag = 1;                                                \
2124             fg_flag = 1;                                                \
2125         } else {                                                        \
2126             int e_b = ppc_##tp##_get_unbiased_exp(xb->fld);             \
2127                                                                         \
2128             if (unlikely(tp##_is_any_nan(xb->fld))) {                   \
2129                 fe_flag = 1;                                            \
2130             } else if (unlikely(tp##_is_zero(xb->fld))) {               \
2131                 fe_flag = 1;                                            \
2132             } else if (unlikely(tp##_is_neg(xb->fld))) {                \
2133                 fe_flag = 1;                                            \
2134             } else if (!tp##_is_zero(xb->fld) &&                        \
2135                        (e_b <= (emin + nbits))) {                       \
2136                 fe_flag = 1;                                            \
2137             }                                                           \
2138                                                                         \
2139             if (unlikely(tp##_is_zero_or_denormal(xb->fld))) {          \
2140                 /*                                                      \
2141                  * XB is not zero because of the above check and        \
2142                  * therefore must be denormalized.                      \
2143                  */                                                     \
2144                 fg_flag = 1;                                            \
2145             }                                                           \
2146         }                                                               \
2147     }                                                                   \
2148                                                                         \
2149     env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
2150 }
2151 
2152 VSX_TSQRT(xstsqrtdp, 1, float64, VsrD(0), -1022, 52)
2153 VSX_TSQRT(xvtsqrtdp, 2, float64, VsrD(i), -1022, 52)
2154 VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23)
2155 
2156 /*
2157  * VSX_MADD - VSX floating point muliply/add variations
2158  *   op    - instruction mnemonic
2159  *   nels  - number of elements (1, 2 or 4)
2160  *   tp    - type (float32 or float64)
2161  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
2162  *   maddflgs - flags for the float*muladd routine that control the
2163  *           various forms (madd, msub, nmadd, nmsub)
2164  *   sfifprf - set FI and FPRF
2165  */
2166 #define VSX_MADD(op, nels, tp, fld, maddflgs, sfifprf)                        \
2167 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt,                             \
2168                  ppc_vsr_t *s1, ppc_vsr_t *s2, ppc_vsr_t *s3)                 \
2169 {                                                                             \
2170     ppc_vsr_t t = { };                                                        \
2171     int i;                                                                    \
2172                                                                               \
2173     helper_reset_fpstatus(env);                                               \
2174                                                                               \
2175     for (i = 0; i < nels; i++) {                                              \
2176         float_status tstat = env->fp_status;                                  \
2177         set_float_exception_flags(0, &tstat);                                 \
2178         t.fld = tp##_muladd(s1->fld, s3->fld, s2->fld, maddflgs, &tstat);     \
2179         env->fp_status.float_exception_flags |= tstat.float_exception_flags;  \
2180                                                                               \
2181         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {     \
2182             float_invalid_op_madd(env, tstat.float_exception_flags,           \
2183                                   sfifprf, GETPC());                          \
2184         }                                                                     \
2185                                                                               \
2186         if (sfifprf) {                                                        \
2187             helper_compute_fprf_float64(env, t.fld);                          \
2188         }                                                                     \
2189     }                                                                         \
2190     *xt = t;                                                                  \
2191     do_float_check_status(env, sfifprf, GETPC());                             \
2192 }
2193 
2194 VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1)
2195 VSX_MADD(XSMSUBDP, 1, float64, VsrD(0), MSUB_FLGS, 1)
2196 VSX_MADD(XSNMADDDP, 1, float64, VsrD(0), NMADD_FLGS, 1)
2197 VSX_MADD(XSNMSUBDP, 1, float64, VsrD(0), NMSUB_FLGS, 1)
2198 VSX_MADD(XSMADDSP, 1, float64r32, VsrD(0), MADD_FLGS, 1)
2199 VSX_MADD(XSMSUBSP, 1, float64r32, VsrD(0), MSUB_FLGS, 1)
2200 VSX_MADD(XSNMADDSP, 1, float64r32, VsrD(0), NMADD_FLGS, 1)
2201 VSX_MADD(XSNMSUBSP, 1, float64r32, VsrD(0), NMSUB_FLGS, 1)
2202 
2203 VSX_MADD(xvmadddp, 2, float64, VsrD(i), MADD_FLGS, 0)
2204 VSX_MADD(xvmsubdp, 2, float64, VsrD(i), MSUB_FLGS, 0)
2205 VSX_MADD(xvnmadddp, 2, float64, VsrD(i), NMADD_FLGS, 0)
2206 VSX_MADD(xvnmsubdp, 2, float64, VsrD(i), NMSUB_FLGS, 0)
2207 
2208 VSX_MADD(xvmaddsp, 4, float32, VsrW(i), MADD_FLGS, 0)
2209 VSX_MADD(xvmsubsp, 4, float32, VsrW(i), MSUB_FLGS, 0)
2210 VSX_MADD(xvnmaddsp, 4, float32, VsrW(i), NMADD_FLGS, 0)
2211 VSX_MADD(xvnmsubsp, 4, float32, VsrW(i), NMSUB_FLGS, 0)
2212 
2213 /*
2214  * VSX_MADDQ - VSX floating point quad-precision muliply/add
2215  *   op    - instruction mnemonic
2216  *   maddflgs - flags for the float*muladd routine that control the
2217  *           various forms (madd, msub, nmadd, nmsub)
2218  *   ro    - round to odd
2219  */
2220 #define VSX_MADDQ(op, maddflgs, ro)                                            \
2221 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *s1, ppc_vsr_t *s2,\
2222                  ppc_vsr_t *s3)                                                \
2223 {                                                                              \
2224     ppc_vsr_t t = *xt;                                                         \
2225                                                                                \
2226     helper_reset_fpstatus(env);                                                \
2227                                                                                \
2228     float_status tstat = env->fp_status;                                       \
2229     set_float_exception_flags(0, &tstat);                                      \
2230     if (ro) {                                                                  \
2231         tstat.float_rounding_mode = float_round_to_odd;                        \
2232     }                                                                          \
2233     t.f128 = float128_muladd(s1->f128, s3->f128, s2->f128, maddflgs, &tstat);  \
2234     env->fp_status.float_exception_flags |= tstat.float_exception_flags;       \
2235                                                                                \
2236     if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {          \
2237         float_invalid_op_madd(env, tstat.float_exception_flags,                \
2238                               false, GETPC());                                 \
2239     }                                                                          \
2240                                                                                \
2241     helper_compute_fprf_float128(env, t.f128);                                 \
2242     *xt = t;                                                                   \
2243     do_float_check_status(env, true, GETPC());                                 \
2244 }
2245 
2246 VSX_MADDQ(XSMADDQP, MADD_FLGS, 0)
2247 VSX_MADDQ(XSMADDQPO, MADD_FLGS, 1)
2248 VSX_MADDQ(XSMSUBQP, MSUB_FLGS, 0)
2249 VSX_MADDQ(XSMSUBQPO, MSUB_FLGS, 1)
2250 VSX_MADDQ(XSNMADDQP, NMADD_FLGS, 0)
2251 VSX_MADDQ(XSNMADDQPO, NMADD_FLGS, 1)
2252 VSX_MADDQ(XSNMSUBQP, NMSUB_FLGS, 0)
2253 VSX_MADDQ(XSNMSUBQPO, NMSUB_FLGS, 0)
2254 
2255 /*
2256  * VSX_SCALAR_CMP - VSX scalar floating point compare
2257  *   op    - instruction mnemonic
2258  *   tp    - type
2259  *   cmp   - comparison operation
2260  *   fld   - vsr_t field
2261  *   svxvc - set VXVC bit
2262  */
2263 #define VSX_SCALAR_CMP(op, tp, cmp, fld, svxvc)                               \
2264         void helper_##op(CPUPPCState *env, ppc_vsr_t *xt,                     \
2265                 ppc_vsr_t *xa, ppc_vsr_t *xb)                                 \
2266 {                                                                             \
2267     int flags;                                                                \
2268     bool r, vxvc;                                                             \
2269                                                                               \
2270     helper_reset_fpstatus(env);                                               \
2271                                                                               \
2272     if (svxvc) {                                                              \
2273         r = tp##_##cmp(xb->fld, xa->fld, &env->fp_status);                    \
2274     } else {                                                                  \
2275         r = tp##_##cmp##_quiet(xb->fld, xa->fld, &env->fp_status);            \
2276     }                                                                         \
2277                                                                               \
2278     flags = get_float_exception_flags(&env->fp_status);                       \
2279     if (unlikely(flags & float_flag_invalid)) {                               \
2280         vxvc = svxvc;                                                         \
2281         if (flags & float_flag_invalid_snan) {                                \
2282             float_invalid_op_vxsnan(env, GETPC());                            \
2283             vxvc &= !(env->fpscr & FP_VE);                                    \
2284         }                                                                     \
2285         if (vxvc) {                                                           \
2286             float_invalid_op_vxvc(env, 0, GETPC());                           \
2287         }                                                                     \
2288     }                                                                         \
2289                                                                               \
2290     memset(xt, 0, sizeof(*xt));                                               \
2291     memset(&xt->fld, -r, sizeof(xt->fld));                                    \
2292     do_float_check_status(env, false, GETPC());                               \
2293 }
2294 
2295 VSX_SCALAR_CMP(XSCMPEQDP, float64, eq, VsrD(0), 0)
2296 VSX_SCALAR_CMP(XSCMPGEDP, float64, le, VsrD(0), 1)
2297 VSX_SCALAR_CMP(XSCMPGTDP, float64, lt, VsrD(0), 1)
2298 VSX_SCALAR_CMP(XSCMPEQQP, float128, eq, f128, 0)
2299 VSX_SCALAR_CMP(XSCMPGEQP, float128, le, f128, 1)
2300 VSX_SCALAR_CMP(XSCMPGTQP, float128, lt, f128, 1)
2301 
2302 void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode,
2303                        ppc_vsr_t *xa, ppc_vsr_t *xb)
2304 {
2305     int64_t exp_a, exp_b;
2306     uint32_t cc;
2307 
2308     exp_a = extract64(xa->VsrD(0), 52, 11);
2309     exp_b = extract64(xb->VsrD(0), 52, 11);
2310 
2311     if (unlikely(float64_is_any_nan(xa->VsrD(0)) ||
2312                  float64_is_any_nan(xb->VsrD(0)))) {
2313         cc = CRF_SO;
2314     } else {
2315         if (exp_a < exp_b) {
2316             cc = CRF_LT;
2317         } else if (exp_a > exp_b) {
2318             cc = CRF_GT;
2319         } else {
2320             cc = CRF_EQ;
2321         }
2322     }
2323 
2324     env->fpscr &= ~FP_FPCC;
2325     env->fpscr |= cc << FPSCR_FPCC;
2326     env->crf[BF(opcode)] = cc;
2327 
2328     do_float_check_status(env, false, GETPC());
2329 }
2330 
2331 void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode,
2332                        ppc_vsr_t *xa, ppc_vsr_t *xb)
2333 {
2334     int64_t exp_a, exp_b;
2335     uint32_t cc;
2336 
2337     exp_a = extract64(xa->VsrD(0), 48, 15);
2338     exp_b = extract64(xb->VsrD(0), 48, 15);
2339 
2340     if (unlikely(float128_is_any_nan(xa->f128) ||
2341                  float128_is_any_nan(xb->f128))) {
2342         cc = CRF_SO;
2343     } else {
2344         if (exp_a < exp_b) {
2345             cc = CRF_LT;
2346         } else if (exp_a > exp_b) {
2347             cc = CRF_GT;
2348         } else {
2349             cc = CRF_EQ;
2350         }
2351     }
2352 
2353     env->fpscr &= ~FP_FPCC;
2354     env->fpscr |= cc << FPSCR_FPCC;
2355     env->crf[BF(opcode)] = cc;
2356 
2357     do_float_check_status(env, false, GETPC());
2358 }
2359 
2360 static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb,
2361                                  int crf_idx, bool ordered)
2362 {
2363     uint32_t cc;
2364     bool vxsnan_flag = false, vxvc_flag = false;
2365 
2366     helper_reset_fpstatus(env);
2367 
2368     switch (float64_compare(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) {
2369     case float_relation_less:
2370         cc = CRF_LT;
2371         break;
2372     case float_relation_equal:
2373         cc = CRF_EQ;
2374         break;
2375     case float_relation_greater:
2376         cc = CRF_GT;
2377         break;
2378     case float_relation_unordered:
2379         cc = CRF_SO;
2380 
2381         if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) ||
2382             float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) {
2383             vxsnan_flag = true;
2384             if (!(env->fpscr & FP_VE) && ordered) {
2385                 vxvc_flag = true;
2386             }
2387         } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) ||
2388                    float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) {
2389             if (ordered) {
2390                 vxvc_flag = true;
2391             }
2392         }
2393 
2394         break;
2395     default:
2396         g_assert_not_reached();
2397     }
2398 
2399     env->fpscr &= ~FP_FPCC;
2400     env->fpscr |= cc << FPSCR_FPCC;
2401     env->crf[crf_idx] = cc;
2402 
2403     if (vxsnan_flag) {
2404         float_invalid_op_vxsnan(env, GETPC());
2405     }
2406     if (vxvc_flag) {
2407         float_invalid_op_vxvc(env, 0, GETPC());
2408     }
2409 
2410     do_float_check_status(env, false, GETPC());
2411 }
2412 
2413 void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2414                      ppc_vsr_t *xb)
2415 {
2416     do_scalar_cmp(env, xa, xb, BF(opcode), true);
2417 }
2418 
2419 void helper_xscmpudp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2420                      ppc_vsr_t *xb)
2421 {
2422     do_scalar_cmp(env, xa, xb, BF(opcode), false);
2423 }
2424 
2425 static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa,
2426                                   ppc_vsr_t *xb, int crf_idx, bool ordered)
2427 {
2428     uint32_t cc;
2429     bool vxsnan_flag = false, vxvc_flag = false;
2430 
2431     helper_reset_fpstatus(env);
2432 
2433     switch (float128_compare(xa->f128, xb->f128, &env->fp_status)) {
2434     case float_relation_less:
2435         cc = CRF_LT;
2436         break;
2437     case float_relation_equal:
2438         cc = CRF_EQ;
2439         break;
2440     case float_relation_greater:
2441         cc = CRF_GT;
2442         break;
2443     case float_relation_unordered:
2444         cc = CRF_SO;
2445 
2446         if (float128_is_signaling_nan(xa->f128, &env->fp_status) ||
2447             float128_is_signaling_nan(xb->f128, &env->fp_status)) {
2448             vxsnan_flag = true;
2449             if (!(env->fpscr & FP_VE) && ordered) {
2450                 vxvc_flag = true;
2451             }
2452         } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) ||
2453                    float128_is_quiet_nan(xb->f128, &env->fp_status)) {
2454             if (ordered) {
2455                 vxvc_flag = true;
2456             }
2457         }
2458 
2459         break;
2460     default:
2461         g_assert_not_reached();
2462     }
2463 
2464     env->fpscr &= ~FP_FPCC;
2465     env->fpscr |= cc << FPSCR_FPCC;
2466     env->crf[crf_idx] = cc;
2467 
2468     if (vxsnan_flag) {
2469         float_invalid_op_vxsnan(env, GETPC());
2470     }
2471     if (vxvc_flag) {
2472         float_invalid_op_vxvc(env, 0, GETPC());
2473     }
2474 
2475     do_float_check_status(env, false, GETPC());
2476 }
2477 
2478 void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2479                      ppc_vsr_t *xb)
2480 {
2481     do_scalar_cmpq(env, xa, xb, BF(opcode), true);
2482 }
2483 
2484 void helper_xscmpuqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2485                      ppc_vsr_t *xb)
2486 {
2487     do_scalar_cmpq(env, xa, xb, BF(opcode), false);
2488 }
2489 
2490 /*
2491  * VSX_MAX_MIN - VSX floating point maximum/minimum
2492  *   name  - instruction mnemonic
2493  *   op    - operation (max or min)
2494  *   nels  - number of elements (1, 2 or 4)
2495  *   tp    - type (float32 or float64)
2496  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
2497  */
2498 #define VSX_MAX_MIN(name, op, nels, tp, fld)                                  \
2499 void helper_##name(CPUPPCState *env, ppc_vsr_t *xt,                           \
2500                    ppc_vsr_t *xa, ppc_vsr_t *xb)                              \
2501 {                                                                             \
2502     ppc_vsr_t t = { };                                                        \
2503     int i;                                                                    \
2504                                                                               \
2505     for (i = 0; i < nels; i++) {                                              \
2506         t.fld = tp##_##op(xa->fld, xb->fld, &env->fp_status);                 \
2507         if (unlikely(tp##_is_signaling_nan(xa->fld, &env->fp_status) ||       \
2508                      tp##_is_signaling_nan(xb->fld, &env->fp_status))) {      \
2509             float_invalid_op_vxsnan(env, GETPC());                            \
2510         }                                                                     \
2511     }                                                                         \
2512                                                                               \
2513     *xt = t;                                                                  \
2514     do_float_check_status(env, false, GETPC());                               \
2515 }
2516 
2517 VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
2518 VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, VsrD(i))
2519 VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, VsrW(i))
2520 VSX_MAX_MIN(xsmindp, minnum, 1, float64, VsrD(0))
2521 VSX_MAX_MIN(xvmindp, minnum, 2, float64, VsrD(i))
2522 VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i))
2523 
2524 #define VSX_MAX_MINC(name, max, tp, fld)                                      \
2525 void helper_##name(CPUPPCState *env,                                          \
2526                    ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)               \
2527 {                                                                             \
2528     ppc_vsr_t t = { };                                                        \
2529     bool first;                                                               \
2530                                                                               \
2531     helper_reset_fpstatus(env);                                               \
2532                                                                               \
2533     if (max) {                                                                \
2534         first = tp##_le_quiet(xb->fld, xa->fld, &env->fp_status);             \
2535     } else {                                                                  \
2536         first = tp##_lt_quiet(xa->fld, xb->fld, &env->fp_status);             \
2537     }                                                                         \
2538                                                                               \
2539     if (first) {                                                              \
2540         t.fld = xa->fld;                                                      \
2541     } else {                                                                  \
2542         t.fld = xb->fld;                                                      \
2543         if (env->fp_status.float_exception_flags & float_flag_invalid_snan) { \
2544             float_invalid_op_vxsnan(env, GETPC());                            \
2545         }                                                                     \
2546     }                                                                         \
2547                                                                               \
2548     *xt = t;                                                                  \
2549 }
2550 
2551 VSX_MAX_MINC(XSMAXCDP, true, float64, VsrD(0));
2552 VSX_MAX_MINC(XSMINCDP, false, float64, VsrD(0));
2553 VSX_MAX_MINC(XSMAXCQP, true, float128, f128);
2554 VSX_MAX_MINC(XSMINCQP, false, float128, f128);
2555 
2556 #define VSX_MAX_MINJ(name, max)                                               \
2557 void helper_##name(CPUPPCState *env,                                          \
2558                    ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)               \
2559 {                                                                             \
2560     ppc_vsr_t t = { };                                                        \
2561     bool vxsnan_flag = false, vex_flag = false;                               \
2562                                                                               \
2563     if (unlikely(float64_is_any_nan(xa->VsrD(0)))) {                          \
2564         if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status)) {         \
2565             vxsnan_flag = true;                                               \
2566         }                                                                     \
2567         t.VsrD(0) = xa->VsrD(0);                                              \
2568     } else if (unlikely(float64_is_any_nan(xb->VsrD(0)))) {                   \
2569         if (float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) {         \
2570             vxsnan_flag = true;                                               \
2571         }                                                                     \
2572         t.VsrD(0) = xb->VsrD(0);                                              \
2573     } else if (float64_is_zero(xa->VsrD(0)) &&                                \
2574                float64_is_zero(xb->VsrD(0))) {                                \
2575         if (max) {                                                            \
2576             if (!float64_is_neg(xa->VsrD(0)) ||                               \
2577                 !float64_is_neg(xb->VsrD(0))) {                               \
2578                 t.VsrD(0) = 0ULL;                                             \
2579             } else {                                                          \
2580                 t.VsrD(0) = 0x8000000000000000ULL;                            \
2581             }                                                                 \
2582         } else {                                                              \
2583             if (float64_is_neg(xa->VsrD(0)) ||                                \
2584                 float64_is_neg(xb->VsrD(0))) {                                \
2585                 t.VsrD(0) = 0x8000000000000000ULL;                            \
2586             } else {                                                          \
2587                 t.VsrD(0) = 0ULL;                                             \
2588             }                                                                 \
2589         }                                                                     \
2590     } else if ((max &&                                                        \
2591                !float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) ||     \
2592                (!max &&                                                       \
2593                float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status))) {      \
2594         t.VsrD(0) = xa->VsrD(0);                                              \
2595     } else {                                                                  \
2596         t.VsrD(0) = xb->VsrD(0);                                              \
2597     }                                                                         \
2598                                                                               \
2599     vex_flag = (env->fpscr & FP_VE) && vxsnan_flag;                           \
2600     if (vxsnan_flag) {                                                        \
2601         float_invalid_op_vxsnan(env, GETPC());                                \
2602     }                                                                         \
2603     if (!vex_flag) {                                                          \
2604         *xt = t;                                                              \
2605     }                                                                         \
2606 }                                                                             \
2607 
2608 VSX_MAX_MINJ(XSMAXJDP, 1);
2609 VSX_MAX_MINJ(XSMINJDP, 0);
2610 
2611 /*
2612  * VSX_CMP - VSX floating point compare
2613  *   op    - instruction mnemonic
2614  *   nels  - number of elements (1, 2 or 4)
2615  *   tp    - type (float32 or float64)
2616  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
2617  *   cmp   - comparison operation
2618  *   svxvc - set VXVC bit
2619  *   exp   - expected result of comparison
2620  */
2621 #define VSX_CMP(op, nels, tp, fld, cmp, svxvc, exp)                       \
2622 uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt,                     \
2623                      ppc_vsr_t *xa, ppc_vsr_t *xb)                        \
2624 {                                                                         \
2625     ppc_vsr_t t = *xt;                                                    \
2626     uint32_t crf6 = 0;                                                    \
2627     int i;                                                                \
2628     int all_true = 1;                                                     \
2629     int all_false = 1;                                                    \
2630                                                                           \
2631     helper_reset_fpstatus(env);                                           \
2632                                                                           \
2633     for (i = 0; i < nels; i++) {                                          \
2634         if (unlikely(tp##_is_any_nan(xa->fld) ||                          \
2635                      tp##_is_any_nan(xb->fld))) {                         \
2636             if (tp##_is_signaling_nan(xa->fld, &env->fp_status) ||        \
2637                 tp##_is_signaling_nan(xb->fld, &env->fp_status)) {        \
2638                 float_invalid_op_vxsnan(env, GETPC());                    \
2639             }                                                             \
2640             if (svxvc) {                                                  \
2641                 float_invalid_op_vxvc(env, 0, GETPC());                   \
2642             }                                                             \
2643             t.fld = 0;                                                    \
2644             all_true = 0;                                                 \
2645         } else {                                                          \
2646             if (tp##_##cmp(xb->fld, xa->fld, &env->fp_status) == exp) {   \
2647                 t.fld = -1;                                               \
2648                 all_false = 0;                                            \
2649             } else {                                                      \
2650                 t.fld = 0;                                                \
2651                 all_true = 0;                                             \
2652             }                                                             \
2653         }                                                                 \
2654     }                                                                     \
2655                                                                           \
2656     *xt = t;                                                              \
2657     crf6 = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0);                  \
2658     return crf6;                                                          \
2659 }
2660 
2661 VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0, 1)
2662 VSX_CMP(xvcmpgedp, 2, float64, VsrD(i), le, 1, 1)
2663 VSX_CMP(xvcmpgtdp, 2, float64, VsrD(i), lt, 1, 1)
2664 VSX_CMP(xvcmpnedp, 2, float64, VsrD(i), eq, 0, 0)
2665 VSX_CMP(xvcmpeqsp, 4, float32, VsrW(i), eq, 0, 1)
2666 VSX_CMP(xvcmpgesp, 4, float32, VsrW(i), le, 1, 1)
2667 VSX_CMP(xvcmpgtsp, 4, float32, VsrW(i), lt, 1, 1)
2668 VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0)
2669 
2670 /*
2671  * VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
2672  *   op    - instruction mnemonic
2673  *   nels  - number of elements (1, 2 or 4)
2674  *   stp   - source type (float32 or float64)
2675  *   ttp   - target type (float32 or float64)
2676  *   sfld  - source vsr_t field
2677  *   tfld  - target vsr_t field (f32 or f64)
2678  *   sfifprf - set FI and FPRF
2679  */
2680 #define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf)  \
2681 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)   \
2682 {                                                                  \
2683     ppc_vsr_t t = { };                                             \
2684     int i;                                                         \
2685                                                                    \
2686     helper_reset_fpstatus(env);                                    \
2687                                                                    \
2688     for (i = 0; i < nels; i++) {                                   \
2689         t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status);        \
2690         if (unlikely(stp##_is_signaling_nan(xb->sfld,              \
2691                                             &env->fp_status))) {   \
2692             float_invalid_op_vxsnan(env, GETPC());                 \
2693             t.tfld = ttp##_snan_to_qnan(t.tfld);                   \
2694         }                                                          \
2695         if (sfifprf) {                                             \
2696             helper_compute_fprf_##ttp(env, t.tfld);                \
2697         }                                                          \
2698     }                                                              \
2699                                                                    \
2700     *xt = t;                                                       \
2701     do_float_check_status(env, sfifprf, GETPC());                  \
2702 }
2703 
2704 VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1)
2705 VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0)
2706 
2707 #define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfifprf)                \
2708 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)      \
2709 {                                                                     \
2710     ppc_vsr_t t = { };                                                \
2711     int i;                                                            \
2712                                                                       \
2713     helper_reset_fpstatus(env);                                       \
2714                                                                       \
2715     for (i = 0; i < nels; i++) {                                      \
2716         t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \
2717         if (unlikely(stp##_is_signaling_nan(xb->VsrD(i),              \
2718                                             &env->fp_status))) {      \
2719             float_invalid_op_vxsnan(env, GETPC());                    \
2720             t.VsrW(2 * i) = ttp##_snan_to_qnan(t.VsrW(2 * i));        \
2721         }                                                             \
2722         if (sfifprf) {                                                \
2723             helper_compute_fprf_##ttp(env, t.VsrW(2 * i));            \
2724         }                                                             \
2725         t.VsrW(2 * i + 1) = t.VsrW(2 * i);                            \
2726     }                                                                 \
2727                                                                       \
2728     *xt = t;                                                          \
2729     do_float_check_status(env, sfifprf, GETPC());                     \
2730 }
2731 
2732 VSX_CVT_FP_TO_FP2(xvcvdpsp, 2, float64, float32, 0)
2733 VSX_CVT_FP_TO_FP2(xscvdpsp, 1, float64, float32, 1)
2734 
2735 /*
2736  * VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion
2737  *   op    - instruction mnemonic
2738  *   nels  - number of elements (1, 2 or 4)
2739  *   stp   - source type (float32 or float64)
2740  *   ttp   - target type (float32 or float64)
2741  *   sfld  - source vsr_t field
2742  *   tfld  - target vsr_t field (f32 or f64)
2743  *   sfprf - set FPRF
2744  */
2745 #define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf)  \
2746 void helper_##op(CPUPPCState *env, uint32_t opcode,                     \
2747                  ppc_vsr_t *xt, ppc_vsr_t *xb)                          \
2748 {                                                                       \
2749     ppc_vsr_t t = *xt;                                                  \
2750     int i;                                                              \
2751                                                                         \
2752     helper_reset_fpstatus(env);                                         \
2753                                                                         \
2754     for (i = 0; i < nels; i++) {                                        \
2755         t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status);             \
2756         if (unlikely(stp##_is_signaling_nan(xb->sfld,                   \
2757                                             &env->fp_status))) {        \
2758             float_invalid_op_vxsnan(env, GETPC());                      \
2759             t.tfld = ttp##_snan_to_qnan(t.tfld);                        \
2760         }                                                               \
2761         if (sfprf) {                                                    \
2762             helper_compute_fprf_##ttp(env, t.tfld);                     \
2763         }                                                               \
2764     }                                                                   \
2765                                                                         \
2766     *xt = t;                                                            \
2767     do_float_check_status(env, true, GETPC());                          \
2768 }
2769 
2770 VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1)
2771 
2772 /*
2773  * VSX_CVT_FP_TO_FP_HP - VSX floating point/floating point conversion
2774  *                       involving one half precision value
2775  *   op    - instruction mnemonic
2776  *   nels  - number of elements (1, 2 or 4)
2777  *   stp   - source type
2778  *   ttp   - target type
2779  *   sfld  - source vsr_t field
2780  *   tfld  - target vsr_t field
2781  *   sfifprf - set FI and FPRF
2782  */
2783 #define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfifprf) \
2784 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)   \
2785 {                                                                  \
2786     ppc_vsr_t t = { };                                             \
2787     int i;                                                         \
2788                                                                    \
2789     helper_reset_fpstatus(env);                                    \
2790                                                                    \
2791     for (i = 0; i < nels; i++) {                                   \
2792         t.tfld = stp##_to_##ttp(xb->sfld, 1, &env->fp_status);     \
2793         if (unlikely(stp##_is_signaling_nan(xb->sfld,              \
2794                                             &env->fp_status))) {   \
2795             float_invalid_op_vxsnan(env, GETPC());                 \
2796             t.tfld = ttp##_snan_to_qnan(t.tfld);                   \
2797         }                                                          \
2798         if (sfifprf) {                                             \
2799             helper_compute_fprf_##ttp(env, t.tfld);                \
2800         }                                                          \
2801     }                                                              \
2802                                                                    \
2803     *xt = t;                                                       \
2804     do_float_check_status(env, sfifprf, GETPC());                  \
2805 }
2806 
2807 VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1)
2808 VSX_CVT_FP_TO_FP_HP(xscvhpdp, 1, float16, float64, VsrH(3), VsrD(0), 1)
2809 VSX_CVT_FP_TO_FP_HP(xvcvsphp, 4, float32, float16, VsrW(i), VsrH(2 * i  + 1), 0)
2810 VSX_CVT_FP_TO_FP_HP(xvcvhpsp, 4, float16, float32, VsrH(2 * i + 1), VsrW(i), 0)
2811 
2812 void helper_XVCVSPBF16(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)
2813 {
2814     ppc_vsr_t t = { };
2815     int i, status;
2816 
2817     helper_reset_fpstatus(env);
2818 
2819     for (i = 0; i < 4; i++) {
2820         t.VsrH(2 * i + 1) = float32_to_bfloat16(xb->VsrW(i), &env->fp_status);
2821     }
2822 
2823     status = get_float_exception_flags(&env->fp_status);
2824     if (unlikely(status & float_flag_invalid_snan)) {
2825         float_invalid_op_vxsnan(env, GETPC());
2826     }
2827 
2828     *xt = t;
2829     do_float_check_status(env, false, GETPC());
2830 }
2831 
2832 void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt,
2833                      ppc_vsr_t *xb)
2834 {
2835     ppc_vsr_t t = { };
2836     float_status tstat;
2837 
2838     helper_reset_fpstatus(env);
2839 
2840     tstat = env->fp_status;
2841     if (ro != 0) {
2842         tstat.float_rounding_mode = float_round_to_odd;
2843     }
2844 
2845     t.VsrD(0) = float128_to_float64(xb->f128, &tstat);
2846     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
2847     if (unlikely(float128_is_signaling_nan(xb->f128, &tstat))) {
2848         float_invalid_op_vxsnan(env, GETPC());
2849         t.VsrD(0) = float64_snan_to_qnan(t.VsrD(0));
2850     }
2851     helper_compute_fprf_float64(env, t.VsrD(0));
2852 
2853     *xt = t;
2854     do_float_check_status(env, true, GETPC());
2855 }
2856 
2857 uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
2858 {
2859     uint64_t result, sign, exp, frac;
2860 
2861     helper_reset_fpstatus(env);
2862     float_status tstat = env->fp_status;
2863     set_float_exception_flags(0, &tstat);
2864 
2865     sign = extract64(xb, 63,  1);
2866     exp  = extract64(xb, 52, 11);
2867     frac = extract64(xb,  0, 52) | 0x10000000000000ULL;
2868 
2869     if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) {
2870         /* DP denormal operand.  */
2871         /* Exponent override to DP min exp.  */
2872         exp = 1;
2873         /* Implicit bit override to 0.  */
2874         frac = deposit64(frac, 53, 1, 0);
2875     }
2876 
2877     if (unlikely(exp < 897 && frac != 0)) {
2878         /* SP tiny operand.  */
2879         if (897 - exp > 63) {
2880             frac = 0;
2881         } else {
2882             /* Denormalize until exp = SP min exp.  */
2883             frac >>= (897 - exp);
2884         }
2885         /* Exponent override to SP min exp - 1.  */
2886         exp = 896;
2887     }
2888 
2889     result = sign << 31;
2890     result |= extract64(exp, 10, 1) << 30;
2891     result |= extract64(exp, 0, 7) << 23;
2892     result |= extract64(frac, 29, 23);
2893 
2894     /* hardware replicates result to both words of the doubleword result.  */
2895     return (result << 32) | result;
2896 }
2897 
2898 uint64_t helper_XSCVSPDPN(uint64_t xb)
2899 {
2900     return helper_todouble(xb >> 32);
2901 }
2902 
2903 /*
2904  * VSX_CVT_FP_TO_INT - VSX floating point to integer conversion
2905  *   op    - instruction mnemonic
2906  *   nels  - number of elements (1, 2 or 4)
2907  *   stp   - source type (float32 or float64)
2908  *   ttp   - target type (int32, uint32, int64 or uint64)
2909  *   sfld  - source vsr_t field
2910  *   tfld  - target vsr_t field
2911  *   sfi   - set FI
2912  *   rnan  - resulting NaN
2913  */
2914 #define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, sfi, rnan)         \
2915 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)             \
2916 {                                                                            \
2917     ppc_vsr_t t = { };                                                       \
2918     int i, flags;                                                            \
2919                                                                              \
2920     helper_reset_fpstatus(env);                                              \
2921                                                                              \
2922     for (i = 0; i < nels; i++) {                                             \
2923         t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status);  \
2924         flags = env->fp_status.float_exception_flags;                        \
2925         if (unlikely(flags & float_flag_invalid)) {                          \
2926             t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC());\
2927         }                                                                    \
2928     }                                                                        \
2929                                                                              \
2930     *xt = t;                                                                 \
2931     do_float_check_status(env, sfi, GETPC());                                \
2932 }
2933 
2934 VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), true, \
2935                   0x8000000000000000ULL)
2936 VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), true, 0ULL)
2937 VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), false, \
2938                   0x8000000000000000ULL)
2939 VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), false, \
2940                   0ULL)
2941 VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), false, \
2942                   0x8000000000000000ULL)
2943 VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), false, \
2944                   0x80000000ULL)
2945 VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), \
2946                   false, 0ULL)
2947 VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), false, 0U)
2948 
2949 #define VSX_CVT_FP_TO_INT128(op, tp, rnan)                                     \
2950 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)               \
2951 {                                                                              \
2952     ppc_vsr_t t;                                                               \
2953     int flags;                                                                 \
2954                                                                                \
2955     helper_reset_fpstatus(env);                                                \
2956     t.s128 = float128_to_##tp##_round_to_zero(xb->f128, &env->fp_status);      \
2957     flags = get_float_exception_flags(&env->fp_status);                        \
2958     if (unlikely(flags & float_flag_invalid)) {                                \
2959         t.VsrD(0) = float_invalid_cvt(env, flags, t.VsrD(0), rnan, 0, GETPC());\
2960         t.VsrD(1) = -(t.VsrD(0) & 1);                                          \
2961     }                                                                          \
2962                                                                                \
2963     *xt = t;                                                                   \
2964     do_float_check_status(env, true, GETPC());                                 \
2965 }
2966 
2967 VSX_CVT_FP_TO_INT128(XSCVQPUQZ, uint128, 0)
2968 VSX_CVT_FP_TO_INT128(XSCVQPSQZ, int128, 0x8000000000000000ULL);
2969 
2970 /*
2971  * Likewise, except that the result is duplicated into both subwords.
2972  * Power ISA v3.1 has Programming Notes for these insns:
2973  *     Previous versions of the architecture allowed the contents of
2974  *     word 0 of the result register to be undefined. However, all
2975  *     processors that support this instruction write the result into
2976  *     words 0 and 1 (and words 2 and 3) of the result register, as
2977  *     is required by this version of the architecture.
2978  */
2979 #define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, sfi, rnan)                    \
2980 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)             \
2981 {                                                                            \
2982     ppc_vsr_t t = { };                                                       \
2983     int i, flags;                                                            \
2984                                                                              \
2985     helper_reset_fpstatus(env);                                              \
2986                                                                              \
2987     for (i = 0; i < nels; i++) {                                             \
2988         t.VsrW(2 * i) = stp##_to_##ttp##_round_to_zero(xb->VsrD(i),          \
2989                                                        &env->fp_status);     \
2990         flags = env->fp_status.float_exception_flags;                        \
2991         if (unlikely(flags & float_flag_invalid)) {                          \
2992             t.VsrW(2 * i) = float_invalid_cvt(env, flags, t.VsrW(2 * i),     \
2993                                               rnan, 0, GETPC());             \
2994         }                                                                    \
2995         t.VsrW(2 * i + 1) = t.VsrW(2 * i);                                   \
2996     }                                                                        \
2997                                                                              \
2998     *xt = t;                                                                 \
2999     do_float_check_status(env, sfi, GETPC());                                \
3000 }
3001 
3002 VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, true, 0x80000000U)
3003 VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, true, 0U)
3004 VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, false, 0x80000000U)
3005 VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, false, 0U)
3006 
3007 /*
3008  * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion
3009  *   op    - instruction mnemonic
3010  *   stp   - source type (float32 or float64)
3011  *   ttp   - target type (int32, uint32, int64 or uint64)
3012  *   sfld  - source vsr_t field
3013  *   tfld  - target vsr_t field
3014  *   rnan  - resulting NaN
3015  */
3016 #define VSX_CVT_FP_TO_INT_VECTOR(op, stp, ttp, sfld, tfld, rnan)             \
3017 void helper_##op(CPUPPCState *env, uint32_t opcode,                          \
3018                  ppc_vsr_t *xt, ppc_vsr_t *xb)                               \
3019 {                                                                            \
3020     ppc_vsr_t t = { };                                                       \
3021     int flags;                                                               \
3022                                                                              \
3023     helper_reset_fpstatus(env);                                              \
3024                                                                              \
3025     t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status);      \
3026     flags = get_float_exception_flags(&env->fp_status);                      \
3027     if (flags & float_flag_invalid) {                                        \
3028         t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC());    \
3029     }                                                                        \
3030                                                                              \
3031     *xt = t;                                                                 \
3032     do_float_check_status(env, true, GETPC());                               \
3033 }
3034 
3035 VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0),          \
3036                   0x8000000000000000ULL)
3037 VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0),          \
3038                   0xffffffff80000000ULL)
3039 VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL)
3040 VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL)
3041 
3042 /*
3043  * VSX_CVT_INT_TO_FP - VSX integer to floating point conversion
3044  *   op    - instruction mnemonic
3045  *   nels  - number of elements (1, 2 or 4)
3046  *   stp   - source type (int32, uint32, int64 or uint64)
3047  *   ttp   - target type (float32 or float64)
3048  *   sfld  - source vsr_t field
3049  *   tfld  - target vsr_t field
3050  *   jdef  - definition of the j index (i or 2*i)
3051  *   sfifprf - set FI and FPRF
3052  */
3053 #define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf, r2sp)\
3054 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)        \
3055 {                                                                       \
3056     ppc_vsr_t t = { };                                                  \
3057     int i;                                                              \
3058                                                                         \
3059     helper_reset_fpstatus(env);                                         \
3060                                                                         \
3061     for (i = 0; i < nels; i++) {                                        \
3062         t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status);             \
3063         if (r2sp) {                                                     \
3064             t.tfld = do_frsp(env, t.tfld, GETPC());                     \
3065         }                                                               \
3066         if (sfifprf) {                                                  \
3067             helper_compute_fprf_float64(env, t.tfld);                   \
3068         }                                                               \
3069     }                                                                   \
3070                                                                         \
3071     *xt = t;                                                            \
3072     do_float_check_status(env, sfifprf, GETPC());                       \
3073 }
3074 
3075 VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
3076 VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 0)
3077 VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, VsrD(0), VsrD(0), 1, 1)
3078 VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 1)
3079 VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, VsrD(i), VsrD(i), 0, 0)
3080 VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, VsrD(i), VsrD(i), 0, 0)
3081 VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2 * i), VsrD(i), 0, 0)
3082 VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2 * i), VsrD(i), 0, 0)
3083 VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0)
3084 VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0)
3085 
3086 #define VSX_CVT_INT_TO_FP2(op, stp, ttp)                                \
3087 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)        \
3088 {                                                                       \
3089     ppc_vsr_t t = { };                                                  \
3090     int i;                                                              \
3091                                                                         \
3092     for (i = 0; i < 2; i++) {                                           \
3093         t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status);   \
3094         t.VsrW(2 * i + 1) = t.VsrW(2 * i);                              \
3095     }                                                                   \
3096                                                                         \
3097     *xt = t;                                                            \
3098     do_float_check_status(env, false, GETPC());                         \
3099 }
3100 
3101 VSX_CVT_INT_TO_FP2(xvcvsxdsp, int64, float32)
3102 VSX_CVT_INT_TO_FP2(xvcvuxdsp, uint64, float32)
3103 
3104 #define VSX_CVT_INT128_TO_FP(op, tp)                            \
3105 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)\
3106 {                                                               \
3107     helper_reset_fpstatus(env);                                 \
3108     xt->f128 = tp##_to_float128(xb->s128, &env->fp_status);     \
3109     helper_compute_fprf_float128(env, xt->f128);                \
3110     do_float_check_status(env, true, GETPC());                  \
3111 }
3112 
3113 VSX_CVT_INT128_TO_FP(XSCVUQQP, uint128);
3114 VSX_CVT_INT128_TO_FP(XSCVSQQP, int128);
3115 
3116 /*
3117  * VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion
3118  *   op    - instruction mnemonic
3119  *   stp   - source type (int32, uint32, int64 or uint64)
3120  *   ttp   - target type (float32 or float64)
3121  *   sfld  - source vsr_t field
3122  *   tfld  - target vsr_t field
3123  */
3124 #define VSX_CVT_INT_TO_FP_VECTOR(op, stp, ttp, sfld, tfld)              \
3125 void helper_##op(CPUPPCState *env, uint32_t opcode,                     \
3126                  ppc_vsr_t *xt, ppc_vsr_t *xb)                          \
3127 {                                                                       \
3128     ppc_vsr_t t = *xt;                                                  \
3129                                                                         \
3130     helper_reset_fpstatus(env);                                         \
3131     t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status);                 \
3132     helper_compute_fprf_##ttp(env, t.tfld);                             \
3133                                                                         \
3134     *xt = t;                                                            \
3135     do_float_check_status(env, true, GETPC());                          \
3136 }
3137 
3138 VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128)
3139 VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128)
3140 
3141 /*
3142  * For "use current rounding mode", define a value that will not be
3143  * one of the existing rounding model enums.
3144  */
3145 #define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \
3146   float_round_up + float_round_to_zero)
3147 
3148 /*
3149  * VSX_ROUND - VSX floating point round
3150  *   op    - instruction mnemonic
3151  *   nels  - number of elements (1, 2 or 4)
3152  *   tp    - type (float32 or float64)
3153  *   fld   - vsr_t field (VsrD(*) or VsrW(*))
3154  *   rmode - rounding mode
3155  *   sfifprf - set FI and FPRF
3156  */
3157 #define VSX_ROUND(op, nels, tp, fld, rmode, sfifprf)                   \
3158 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)       \
3159 {                                                                      \
3160     ppc_vsr_t t = { };                                                 \
3161     int i;                                                             \
3162     FloatRoundMode curr_rounding_mode;                                 \
3163                                                                        \
3164     helper_reset_fpstatus(env);                                        \
3165                                                                        \
3166     if (rmode != FLOAT_ROUND_CURRENT) {                                \
3167         curr_rounding_mode = get_float_rounding_mode(&env->fp_status); \
3168         set_float_rounding_mode(rmode, &env->fp_status);               \
3169     }                                                                  \
3170                                                                        \
3171     for (i = 0; i < nels; i++) {                                       \
3172         if (unlikely(tp##_is_signaling_nan(xb->fld,                    \
3173                                            &env->fp_status))) {        \
3174             float_invalid_op_vxsnan(env, GETPC());                     \
3175             t.fld = tp##_snan_to_qnan(xb->fld);                        \
3176         } else {                                                       \
3177             t.fld = tp##_round_to_int(xb->fld, &env->fp_status);       \
3178         }                                                              \
3179         if (sfifprf) {                                                 \
3180             helper_compute_fprf_float64(env, t.fld);                   \
3181         }                                                              \
3182     }                                                                  \
3183                                                                        \
3184     /*                                                                 \
3185      * If this is not a "use current rounding mode" instruction,       \
3186      * then inhibit setting of the XX bit and restore rounding         \
3187      * mode from FPSCR                                                 \
3188      */                                                                \
3189     if (rmode != FLOAT_ROUND_CURRENT) {                                \
3190         set_float_rounding_mode(curr_rounding_mode, &env->fp_status);  \
3191         env->fp_status.float_exception_flags &= ~float_flag_inexact;   \
3192     }                                                                  \
3193                                                                        \
3194     *xt = t;                                                           \
3195     do_float_check_status(env, sfifprf, GETPC());                      \
3196 }
3197 
3198 VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
3199 VSX_ROUND(xsrdpic, 1, float64, VsrD(0), FLOAT_ROUND_CURRENT, 1)
3200 VSX_ROUND(xsrdpim, 1, float64, VsrD(0), float_round_down, 1)
3201 VSX_ROUND(xsrdpip, 1, float64, VsrD(0), float_round_up, 1)
3202 VSX_ROUND(xsrdpiz, 1, float64, VsrD(0), float_round_to_zero, 1)
3203 
3204 VSX_ROUND(xvrdpi, 2, float64, VsrD(i), float_round_ties_away, 0)
3205 VSX_ROUND(xvrdpic, 2, float64, VsrD(i), FLOAT_ROUND_CURRENT, 0)
3206 VSX_ROUND(xvrdpim, 2, float64, VsrD(i), float_round_down, 0)
3207 VSX_ROUND(xvrdpip, 2, float64, VsrD(i), float_round_up, 0)
3208 VSX_ROUND(xvrdpiz, 2, float64, VsrD(i), float_round_to_zero, 0)
3209 
3210 VSX_ROUND(xvrspi, 4, float32, VsrW(i), float_round_ties_away, 0)
3211 VSX_ROUND(xvrspic, 4, float32, VsrW(i), FLOAT_ROUND_CURRENT, 0)
3212 VSX_ROUND(xvrspim, 4, float32, VsrW(i), float_round_down, 0)
3213 VSX_ROUND(xvrspip, 4, float32, VsrW(i), float_round_up, 0)
3214 VSX_ROUND(xvrspiz, 4, float32, VsrW(i), float_round_to_zero, 0)
3215 
3216 uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
3217 {
3218     helper_reset_fpstatus(env);
3219 
3220     uint64_t xt = do_frsp(env, xb, GETPC());
3221 
3222     helper_compute_fprf_float64(env, xt);
3223     do_float_check_status(env, true, GETPC());
3224     return xt;
3225 }
3226 
3227 void helper_XVXSIGSP(ppc_vsr_t *xt, ppc_vsr_t *xb)
3228 {
3229     ppc_vsr_t t = { };
3230     uint32_t exp, i, fraction;
3231 
3232     for (i = 0; i < 4; i++) {
3233         exp = (xb->VsrW(i) >> 23) & 0xFF;
3234         fraction = xb->VsrW(i) & 0x7FFFFF;
3235         if (exp != 0 && exp != 255) {
3236             t.VsrW(i) = fraction | 0x00800000;
3237         } else {
3238             t.VsrW(i) = fraction;
3239         }
3240     }
3241     *xt = t;
3242 }
3243 
3244 #define VSX_TSTDC(tp)                                       \
3245 static int32_t tp##_tstdc(tp b, uint32_t dcmx)              \
3246 {                                                           \
3247     uint32_t match = 0;                                     \
3248     uint32_t sign = tp##_is_neg(b);                         \
3249     if (tp##_is_any_nan(b)) {                               \
3250         match = extract32(dcmx, 6, 1);                      \
3251     } else if (tp##_is_infinity(b)) {                       \
3252         match = extract32(dcmx, 4 + !sign, 1);              \
3253     } else if (tp##_is_zero(b)) {                           \
3254         match = extract32(dcmx, 2 + !sign, 1);              \
3255     } else if (tp##_is_zero_or_denormal(b)) {               \
3256         match = extract32(dcmx, 0 + !sign, 1);              \
3257     }                                                       \
3258     return (match != 0);                                    \
3259 }
3260 
3261 VSX_TSTDC(float32)
3262 VSX_TSTDC(float64)
3263 VSX_TSTDC(float128)
3264 #undef VSX_TSTDC
3265 
3266 void helper_XVTSTDCDP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v)
3267 {
3268     int i;
3269     for (i = 0; i < 2; i++) {
3270         t->s64[i] = (int64_t)-float64_tstdc(b->f64[i], dcmx);
3271     }
3272 }
3273 
3274 void helper_XVTSTDCSP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v)
3275 {
3276     int i;
3277     for (i = 0; i < 4; i++) {
3278         t->s32[i] = (int32_t)-float32_tstdc(b->f32[i], dcmx);
3279     }
3280 }
3281 
3282 static bool not_SP_value(float64 val)
3283 {
3284     return val != helper_todouble(helper_tosingle(val));
3285 }
3286 
3287 /*
3288  * VSX_XS_TSTDC - VSX Scalar Test Data Class
3289  *   NAME  - instruction name
3290  *   FLD   - vsr_t field (VsrD(0) or f128)
3291  *   TP    - type (float64 or float128)
3292  */
3293 #define VSX_XS_TSTDC(NAME, FLD, TP)                                         \
3294     void helper_##NAME(CPUPPCState *env, uint32_t bf,                       \
3295                        uint32_t dcmx, ppc_vsr_t *b)                         \
3296     {                                                                       \
3297         uint32_t cc, match, sign = TP##_is_neg(b->FLD);                     \
3298         match = TP##_tstdc(b->FLD, dcmx);                                   \
3299         cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT;                      \
3300         env->fpscr &= ~FP_FPCC;                                             \
3301         env->fpscr |= cc << FPSCR_FPCC;                                     \
3302         env->crf[bf] = cc;                                                  \
3303     }
3304 
3305 VSX_XS_TSTDC(XSTSTDCDP, VsrD(0), float64)
3306 VSX_XS_TSTDC(XSTSTDCQP, f128, float128)
3307 #undef VSX_XS_TSTDC
3308 
3309 void helper_XSTSTDCSP(CPUPPCState *env, uint32_t bf,
3310                       uint32_t dcmx, ppc_vsr_t *b)
3311 {
3312     uint32_t cc, match, sign = float64_is_neg(b->VsrD(0));
3313     uint32_t exp = (b->VsrD(0) >> 52) & 0x7FF;
3314     int not_sp = (int)not_SP_value(b->VsrD(0));
3315     match = float64_tstdc(b->VsrD(0), dcmx) || (exp > 0 && exp < 0x381);
3316     cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT;
3317     env->fpscr &= ~FP_FPCC;
3318     env->fpscr |= cc << FPSCR_FPCC;
3319     env->crf[bf] = cc;
3320 }
3321 
3322 void helper_xsrqpi(CPUPPCState *env, uint32_t opcode,
3323                    ppc_vsr_t *xt, ppc_vsr_t *xb)
3324 {
3325     ppc_vsr_t t = { };
3326     uint8_t r = Rrm(opcode);
3327     uint8_t ex = Rc(opcode);
3328     uint8_t rmc = RMC(opcode);
3329     uint8_t rmode = 0;
3330     float_status tstat;
3331 
3332     helper_reset_fpstatus(env);
3333 
3334     if (r == 0 && rmc == 0) {
3335         rmode = float_round_ties_away;
3336     } else if (r == 0 && rmc == 0x3) {
3337         rmode = env->fpscr & FP_RN;
3338     } else if (r == 1) {
3339         switch (rmc) {
3340         case 0:
3341             rmode = float_round_nearest_even;
3342             break;
3343         case 1:
3344             rmode = float_round_to_zero;
3345             break;
3346         case 2:
3347             rmode = float_round_up;
3348             break;
3349         case 3:
3350             rmode = float_round_down;
3351             break;
3352         default:
3353             abort();
3354         }
3355     }
3356 
3357     tstat = env->fp_status;
3358     set_float_exception_flags(0, &tstat);
3359     set_float_rounding_mode(rmode, &tstat);
3360     t.f128 = float128_round_to_int(xb->f128, &tstat);
3361     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3362 
3363     if (unlikely(tstat.float_exception_flags & float_flag_invalid_snan)) {
3364         float_invalid_op_vxsnan(env, GETPC());
3365     }
3366 
3367     if (ex == 0 && (tstat.float_exception_flags & float_flag_inexact)) {
3368         env->fp_status.float_exception_flags &= ~float_flag_inexact;
3369     }
3370 
3371     helper_compute_fprf_float128(env, t.f128);
3372     do_float_check_status(env, true, GETPC());
3373     *xt = t;
3374 }
3375 
3376 void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode,
3377                     ppc_vsr_t *xt, ppc_vsr_t *xb)
3378 {
3379     ppc_vsr_t t = { };
3380     uint8_t r = Rrm(opcode);
3381     uint8_t rmc = RMC(opcode);
3382     uint8_t rmode = 0;
3383     floatx80 round_res;
3384     float_status tstat;
3385 
3386     helper_reset_fpstatus(env);
3387 
3388     if (r == 0 && rmc == 0) {
3389         rmode = float_round_ties_away;
3390     } else if (r == 0 && rmc == 0x3) {
3391         rmode = env->fpscr & FP_RN;
3392     } else if (r == 1) {
3393         switch (rmc) {
3394         case 0:
3395             rmode = float_round_nearest_even;
3396             break;
3397         case 1:
3398             rmode = float_round_to_zero;
3399             break;
3400         case 2:
3401             rmode = float_round_up;
3402             break;
3403         case 3:
3404             rmode = float_round_down;
3405             break;
3406         default:
3407             abort();
3408         }
3409     }
3410 
3411     tstat = env->fp_status;
3412     set_float_exception_flags(0, &tstat);
3413     set_float_rounding_mode(rmode, &tstat);
3414     round_res = float128_to_floatx80(xb->f128, &tstat);
3415     t.f128 = floatx80_to_float128(round_res, &tstat);
3416     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3417 
3418     if (unlikely(tstat.float_exception_flags & float_flag_invalid_snan)) {
3419         float_invalid_op_vxsnan(env, GETPC());
3420         t.f128 = float128_snan_to_qnan(t.f128);
3421     }
3422 
3423     helper_compute_fprf_float128(env, t.f128);
3424     *xt = t;
3425     do_float_check_status(env, true, GETPC());
3426 }
3427 
3428 void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode,
3429                      ppc_vsr_t *xt, ppc_vsr_t *xb)
3430 {
3431     ppc_vsr_t t = { };
3432     float_status tstat;
3433 
3434     helper_reset_fpstatus(env);
3435 
3436     tstat = env->fp_status;
3437     if (unlikely(Rc(opcode) != 0)) {
3438         tstat.float_rounding_mode = float_round_to_odd;
3439     }
3440 
3441     set_float_exception_flags(0, &tstat);
3442     t.f128 = float128_sqrt(xb->f128, &tstat);
3443     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3444 
3445     if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
3446         float_invalid_op_sqrt(env, tstat.float_exception_flags, 1, GETPC());
3447     }
3448 
3449     helper_compute_fprf_float128(env, t.f128);
3450     *xt = t;
3451     do_float_check_status(env, true, GETPC());
3452 }
3453 
3454 void helper_xssubqp(CPUPPCState *env, uint32_t opcode,
3455                     ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
3456 {
3457     ppc_vsr_t t = *xt;
3458     float_status tstat;
3459 
3460     helper_reset_fpstatus(env);
3461 
3462     tstat = env->fp_status;
3463     if (unlikely(Rc(opcode) != 0)) {
3464         tstat.float_rounding_mode = float_round_to_odd;
3465     }
3466 
3467     set_float_exception_flags(0, &tstat);
3468     t.f128 = float128_sub(xa->f128, xb->f128, &tstat);
3469     env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3470 
3471     if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
3472         float_invalid_op_addsub(env, tstat.float_exception_flags, 1, GETPC());
3473     }
3474 
3475     helper_compute_fprf_float128(env, t.f128);
3476     *xt = t;
3477     do_float_check_status(env, true, GETPC());
3478 }
3479 
3480 static inline void vsxger_excp(CPUPPCState *env, uintptr_t retaddr)
3481 {
3482     /*
3483      * XV*GER instructions execute and set the FPSCR as if exceptions
3484      * are disabled and only at the end throw an exception
3485      */
3486     target_ulong enable;
3487     enable = env->fpscr & (FP_ENABLES | FP_FI | FP_FR);
3488     env->fpscr &= ~(FP_ENABLES | FP_FI | FP_FR);
3489     int status = get_float_exception_flags(&env->fp_status);
3490     if (unlikely(status & float_flag_invalid)) {
3491         if (status & float_flag_invalid_snan) {
3492             float_invalid_op_vxsnan(env, 0);
3493         }
3494         if (status & float_flag_invalid_imz) {
3495             float_invalid_op_vximz(env, false, 0);
3496         }
3497         if (status & float_flag_invalid_isi) {
3498             float_invalid_op_vxisi(env, false, 0);
3499         }
3500     }
3501     do_float_check_status(env, false, retaddr);
3502     env->fpscr |= enable;
3503     do_fpscr_check_status(env, retaddr);
3504 }
3505 
3506 typedef float64 extract_f16(float16, float_status *);
3507 
3508 static float64 extract_hf16(float16 in, float_status *fp_status)
3509 {
3510     return float16_to_float64(in, true, fp_status);
3511 }
3512 
3513 static float64 extract_bf16(bfloat16 in, float_status *fp_status)
3514 {
3515     return bfloat16_to_float64(in, fp_status);
3516 }
3517 
3518 static void vsxger16(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3519                      ppc_acc_t  *at, uint32_t mask, bool acc,
3520                      bool neg_mul, bool neg_acc, extract_f16 extract)
3521 {
3522     float32 r, aux_acc;
3523     float64 psum, va, vb, vc, vd;
3524     int i, j, xmsk_bit, ymsk_bit;
3525     uint8_t pmsk = FIELD_EX32(mask, GER_MSK, PMSK),
3526             xmsk = FIELD_EX32(mask, GER_MSK, XMSK),
3527             ymsk = FIELD_EX32(mask, GER_MSK, YMSK);
3528     float_status *excp_ptr = &env->fp_status;
3529     for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) {
3530         for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) {
3531             if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) {
3532                 va = !(pmsk & 2) ? float64_zero :
3533                                    extract(a->VsrHF(2 * i), excp_ptr);
3534                 vb = !(pmsk & 2) ? float64_zero :
3535                                    extract(b->VsrHF(2 * j), excp_ptr);
3536                 vc = !(pmsk & 1) ? float64_zero :
3537                                    extract(a->VsrHF(2 * i + 1), excp_ptr);
3538                 vd = !(pmsk & 1) ? float64_zero :
3539                                    extract(b->VsrHF(2 * j + 1), excp_ptr);
3540                 psum = float64_mul(va, vb, excp_ptr);
3541                 psum = float64r32_muladd(vc, vd, psum, 0, excp_ptr);
3542                 r = float64_to_float32(psum, excp_ptr);
3543                 if (acc) {
3544                     aux_acc = at[i].VsrSF(j);
3545                     if (neg_mul) {
3546                         r = bfp32_neg(r);
3547                     }
3548                     if (neg_acc) {
3549                         aux_acc = bfp32_neg(aux_acc);
3550                     }
3551                     r = float32_add(r, aux_acc, excp_ptr);
3552                 }
3553                 at[i].VsrSF(j) = r;
3554             } else {
3555                 at[i].VsrSF(j) = float32_zero;
3556             }
3557         }
3558     }
3559     vsxger_excp(env, GETPC());
3560 }
3561 
3562 typedef void vsxger_zero(ppc_vsr_t *at, int, int);
3563 
3564 typedef void vsxger_muladd_f(ppc_vsr_t *, ppc_vsr_t *, ppc_vsr_t *, int, int,
3565                              int flags, float_status *s);
3566 
3567 static void vsxger_muladd32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3568                             int j, int flags, float_status *s)
3569 {
3570     at[i].VsrSF(j) = float32_muladd(a->VsrSF(i), b->VsrSF(j),
3571                                     at[i].VsrSF(j), flags, s);
3572 }
3573 
3574 static void vsxger_mul32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3575                          int j, int flags, float_status *s)
3576 {
3577     at[i].VsrSF(j) = float32_mul(a->VsrSF(i), b->VsrSF(j), s);
3578 }
3579 
3580 static void vsxger_zero32(ppc_vsr_t *at, int i, int j)
3581 {
3582     at[i].VsrSF(j) = float32_zero;
3583 }
3584 
3585 static void vsxger_muladd64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3586                             int j, int flags, float_status *s)
3587 {
3588     if (j >= 2) {
3589         j -= 2;
3590         at[i].VsrDF(j) = float64_muladd(a[i / 2].VsrDF(i % 2), b->VsrDF(j),
3591                                         at[i].VsrDF(j), flags, s);
3592     }
3593 }
3594 
3595 static void vsxger_mul64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3596                          int j, int flags, float_status *s)
3597 {
3598     if (j >= 2) {
3599         j -= 2;
3600         at[i].VsrDF(j) = float64_mul(a[i / 2].VsrDF(i % 2), b->VsrDF(j), s);
3601     }
3602 }
3603 
3604 static void vsxger_zero64(ppc_vsr_t *at, int i, int j)
3605 {
3606     if (j >= 2) {
3607         j -= 2;
3608         at[i].VsrDF(j) = float64_zero;
3609     }
3610 }
3611 
3612 static void vsxger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3613                    ppc_acc_t  *at, uint32_t mask, bool acc, bool neg_mul,
3614                    bool neg_acc, vsxger_muladd_f mul, vsxger_muladd_f muladd,
3615                    vsxger_zero zero)
3616 {
3617     int i, j, xmsk_bit, ymsk_bit, op_flags;
3618     uint8_t xmsk = mask & 0x0F;
3619     uint8_t ymsk = (mask >> 4) & 0x0F;
3620     float_status *excp_ptr = &env->fp_status;
3621     op_flags = (neg_acc ^ neg_mul) ? float_muladd_negate_c : 0;
3622     op_flags |= (neg_mul) ? float_muladd_negate_result : 0;
3623     helper_reset_fpstatus(env);
3624     for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) {
3625         for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) {
3626             if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) {
3627                 if (acc) {
3628                     muladd(at, a, b, i, j, op_flags, excp_ptr);
3629                 } else {
3630                     mul(at, a, b, i, j, op_flags, excp_ptr);
3631                 }
3632             } else {
3633                 zero(at, i, j);
3634             }
3635         }
3636     }
3637     vsxger_excp(env, GETPC());
3638 }
3639 
3640 QEMU_FLATTEN
3641 void helper_XVBF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3642                        ppc_acc_t *at, uint32_t mask)
3643 {
3644     vsxger16(env, a, b, at, mask, false, false, false, extract_bf16);
3645 }
3646 
3647 QEMU_FLATTEN
3648 void helper_XVBF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3649                          ppc_acc_t *at, uint32_t mask)
3650 {
3651     vsxger16(env, a, b, at, mask, true, false, false, extract_bf16);
3652 }
3653 
3654 QEMU_FLATTEN
3655 void helper_XVBF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3656                          ppc_acc_t *at, uint32_t mask)
3657 {
3658     vsxger16(env, a, b, at, mask, true, false, true, extract_bf16);
3659 }
3660 
3661 QEMU_FLATTEN
3662 void helper_XVBF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3663                          ppc_acc_t *at, uint32_t mask)
3664 {
3665     vsxger16(env, a, b, at, mask, true, true, false, extract_bf16);
3666 }
3667 
3668 QEMU_FLATTEN
3669 void helper_XVBF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3670                          ppc_acc_t *at, uint32_t mask)
3671 {
3672     vsxger16(env, a, b, at, mask, true, true, true, extract_bf16);
3673 }
3674 
3675 QEMU_FLATTEN
3676 void helper_XVF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3677                      ppc_acc_t *at, uint32_t mask)
3678 {
3679     vsxger16(env, a, b, at, mask, false, false, false, extract_hf16);
3680 }
3681 
3682 QEMU_FLATTEN
3683 void helper_XVF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3684                         ppc_acc_t *at, uint32_t mask)
3685 {
3686     vsxger16(env, a, b, at, mask, true, false, false, extract_hf16);
3687 }
3688 
3689 QEMU_FLATTEN
3690 void helper_XVF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3691                         ppc_acc_t *at, uint32_t mask)
3692 {
3693     vsxger16(env, a, b, at, mask, true, false, true, extract_hf16);
3694 }
3695 
3696 QEMU_FLATTEN
3697 void helper_XVF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3698                         ppc_acc_t *at, uint32_t mask)
3699 {
3700     vsxger16(env, a, b, at, mask, true, true, false, extract_hf16);
3701 }
3702 
3703 QEMU_FLATTEN
3704 void helper_XVF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3705                         ppc_acc_t *at, uint32_t mask)
3706 {
3707     vsxger16(env, a, b, at, mask, true, true, true, extract_hf16);
3708 }
3709 
3710 QEMU_FLATTEN
3711 void helper_XVF32GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3712                      ppc_acc_t *at, uint32_t mask)
3713 {
3714     vsxger(env, a, b, at, mask, false, false, false, vsxger_mul32,
3715            vsxger_muladd32, vsxger_zero32);
3716 }
3717 
3718 QEMU_FLATTEN
3719 void helper_XVF32GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3720                        ppc_acc_t *at, uint32_t mask)
3721 {
3722     vsxger(env, a, b, at, mask, true, false, false, vsxger_mul32,
3723            vsxger_muladd32, vsxger_zero32);
3724 }
3725 
3726 QEMU_FLATTEN
3727 void helper_XVF32GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3728                        ppc_acc_t *at, uint32_t mask)
3729 {
3730     vsxger(env, a, b, at, mask, true, false, true, vsxger_mul32,
3731            vsxger_muladd32, vsxger_zero32);
3732 }
3733 
3734 QEMU_FLATTEN
3735 void helper_XVF32GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3736                        ppc_acc_t *at, uint32_t mask)
3737 {
3738     vsxger(env, a, b, at, mask, true, true, false, vsxger_mul32,
3739            vsxger_muladd32, vsxger_zero32);
3740 }
3741 
3742 QEMU_FLATTEN
3743 void helper_XVF32GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3744                        ppc_acc_t *at, uint32_t mask)
3745 {
3746     vsxger(env, a, b, at, mask, true, true, true, vsxger_mul32,
3747            vsxger_muladd32, vsxger_zero32);
3748 }
3749 
3750 QEMU_FLATTEN
3751 void helper_XVF64GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3752                      ppc_acc_t *at, uint32_t mask)
3753 {
3754     vsxger(env, a, b, at, mask, false, false, false, vsxger_mul64,
3755            vsxger_muladd64, vsxger_zero64);
3756 }
3757 
3758 QEMU_FLATTEN
3759 void helper_XVF64GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3760                        ppc_acc_t *at, uint32_t mask)
3761 {
3762     vsxger(env, a, b, at, mask, true, false, false, vsxger_mul64,
3763            vsxger_muladd64, vsxger_zero64);
3764 }
3765 
3766 QEMU_FLATTEN
3767 void helper_XVF64GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3768                        ppc_acc_t *at, uint32_t mask)
3769 {
3770     vsxger(env, a, b, at, mask, true, false, true, vsxger_mul64,
3771            vsxger_muladd64, vsxger_zero64);
3772 }
3773 
3774 QEMU_FLATTEN
3775 void helper_XVF64GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3776                        ppc_acc_t *at, uint32_t mask)
3777 {
3778     vsxger(env, a, b, at, mask, true, true, false, vsxger_mul64,
3779            vsxger_muladd64, vsxger_zero64);
3780 }
3781 
3782 QEMU_FLATTEN
3783 void helper_XVF64GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3784                        ppc_acc_t *at, uint32_t mask)
3785 {
3786     vsxger(env, a, b, at, mask, true, true, true, vsxger_mul64,
3787            vsxger_muladd64, vsxger_zero64);
3788 }
3789