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