aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/Makefile.objs2
-rw-r--r--target-ppc/fpu_helper.c1731
-rw-r--r--target-ppc/op_helper.c1710
3 files changed, 1733 insertions, 1710 deletions
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index a02b7bc..dde916c 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -3,5 +3,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += op_helper.o helper.o
obj-y += excp_helper.o
+obj-y += fpu_helper.o
+$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
new file mode 100644
index 0000000..be965d1
--- /dev/null
+++ b/target-ppc/fpu_helper.c
@@ -0,0 +1,1731 @@
+/*
+ * PowerPC floating point and SPE emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+/*****************************************************************************/
+/* Floating point operations helpers */
+uint64_t helper_float32_to_float64(uint32_t arg)
+{
+ CPU_FloatU f;
+ CPU_DoubleU d;
+
+ f.l = arg;
+ d.d = float32_to_float64(f.f, &env->fp_status);
+ return d.ll;
+}
+
+uint32_t helper_float64_to_float32(uint64_t arg)
+{
+ CPU_FloatU f;
+ CPU_DoubleU d;
+
+ d.ll = arg;
+ f.f = float64_to_float32(d.d, &env->fp_status);
+ return f.l;
+}
+
+static inline int isden(float64 d)
+{
+ CPU_DoubleU u;
+
+ u.d = d;
+
+ return ((u.ll >> 52) & 0x7FF) == 0;
+}
+
+uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
+{
+ CPU_DoubleU farg;
+ int isneg;
+ int ret;
+
+ farg.ll = arg;
+ isneg = float64_is_neg(farg.d);
+ if (unlikely(float64_is_any_nan(farg.d))) {
+ if (float64_is_signaling_nan(farg.d)) {
+ /* Signaling NaN: flags are undefined */
+ ret = 0x00;
+ } else {
+ /* Quiet NaN */
+ ret = 0x11;
+ }
+ } else if (unlikely(float64_is_infinity(farg.d))) {
+ /* +/- infinity */
+ if (isneg) {
+ ret = 0x09;
+ } else {
+ ret = 0x05;
+ }
+ } else {
+ if (float64_is_zero(farg.d)) {
+ /* +/- zero */
+ if (isneg) {
+ ret = 0x12;
+ } else {
+ ret = 0x02;
+ }
+ } else {
+ if (isden(farg.d)) {
+ /* Denormalized numbers */
+ ret = 0x10;
+ } else {
+ /* Normalized numbers */
+ ret = 0x00;
+ }
+ if (isneg) {
+ ret |= 0x08;
+ } else {
+ ret |= 0x04;
+ }
+ }
+ }
+ if (set_fprf) {
+ /* We update FPSCR_FPRF */
+ env->fpscr &= ~(0x1F << FPSCR_FPRF);
+ env->fpscr |= ret << FPSCR_FPRF;
+ }
+ /* We just need fpcc to update Rc1 */
+ return ret & 0xF;
+}
+
+/* Floating-point invalid operations exception */
+static inline uint64_t fload_invalid_op_excp(int op)
+{
+ uint64_t ret = 0;
+ int ve;
+
+ ve = fpscr_ve;
+ switch (op) {
+ case POWERPC_EXCP_FP_VXSNAN:
+ env->fpscr |= 1 << FPSCR_VXSNAN;
+ break;
+ case POWERPC_EXCP_FP_VXSOFT:
+ env->fpscr |= 1 << FPSCR_VXSOFT;
+ break;
+ case POWERPC_EXCP_FP_VXISI:
+ /* Magnitude subtraction of infinities */
+ env->fpscr |= 1 << FPSCR_VXISI;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXIDI:
+ /* Division of infinity by infinity */
+ env->fpscr |= 1 << FPSCR_VXIDI;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXZDZ:
+ /* Division of zero by zero */
+ env->fpscr |= 1 << FPSCR_VXZDZ;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXIMZ:
+ /* Multiplication of zero by infinity */
+ env->fpscr |= 1 << FPSCR_VXIMZ;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXVC:
+ /* Ordered comparison of NaN */
+ env->fpscr |= 1 << FPSCR_VXVC;
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ /* We must update the target FPR before raising the exception */
+ if (ve != 0) {
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* Exception is differed */
+ ve = 0;
+ }
+ break;
+ case POWERPC_EXCP_FP_VXSQRT:
+ /* Square root of a negative number */
+ env->fpscr |= 1 << FPSCR_VXSQRT;
+ update_arith:
+ env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ if (ve == 0) {
+ /* Set the result to quiet NaN */
+ ret = 0x7FF8000000000000ULL;
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
+ break;
+ case POWERPC_EXCP_FP_VXCVI:
+ /* Invalid conversion */
+ env->fpscr |= 1 << FPSCR_VXCVI;
+ env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ if (ve == 0) {
+ /* Set the result to quiet NaN */
+ ret = 0x7FF8000000000000ULL;
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
+ break;
+ }
+ /* Update the floating-point invalid operation summary */
+ env->fpscr |= 1 << FPSCR_VX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (ve != 0) {
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_FP | op);
+ }
+ }
+ return ret;
+}
+
+static inline void float_zero_divide_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_ZX;
+ env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ze != 0) {
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
+ }
+ }
+}
+
+static inline void float_overflow_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_OX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_oe != 0) {
+ /* XXX: should adjust the result */
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We must update the target FPR before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
+ } else {
+ env->fpscr |= 1 << FPSCR_XX;
+ env->fpscr |= 1 << FPSCR_FI;
+ }
+}
+
+static inline void float_underflow_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_UX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ue != 0) {
+ /* XXX: should adjust the result */
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We must update the target FPR before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
+ }
+}
+
+static inline void float_inexact_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_XX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_xe != 0) {
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We must update the target FPR before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
+ }
+}
+
+static inline void fpscr_set_rounding_mode(void)
+{
+ int rnd_type;
+
+ /* Set rounding mode */
+ switch (fpscr_rn) {
+ case 0:
+ /* Best approximation (round to nearest) */
+ rnd_type = float_round_nearest_even;
+ break;
+ case 1:
+ /* Smaller magnitude (round toward zero) */
+ rnd_type = float_round_to_zero;
+ break;
+ case 2:
+ /* Round toward +infinite */
+ rnd_type = float_round_up;
+ break;
+ default:
+ case 3:
+ /* Round toward -infinite */
+ rnd_type = float_round_down;
+ break;
+ }
+ set_float_rounding_mode(rnd_type, &env->fp_status);
+}
+
+void helper_fpscr_clrbit(uint32_t bit)
+{
+ int prev;
+
+ prev = (env->fpscr >> bit) & 1;
+ env->fpscr &= ~(1 << bit);
+ if (prev == 1) {
+ switch (bit) {
+ case FPSCR_RN1:
+ case FPSCR_RN:
+ fpscr_set_rounding_mode();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void helper_fpscr_setbit(uint32_t bit)
+{
+ int prev;
+
+ prev = (env->fpscr >> bit) & 1;
+ env->fpscr |= 1 << bit;
+ if (prev == 0) {
+ switch (bit) {
+ case FPSCR_VX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ve) {
+ goto raise_ve;
+ }
+ case FPSCR_OX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_oe) {
+ goto raise_oe;
+ }
+ break;
+ case FPSCR_UX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ue) {
+ goto raise_ue;
+ }
+ break;
+ case FPSCR_ZX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ze) {
+ goto raise_ze;
+ }
+ break;
+ case FPSCR_XX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_xe) {
+ goto raise_xe;
+ }
+ break;
+ case FPSCR_VXSNAN:
+ case FPSCR_VXISI:
+ case FPSCR_VXIDI:
+ case FPSCR_VXZDZ:
+ case FPSCR_VXIMZ:
+ case FPSCR_VXVC:
+ case FPSCR_VXSOFT:
+ case FPSCR_VXSQRT:
+ case FPSCR_VXCVI:
+ env->fpscr |= 1 << FPSCR_VX;
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ve != 0) {
+ goto raise_ve;
+ }
+ break;
+ case FPSCR_VE:
+ if (fpscr_vx != 0) {
+ raise_ve:
+ env->error_code = POWERPC_EXCP_FP;
+ if (fpscr_vxsnan) {
+ env->error_code |= POWERPC_EXCP_FP_VXSNAN;
+ }
+ if (fpscr_vxisi) {
+ env->error_code |= POWERPC_EXCP_FP_VXISI;
+ }
+ if (fpscr_vxidi) {
+ env->error_code |= POWERPC_EXCP_FP_VXIDI;
+ }
+ if (fpscr_vxzdz) {
+ env->error_code |= POWERPC_EXCP_FP_VXZDZ;
+ }
+ if (fpscr_vximz) {
+ env->error_code |= POWERPC_EXCP_FP_VXIMZ;
+ }
+ if (fpscr_vxvc) {
+ env->error_code |= POWERPC_EXCP_FP_VXVC;
+ }
+ if (fpscr_vxsoft) {
+ env->error_code |= POWERPC_EXCP_FP_VXSOFT;
+ }
+ if (fpscr_vxsqrt) {
+ env->error_code |= POWERPC_EXCP_FP_VXSQRT;
+ }
+ if (fpscr_vxcvi) {
+ env->error_code |= POWERPC_EXCP_FP_VXCVI;
+ }
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_OE:
+ if (fpscr_ox != 0) {
+ raise_oe:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_UE:
+ if (fpscr_ux != 0) {
+ raise_ue:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_ZE:
+ if (fpscr_zx != 0) {
+ raise_ze:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_XE:
+ if (fpscr_xx != 0) {
+ raise_xe:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_RN1:
+ case FPSCR_RN:
+ fpscr_set_rounding_mode();
+ break;
+ default:
+ break;
+ raise_excp:
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We have to update Rc1 before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ break;
+ }
+ }
+}
+
+void helper_store_fpscr(uint64_t arg, uint32_t mask)
+{
+ /*
+ * We use only the 32 LSB of the incoming fpr
+ */
+ uint32_t prev, new;
+ int i;
+
+ prev = env->fpscr;
+ new = (uint32_t)arg;
+ new &= ~0x60000000;
+ new |= prev & 0x60000000;
+ for (i = 0; i < 8; i++) {
+ if (mask & (1 << i)) {
+ env->fpscr &= ~(0xF << (4 * i));
+ env->fpscr |= new & (0xF << (4 * i));
+ }
+ }
+ /* Update VX and FEX */
+ if (fpscr_ix != 0) {
+ env->fpscr |= 1 << FPSCR_VX;
+ } else {
+ env->fpscr &= ~(1 << FPSCR_VX);
+ }
+ if ((fpscr_ex & fpscr_eex) != 0) {
+ env->fpscr |= 1 << FPSCR_FEX;
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ /* XXX: we should compute it properly */
+ env->error_code = POWERPC_EXCP_FP;
+ } else {
+ env->fpscr &= ~(1 << FPSCR_FEX);
+ }
+ fpscr_set_rounding_mode();
+}
+
+void helper_float_check_status(void)
+{
+ if (env->exception_index == POWERPC_EXCP_PROGRAM &&
+ (env->error_code & POWERPC_EXCP_FP)) {
+ /* Differred floating-point exception after target FPR update */
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
+ helper_raise_exception_err(env, env->exception_index,
+ env->error_code);
+ }
+ } else {
+ int status = get_float_exception_flags(&env->fp_status);
+ if (status & float_flag_divbyzero) {
+ float_zero_divide_excp();
+ } else if (status & float_flag_overflow) {
+ float_overflow_excp();
+ } else if (status & float_flag_underflow) {
+ float_underflow_excp();
+ } else if (status & float_flag_inexact) {
+ float_inexact_excp();
+ }
+ }
+}
+
+void helper_reset_fpstatus(void)
+{
+ set_float_exception_flags(0, &env->fp_status);
+}
+
+/* fadd - fadd. */
+uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN addition */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fsub - fsub. */
+uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN subtraction */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fmul - fmul. */
+uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN multiplication */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fdiv - fdiv. */
+uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_infinity(farg1.d) &&
+ float64_is_infinity(farg2.d))) {
+ /* Division of infinity by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
+ } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
+ /* Division of zero by zero */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN division */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fabs */
+uint64_t helper_fabs(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+ farg.d = float64_abs(farg.d);
+ return farg.ll;
+}
+
+/* fnabs */
+uint64_t helper_fnabs(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+ farg.d = float64_abs(farg.d);
+ farg.d = float64_chs(farg.d);
+ return farg.ll;
+}
+
+/* fneg */
+uint64_t helper_fneg(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+ farg.d = float64_chs(farg.d);
+ return farg.ll;
+}
+
+/* fctiw - fctiw. */
+uint64_t helper_fctiw(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int32(farg.d, &env->fp_status);
+ /* XXX: higher bits are not supposed to be significant.
+ * to make tests easier, return the same as a real PowerPC 750
+ */
+ farg.ll |= 0xFFF80000ULL << 32;
+ }
+ return farg.ll;
+}
+
+/* fctiwz - fctiwz. */
+uint64_t helper_fctiwz(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
+ /* XXX: higher bits are not supposed to be significant.
+ * to make tests easier, return the same as a real PowerPC 750
+ */
+ farg.ll |= 0xFFF80000ULL << 32;
+ }
+ return farg.ll;
+}
+
+#if defined(TARGET_PPC64)
+/* fcfid - fcfid. */
+uint64_t helper_fcfid(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.d = int64_to_float64(arg, &env->fp_status);
+ return farg.ll;
+}
+
+/* fctid - fctid. */
+uint64_t helper_fctid(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int64(farg.d, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+/* fctidz - fctidz. */
+uint64_t helper_fctidz(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+#endif
+
+static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN round */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity round */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ set_float_rounding_mode(rounding_mode, &env->fp_status);
+ farg.ll = float64_round_to_int(farg.d, &env->fp_status);
+ /* Restore rounding mode from FPSCR */
+ fpscr_set_rounding_mode();
+ }
+ return farg.ll;
+}
+
+uint64_t helper_frin(uint64_t arg)
+{
+ return do_fri(arg, float_round_nearest_even);
+}
+
+uint64_t helper_friz(uint64_t arg)
+{
+ return do_fri(arg, float_round_to_zero);
+}
+
+uint64_t helper_frip(uint64_t arg)
+{
+ return do_fri(arg, float_round_up);
+}
+
+uint64_t helper_frim(uint64_t arg)
+{
+ return do_fri(arg, float_round_down);
+}
+
+/* fmadd - fmadd. */
+uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ }
+
+ return farg1.ll;
+}
+
+/* fmsub - fmsub. */
+uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) &&
+ float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ }
+ return farg1.ll;
+}
+
+/* fnmadd - fnmadd. */
+uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ if (likely(!float64_is_any_nan(farg1.d))) {
+ farg1.d = float64_chs(farg1.d);
+ }
+ }
+ return farg1.ll;
+}
+
+/* fnmsub - fnmsub. */
+uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) &&
+ float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ if (likely(!float64_is_any_nan(farg1.d))) {
+ farg1.d = float64_chs(farg1.d);
+ }
+ }
+ return farg1.ll;
+}
+
+/* frsp - frsp. */
+uint64_t helper_frsp(uint64_t arg)
+{
+ CPU_DoubleU farg;
+ float32 f32;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+
+ return farg.ll;
+}
+
+/* fsqrt - fsqrt. */
+uint64_t helper_fsqrt(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+ /* Square root of a negative nonzero number */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_sqrt(farg.d, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+/* fre - fre. */
+uint64_t helper_fre(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN reciprocal */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ return farg.d;
+}
+
+/* fres - fres. */
+uint64_t helper_fres(uint64_t arg)
+{
+ CPU_DoubleU farg;
+ float32 f32;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN reciprocal */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+
+ return farg.ll;
+}
+
+/* frsqrte - frsqrte. */
+uint64_t helper_frsqrte(uint64_t arg)
+{
+ CPU_DoubleU farg;
+ float32 f32;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+ /* Reciprocal square root of a negative nonzero number */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN reciprocal square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_sqrt(farg.d, &env->fp_status);
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+/* fsel - fsel. */
+uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1;
+
+ farg1.ll = arg1;
+
+ if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
+ !float64_is_any_nan(farg1.d)) {
+ return arg2;
+ } else {
+ return arg3;
+ }
+}
+
+void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
+{
+ CPU_DoubleU farg1, farg2;
+ uint32_t ret = 0;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_any_nan(farg1.d) ||
+ float64_is_any_nan(farg2.d))) {
+ ret = 0x01UL;
+ } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x08UL;
+ } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x04UL;
+ } else {
+ ret = 0x02UL;
+ }
+
+ env->fpscr &= ~(0x0F << FPSCR_FPRF);
+ env->fpscr |= ret << FPSCR_FPRF;
+ env->crf[crfD] = ret;
+ if (unlikely(ret == 0x01UL
+ && (float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d)))) {
+ /* sNaN comparison */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+}
+
+void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
+{
+ CPU_DoubleU farg1, farg2;
+ uint32_t ret = 0;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_any_nan(farg1.d) ||
+ float64_is_any_nan(farg2.d))) {
+ ret = 0x01UL;
+ } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x08UL;
+ } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x04UL;
+ } else {
+ ret = 0x02UL;
+ }
+
+ env->fpscr &= ~(0x0F << FPSCR_FPRF);
+ env->fpscr |= ret << FPSCR_FPRF;
+ env->crf[crfD] = ret;
+ if (unlikely(ret == 0x01UL)) {
+ if (float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d)) {
+ /* sNaN comparison */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXVC);
+ } else {
+ /* qNaN comparison */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
+ }
+ }
+}
+
+/* Single-precision floating-point conversions */
+static inline uint32_t efscfsi(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.f = int32_to_float32(val, &env->vec_status);
+
+ return u.l;
+}
+
+static inline uint32_t efscfui(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.f = uint32_to_float32(val, &env->vec_status);
+
+ return u.l;
+}
+
+static inline int32_t efsctsi(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_int32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctui(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_uint32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctsiz(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_int32_round_to_zero(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctuiz(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
+}
+
+static inline uint32_t efscfsf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.f = int32_to_float32(val, &env->vec_status);
+ tmp = int64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_div(u.f, tmp, &env->vec_status);
+
+ return u.l;
+}
+
+static inline uint32_t efscfuf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.f = uint32_to_float32(val, &env->vec_status);
+ tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_div(u.f, tmp, &env->vec_status);
+
+ return u.l;
+}
+
+static inline uint32_t efsctsf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+ tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_mul(u.f, tmp, &env->vec_status);
+
+ return float32_to_int32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctuf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+ tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_mul(u.f, tmp, &env->vec_status);
+
+ return float32_to_uint32(u.f, &env->vec_status);
+}
+
+#define HELPER_SPE_SINGLE_CONV(name) \
+ uint32_t helper_e##name(uint32_t val) \
+ { \
+ return e##name(val); \
+ }
+/* efscfsi */
+HELPER_SPE_SINGLE_CONV(fscfsi);
+/* efscfui */
+HELPER_SPE_SINGLE_CONV(fscfui);
+/* efscfuf */
+HELPER_SPE_SINGLE_CONV(fscfuf);
+/* efscfsf */
+HELPER_SPE_SINGLE_CONV(fscfsf);
+/* efsctsi */
+HELPER_SPE_SINGLE_CONV(fsctsi);
+/* efsctui */
+HELPER_SPE_SINGLE_CONV(fsctui);
+/* efsctsiz */
+HELPER_SPE_SINGLE_CONV(fsctsiz);
+/* efsctuiz */
+HELPER_SPE_SINGLE_CONV(fsctuiz);
+/* efsctsf */
+HELPER_SPE_SINGLE_CONV(fsctsf);
+/* efsctuf */
+HELPER_SPE_SINGLE_CONV(fsctuf);
+
+#define HELPER_SPE_VECTOR_CONV(name) \
+ uint64_t helper_ev##name(uint64_t val) \
+ { \
+ return ((uint64_t)e##name(val >> 32) << 32) | \
+ (uint64_t)e##name(val); \
+ }
+/* evfscfsi */
+HELPER_SPE_VECTOR_CONV(fscfsi);
+/* evfscfui */
+HELPER_SPE_VECTOR_CONV(fscfui);
+/* evfscfuf */
+HELPER_SPE_VECTOR_CONV(fscfuf);
+/* evfscfsf */
+HELPER_SPE_VECTOR_CONV(fscfsf);
+/* evfsctsi */
+HELPER_SPE_VECTOR_CONV(fsctsi);
+/* evfsctui */
+HELPER_SPE_VECTOR_CONV(fsctui);
+/* evfsctsiz */
+HELPER_SPE_VECTOR_CONV(fsctsiz);
+/* evfsctuiz */
+HELPER_SPE_VECTOR_CONV(fsctuiz);
+/* evfsctsf */
+HELPER_SPE_VECTOR_CONV(fsctsf);
+/* evfsctuf */
+HELPER_SPE_VECTOR_CONV(fsctuf);
+
+/* Single-precision floating-point arithmetic */
+static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_add(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+static inline uint32_t efssub(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_div(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+#define HELPER_SPE_SINGLE_ARITH(name) \
+ uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(op1, op2); \
+ }
+/* efsadd */
+HELPER_SPE_SINGLE_ARITH(fsadd);
+/* efssub */
+HELPER_SPE_SINGLE_ARITH(fssub);
+/* efsmul */
+HELPER_SPE_SINGLE_ARITH(fsmul);
+/* efsdiv */
+HELPER_SPE_SINGLE_ARITH(fsdiv);
+
+#define HELPER_SPE_VECTOR_ARITH(name) \
+ uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ { \
+ return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
+ (uint64_t)e##name(op1, op2); \
+ }
+/* evfsadd */
+HELPER_SPE_VECTOR_ARITH(fsadd);
+/* evfssub */
+HELPER_SPE_VECTOR_ARITH(fssub);
+/* evfsmul */
+HELPER_SPE_VECTOR_ARITH(fsmul);
+/* evfsdiv */
+HELPER_SPE_VECTOR_ARITH(fsdiv);
+
+/* Single-precision floating-point comparisons */
+static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
+}
+
+static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
+}
+
+static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
+}
+
+static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+ return efscmplt(op1, op2);
+}
+
+static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+ return efscmpgt(op1, op2);
+}
+
+static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+ return efscmpeq(op1, op2);
+}
+
+#define HELPER_SINGLE_SPE_CMP(name) \
+ uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(op1, op2) << 2; \
+ }
+/* efststlt */
+HELPER_SINGLE_SPE_CMP(fststlt);
+/* efststgt */
+HELPER_SINGLE_SPE_CMP(fststgt);
+/* efststeq */
+HELPER_SINGLE_SPE_CMP(fststeq);
+/* efscmplt */
+HELPER_SINGLE_SPE_CMP(fscmplt);
+/* efscmpgt */
+HELPER_SINGLE_SPE_CMP(fscmpgt);
+/* efscmpeq */
+HELPER_SINGLE_SPE_CMP(fscmpeq);
+
+static inline uint32_t evcmp_merge(int t0, int t1)
+{
+ return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
+}
+
+#define HELPER_VECTOR_SPE_CMP(name) \
+ uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ { \
+ return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
+ }
+/* evfststlt */
+HELPER_VECTOR_SPE_CMP(fststlt);
+/* evfststgt */
+HELPER_VECTOR_SPE_CMP(fststgt);
+/* evfststeq */
+HELPER_VECTOR_SPE_CMP(fststeq);
+/* evfscmplt */
+HELPER_VECTOR_SPE_CMP(fscmplt);
+/* evfscmpgt */
+HELPER_VECTOR_SPE_CMP(fscmpgt);
+/* evfscmpeq */
+HELPER_VECTOR_SPE_CMP(fscmpeq);
+
+/* Double-precision floating-point conversion */
+uint64_t helper_efdcfsi(uint32_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = int32_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfsid(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = int64_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfui(uint32_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = uint32_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfuid(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = uint64_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint32_t helper_efdctsi(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_int32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctui(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_uint32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctsiz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_int32_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdctsidz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_int64_round_to_zero(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctuiz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdctuidz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdcfsf(uint32_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.d = int32_to_float64(val, &env->vec_status);
+ tmp = int64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_div(u.d, tmp, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfuf(uint32_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.d = uint32_to_float64(val, &env->vec_status);
+ tmp = int64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_div(u.d, tmp, &env->vec_status);
+
+ return u.ll;
+}
+
+uint32_t helper_efdctsf(uint64_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+ tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_mul(u.d, tmp, &env->vec_status);
+
+ return float64_to_int32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctuf(uint64_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+ tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_mul(u.d, tmp, &env->vec_status);
+
+ return float64_to_uint32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efscfd(uint64_t val)
+{
+ CPU_DoubleU u1;
+ CPU_FloatU u2;
+
+ u1.ll = val;
+ u2.f = float64_to_float32(u1.d, &env->vec_status);
+
+ return u2.l;
+}
+
+uint64_t helper_efdcfs(uint32_t val)
+{
+ CPU_DoubleU u2;
+ CPU_FloatU u1;
+
+ u1.l = val;
+ u2.d = float32_to_float64(u1.f, &env->vec_status);
+
+ return u2.ll;
+}
+
+/* Double precision fixed-point arithmetic */
+uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_add(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_div(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+/* Double precision floating point helpers */
+uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
+}
+
+uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
+}
+
+uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
+}
+
+uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return helper_efdtstlt(op1, op2);
+}
+
+uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return helper_efdtstgt(op1, op2);
+}
+
+uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return helper_efdtsteq(op1, op2);
+}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index eedbb42..3f677f6 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -547,1099 +547,6 @@ target_ulong helper_popcntw(target_ulong val)
#endif
/*****************************************************************************/
-/* Floating point operations helpers */
-uint64_t helper_float32_to_float64(uint32_t arg)
-{
- CPU_FloatU f;
- CPU_DoubleU d;
-
- f.l = arg;
- d.d = float32_to_float64(f.f, &env->fp_status);
- return d.ll;
-}
-
-uint32_t helper_float64_to_float32(uint64_t arg)
-{
- CPU_FloatU f;
- CPU_DoubleU d;
-
- d.ll = arg;
- f.f = float64_to_float32(d.d, &env->fp_status);
- return f.l;
-}
-
-static inline int isden(float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return ((u.ll >> 52) & 0x7FF) == 0;
-}
-
-uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
-{
- CPU_DoubleU farg;
- int isneg;
- int ret;
-
- farg.ll = arg;
- isneg = float64_is_neg(farg.d);
- if (unlikely(float64_is_any_nan(farg.d))) {
- if (float64_is_signaling_nan(farg.d)) {
- /* Signaling NaN: flags are undefined */
- ret = 0x00;
- } else {
- /* Quiet NaN */
- ret = 0x11;
- }
- } else if (unlikely(float64_is_infinity(farg.d))) {
- /* +/- infinity */
- if (isneg) {
- ret = 0x09;
- } else {
- ret = 0x05;
- }
- } else {
- if (float64_is_zero(farg.d)) {
- /* +/- zero */
- if (isneg) {
- ret = 0x12;
- } else {
- ret = 0x02;
- }
- } else {
- if (isden(farg.d)) {
- /* Denormalized numbers */
- ret = 0x10;
- } else {
- /* Normalized numbers */
- ret = 0x00;
- }
- if (isneg) {
- ret |= 0x08;
- } else {
- ret |= 0x04;
- }
- }
- }
- if (set_fprf) {
- /* We update FPSCR_FPRF */
- env->fpscr &= ~(0x1F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
- }
- /* We just need fpcc to update Rc1 */
- return ret & 0xF;
-}
-
-/* Floating-point invalid operations exception */
-static inline uint64_t fload_invalid_op_excp(int op)
-{
- uint64_t ret = 0;
- int ve;
-
- ve = fpscr_ve;
- switch (op) {
- case POWERPC_EXCP_FP_VXSNAN:
- env->fpscr |= 1 << FPSCR_VXSNAN;
- break;
- case POWERPC_EXCP_FP_VXSOFT:
- env->fpscr |= 1 << FPSCR_VXSOFT;
- break;
- case POWERPC_EXCP_FP_VXISI:
- /* Magnitude subtraction of infinities */
- env->fpscr |= 1 << FPSCR_VXISI;
- goto update_arith;
- case POWERPC_EXCP_FP_VXIDI:
- /* Division of infinity by infinity */
- env->fpscr |= 1 << FPSCR_VXIDI;
- goto update_arith;
- case POWERPC_EXCP_FP_VXZDZ:
- /* Division of zero by zero */
- env->fpscr |= 1 << FPSCR_VXZDZ;
- goto update_arith;
- case POWERPC_EXCP_FP_VXIMZ:
- /* Multiplication of zero by infinity */
- env->fpscr |= 1 << FPSCR_VXIMZ;
- goto update_arith;
- case POWERPC_EXCP_FP_VXVC:
- /* Ordered comparison of NaN */
- env->fpscr |= 1 << FPSCR_VXVC;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
- /* We must update the target FPR before raising the exception */
- if (ve != 0) {
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* Exception is differed */
- ve = 0;
- }
- break;
- case POWERPC_EXCP_FP_VXSQRT:
- /* Square root of a negative number */
- env->fpscr |= 1 << FPSCR_VXSQRT;
- update_arith:
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
- if (ve == 0) {
- /* Set the result to quiet NaN */
- ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
- }
- break;
- case POWERPC_EXCP_FP_VXCVI:
- /* Invalid conversion */
- env->fpscr |= 1 << FPSCR_VXCVI;
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
- if (ve == 0) {
- /* Set the result to quiet NaN */
- ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
- }
- break;
- }
- /* Update the floating-point invalid operation summary */
- env->fpscr |= 1 << FPSCR_VX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (ve != 0) {
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_FP | op);
- }
- }
- return ret;
-}
-
-static inline void float_zero_divide_excp(void)
-{
- env->fpscr |= 1 << FPSCR_ZX;
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ze != 0) {
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
- }
- }
-}
-
-static inline void float_overflow_excp(void)
-{
- env->fpscr |= 1 << FPSCR_OX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_oe != 0) {
- /* XXX: should adjust the result */
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We must update the target FPR before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
- } else {
- env->fpscr |= 1 << FPSCR_XX;
- env->fpscr |= 1 << FPSCR_FI;
- }
-}
-
-static inline void float_underflow_excp(void)
-{
- env->fpscr |= 1 << FPSCR_UX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ue != 0) {
- /* XXX: should adjust the result */
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We must update the target FPR before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
- }
-}
-
-static inline void float_inexact_excp(void)
-{
- env->fpscr |= 1 << FPSCR_XX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_xe != 0) {
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We must update the target FPR before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
- }
-}
-
-static inline void fpscr_set_rounding_mode(void)
-{
- int rnd_type;
-
- /* Set rounding mode */
- switch (fpscr_rn) {
- case 0:
- /* Best approximation (round to nearest) */
- rnd_type = float_round_nearest_even;
- break;
- case 1:
- /* Smaller magnitude (round toward zero) */
- rnd_type = float_round_to_zero;
- break;
- case 2:
- /* Round toward +infinite */
- rnd_type = float_round_up;
- break;
- default:
- case 3:
- /* Round toward -infinite */
- rnd_type = float_round_down;
- break;
- }
- set_float_rounding_mode(rnd_type, &env->fp_status);
-}
-
-void helper_fpscr_clrbit(uint32_t bit)
-{
- int prev;
-
- prev = (env->fpscr >> bit) & 1;
- env->fpscr &= ~(1 << bit);
- if (prev == 1) {
- switch (bit) {
- case FPSCR_RN1:
- case FPSCR_RN:
- fpscr_set_rounding_mode();
- break;
- default:
- break;
- }
- }
-}
-
-void helper_fpscr_setbit(uint32_t bit)
-{
- int prev;
-
- prev = (env->fpscr >> bit) & 1;
- env->fpscr |= 1 << bit;
- if (prev == 0) {
- switch (bit) {
- case FPSCR_VX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ve) {
- goto raise_ve;
- }
- case FPSCR_OX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_oe) {
- goto raise_oe;
- }
- break;
- case FPSCR_UX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ue) {
- goto raise_ue;
- }
- break;
- case FPSCR_ZX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ze) {
- goto raise_ze;
- }
- break;
- case FPSCR_XX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_xe) {
- goto raise_xe;
- }
- break;
- case FPSCR_VXSNAN:
- case FPSCR_VXISI:
- case FPSCR_VXIDI:
- case FPSCR_VXZDZ:
- case FPSCR_VXIMZ:
- case FPSCR_VXVC:
- case FPSCR_VXSOFT:
- case FPSCR_VXSQRT:
- case FPSCR_VXCVI:
- env->fpscr |= 1 << FPSCR_VX;
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ve != 0) {
- goto raise_ve;
- }
- break;
- case FPSCR_VE:
- if (fpscr_vx != 0) {
- raise_ve:
- env->error_code = POWERPC_EXCP_FP;
- if (fpscr_vxsnan) {
- env->error_code |= POWERPC_EXCP_FP_VXSNAN;
- }
- if (fpscr_vxisi) {
- env->error_code |= POWERPC_EXCP_FP_VXISI;
- }
- if (fpscr_vxidi) {
- env->error_code |= POWERPC_EXCP_FP_VXIDI;
- }
- if (fpscr_vxzdz) {
- env->error_code |= POWERPC_EXCP_FP_VXZDZ;
- }
- if (fpscr_vximz) {
- env->error_code |= POWERPC_EXCP_FP_VXIMZ;
- }
- if (fpscr_vxvc) {
- env->error_code |= POWERPC_EXCP_FP_VXVC;
- }
- if (fpscr_vxsoft) {
- env->error_code |= POWERPC_EXCP_FP_VXSOFT;
- }
- if (fpscr_vxsqrt) {
- env->error_code |= POWERPC_EXCP_FP_VXSQRT;
- }
- if (fpscr_vxcvi) {
- env->error_code |= POWERPC_EXCP_FP_VXCVI;
- }
- goto raise_excp;
- }
- break;
- case FPSCR_OE:
- if (fpscr_ox != 0) {
- raise_oe:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
- goto raise_excp;
- }
- break;
- case FPSCR_UE:
- if (fpscr_ux != 0) {
- raise_ue:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
- goto raise_excp;
- }
- break;
- case FPSCR_ZE:
- if (fpscr_zx != 0) {
- raise_ze:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
- goto raise_excp;
- }
- break;
- case FPSCR_XE:
- if (fpscr_xx != 0) {
- raise_xe:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
- goto raise_excp;
- }
- break;
- case FPSCR_RN1:
- case FPSCR_RN:
- fpscr_set_rounding_mode();
- break;
- default:
- break;
- raise_excp:
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We have to update Rc1 before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- break;
- }
- }
-}
-
-void helper_store_fpscr(uint64_t arg, uint32_t mask)
-{
- /*
- * We use only the 32 LSB of the incoming fpr
- */
- uint32_t prev, new;
- int i;
-
- prev = env->fpscr;
- new = (uint32_t)arg;
- new &= ~0x60000000;
- new |= prev & 0x60000000;
- for (i = 0; i < 8; i++) {
- if (mask & (1 << i)) {
- env->fpscr &= ~(0xF << (4 * i));
- env->fpscr |= new & (0xF << (4 * i));
- }
- }
- /* Update VX and FEX */
- if (fpscr_ix != 0) {
- env->fpscr |= 1 << FPSCR_VX;
- } else {
- env->fpscr &= ~(1 << FPSCR_VX);
- }
- if ((fpscr_ex & fpscr_eex) != 0) {
- env->fpscr |= 1 << FPSCR_FEX;
- env->exception_index = POWERPC_EXCP_PROGRAM;
- /* XXX: we should compute it properly */
- env->error_code = POWERPC_EXCP_FP;
- } else {
- env->fpscr &= ~(1 << FPSCR_FEX);
- }
- fpscr_set_rounding_mode();
-}
-
-void helper_float_check_status(void)
-{
- if (env->exception_index == POWERPC_EXCP_PROGRAM &&
- (env->error_code & POWERPC_EXCP_FP)) {
- /* Differred floating-point exception after target FPR update */
- if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(env, env->exception_index,
- env->error_code);
- }
- } else {
- int status = get_float_exception_flags(&env->fp_status);
- if (status & float_flag_divbyzero) {
- float_zero_divide_excp();
- } else if (status & float_flag_overflow) {
- float_overflow_excp();
- } else if (status & float_flag_underflow) {
- float_underflow_excp();
- } else if (status & float_flag_inexact) {
- float_inexact_excp();
- }
- }
-}
-
-void helper_reset_fpstatus(void)
-{
- set_float_exception_flags(0, &env->fp_status);
-}
-
-/* fadd - fadd. */
-uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
- float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN addition */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fsub - fsub. */
-uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
- float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN subtraction */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fmul - fmul. */
-uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN multiplication */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fdiv - fdiv. */
-uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_infinity(farg1.d) &&
- float64_is_infinity(farg2.d))) {
- /* Division of infinity by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
- } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
- /* Division of zero by zero */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN division */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fabs */
-uint64_t helper_fabs(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_abs(farg.d);
- return farg.ll;
-}
-
-/* fnabs */
-uint64_t helper_fnabs(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_abs(farg.d);
- farg.d = float64_chs(farg.d);
- return farg.ll;
-}
-
-/* fneg */
-uint64_t helper_fneg(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_chs(farg.d);
- return farg.ll;
-}
-
-/* fctiw - fctiw. */
-uint64_t helper_fctiw(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
-
-/* fctiwz - fctiwz. */
-uint64_t helper_fctiwz(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
-
-#if defined(TARGET_PPC64)
-/* fcfid - fcfid. */
-uint64_t helper_fcfid(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.d = int64_to_float64(arg, &env->fp_status);
- return farg.ll;
-}
-
-/* fctid - fctid. */
-uint64_t helper_fctid(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fctidz - fctidz. */
-uint64_t helper_fctidz(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-#endif
-
-static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN round */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity round */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- set_float_rounding_mode(rounding_mode, &env->fp_status);
- farg.ll = float64_round_to_int(farg.d, &env->fp_status);
- /* Restore rounding mode from FPSCR */
- fpscr_set_rounding_mode();
- }
- return farg.ll;
-}
-
-uint64_t helper_frin(uint64_t arg)
-{
- return do_fri(arg, float_round_nearest_even);
-}
-
-uint64_t helper_friz(uint64_t arg)
-{
- return do_fri(arg, float_round_to_zero);
-}
-
-uint64_t helper_frip(uint64_t arg)
-{
- return do_fri(arg, float_round_up);
-}
-
-uint64_t helper_frim(uint64_t arg)
-{
- return do_fri(arg, float_round_down);
-}
-
-/* fmadd - fmadd. */
-uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- }
-
- return farg1.ll;
-}
-
-/* fmsub - fmsub. */
-uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) &&
- float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- }
- return farg1.ll;
-}
-
-/* fnmadd - fnmadd. */
-uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- if (likely(!float64_is_any_nan(farg1.d))) {
- farg1.d = float64_chs(farg1.d);
- }
- }
- return farg1.ll;
-}
-
-/* fnmsub - fnmsub. */
-uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) &&
- float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- if (likely(!float64_is_any_nan(farg1.d))) {
- farg1.d = float64_chs(farg1.d);
- }
- }
- return farg1.ll;
-}
-
-/* frsp - frsp. */
-uint64_t helper_frsp(uint64_t arg)
-{
- CPU_DoubleU farg;
- float32 f32;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
-
- return farg.ll;
-}
-
-/* fsqrt - fsqrt. */
-uint64_t helper_fsqrt(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
- /* Square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
- } else {
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_sqrt(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fre - fre. */
-uint64_t helper_fre(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN reciprocal */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
- return farg.d;
-}
-
-/* fres - fres. */
-uint64_t helper_fres(uint64_t arg)
-{
- CPU_DoubleU farg;
- float32 f32;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN reciprocal */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
-
- return farg.ll;
-}
-
-/* frsqrte - frsqrte. */
-uint64_t helper_frsqrte(uint64_t arg)
-{
- CPU_DoubleU farg;
- float32 f32;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
- /* Reciprocal square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
- } else {
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN reciprocal square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_sqrt(farg.d, &env->fp_status);
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fsel - fsel. */
-uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1;
-
- farg1.ll = arg1;
-
- if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
- !float64_is_any_nan(farg1.d)) {
- return arg2;
- } else {
- return arg3;
- }
-}
-
-void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
-{
- CPU_DoubleU farg1, farg2;
- uint32_t ret = 0;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_any_nan(farg1.d) ||
- float64_is_any_nan(farg2.d))) {
- ret = 0x01UL;
- } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x08UL;
- } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x04UL;
- } else {
- ret = 0x02UL;
- }
-
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
- env->crf[crfD] = ret;
- if (unlikely(ret == 0x01UL
- && (float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d)))) {
- /* sNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
-}
-
-void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
-{
- CPU_DoubleU farg1, farg2;
- uint32_t ret = 0;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_any_nan(farg1.d) ||
- float64_is_any_nan(farg2.d))) {
- ret = 0x01UL;
- } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x08UL;
- } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x04UL;
- } else {
- ret = 0x02UL;
- }
-
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
- env->crf[crfD] = ret;
- if (unlikely(ret == 0x01UL)) {
- if (float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d)) {
- /* sNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXVC);
- } else {
- /* qNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
- }
- }
-}
-
-/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
target_ulong helper_clcs(uint32_t arg)
@@ -3125,623 +2032,6 @@ uint32_t helper_cntlzw32(uint32_t val)
return clz32(val);
}
-/* Single-precision floating-point conversions */
-static inline uint32_t efscfsi(uint32_t val)
-{
- CPU_FloatU u;
-
- u.f = int32_to_float32(val, &env->vec_status);
-
- return u.l;
-}
-
-static inline uint32_t efscfui(uint32_t val)
-{
- CPU_FloatU u;
-
- u.f = uint32_to_float32(val, &env->vec_status);
-
- return u.l;
-}
-
-static inline int32_t efsctsi(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_int32(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctui(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_uint32(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctsiz(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_int32_round_to_zero(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctuiz(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
-}
-
-static inline uint32_t efscfsf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.f = int32_to_float32(val, &env->vec_status);
- tmp = int64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_div(u.f, tmp, &env->vec_status);
-
- return u.l;
-}
-
-static inline uint32_t efscfuf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.f = uint32_to_float32(val, &env->vec_status);
- tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_div(u.f, tmp, &env->vec_status);
-
- return u.l;
-}
-
-static inline uint32_t efsctsf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
- tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_mul(u.f, tmp, &env->vec_status);
-
- return float32_to_int32(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctuf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
- tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_mul(u.f, tmp, &env->vec_status);
-
- return float32_to_uint32(u.f, &env->vec_status);
-}
-
-#define HELPER_SPE_SINGLE_CONV(name) \
- uint32_t helper_e##name(uint32_t val) \
- { \
- return e##name(val); \
- }
-/* efscfsi */
-HELPER_SPE_SINGLE_CONV(fscfsi);
-/* efscfui */
-HELPER_SPE_SINGLE_CONV(fscfui);
-/* efscfuf */
-HELPER_SPE_SINGLE_CONV(fscfuf);
-/* efscfsf */
-HELPER_SPE_SINGLE_CONV(fscfsf);
-/* efsctsi */
-HELPER_SPE_SINGLE_CONV(fsctsi);
-/* efsctui */
-HELPER_SPE_SINGLE_CONV(fsctui);
-/* efsctsiz */
-HELPER_SPE_SINGLE_CONV(fsctsiz);
-/* efsctuiz */
-HELPER_SPE_SINGLE_CONV(fsctuiz);
-/* efsctsf */
-HELPER_SPE_SINGLE_CONV(fsctsf);
-/* efsctuf */
-HELPER_SPE_SINGLE_CONV(fsctuf);
-
-#define HELPER_SPE_VECTOR_CONV(name) \
- uint64_t helper_ev##name(uint64_t val) \
- { \
- return ((uint64_t)e##name(val >> 32) << 32) | \
- (uint64_t)e##name(val); \
- }
-/* evfscfsi */
-HELPER_SPE_VECTOR_CONV(fscfsi);
-/* evfscfui */
-HELPER_SPE_VECTOR_CONV(fscfui);
-/* evfscfuf */
-HELPER_SPE_VECTOR_CONV(fscfuf);
-/* evfscfsf */
-HELPER_SPE_VECTOR_CONV(fscfsf);
-/* evfsctsi */
-HELPER_SPE_VECTOR_CONV(fsctsi);
-/* evfsctui */
-HELPER_SPE_VECTOR_CONV(fsctui);
-/* evfsctsiz */
-HELPER_SPE_VECTOR_CONV(fsctsiz);
-/* evfsctuiz */
-HELPER_SPE_VECTOR_CONV(fsctuiz);
-/* evfsctsf */
-HELPER_SPE_VECTOR_CONV(fsctsf);
-/* evfsctuf */
-HELPER_SPE_VECTOR_CONV(fsctuf);
-
-/* Single-precision floating-point arithmetic */
-static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_add(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-static inline uint32_t efssub(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_div(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-#define HELPER_SPE_SINGLE_ARITH(name) \
- uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
- { \
- return e##name(op1, op2); \
- }
-/* efsadd */
-HELPER_SPE_SINGLE_ARITH(fsadd);
-/* efssub */
-HELPER_SPE_SINGLE_ARITH(fssub);
-/* efsmul */
-HELPER_SPE_SINGLE_ARITH(fsmul);
-/* efsdiv */
-HELPER_SPE_SINGLE_ARITH(fsdiv);
-
-#define HELPER_SPE_VECTOR_ARITH(name) \
- uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \
- { \
- return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
- (uint64_t)e##name(op1, op2); \
- }
-/* evfsadd */
-HELPER_SPE_VECTOR_ARITH(fsadd);
-/* evfssub */
-HELPER_SPE_VECTOR_ARITH(fssub);
-/* evfsmul */
-HELPER_SPE_VECTOR_ARITH(fsmul);
-/* evfsdiv */
-HELPER_SPE_VECTOR_ARITH(fsdiv);
-
-/* Single-precision floating-point comparisons */
-static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
-}
-
-static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
-}
-
-static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
-}
-
-static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
-{
- /* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmplt(op1, op2);
-}
-
-static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
-{
- /* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmpgt(op1, op2);
-}
-
-static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
-{
- /* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmpeq(op1, op2);
-}
-
-#define HELPER_SINGLE_SPE_CMP(name) \
- uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
- { \
- return e##name(op1, op2) << 2; \
- }
-/* efststlt */
-HELPER_SINGLE_SPE_CMP(fststlt);
-/* efststgt */
-HELPER_SINGLE_SPE_CMP(fststgt);
-/* efststeq */
-HELPER_SINGLE_SPE_CMP(fststeq);
-/* efscmplt */
-HELPER_SINGLE_SPE_CMP(fscmplt);
-/* efscmpgt */
-HELPER_SINGLE_SPE_CMP(fscmpgt);
-/* efscmpeq */
-HELPER_SINGLE_SPE_CMP(fscmpeq);
-
-static inline uint32_t evcmp_merge(int t0, int t1)
-{
- return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
-}
-
-#define HELPER_VECTOR_SPE_CMP(name) \
- uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \
- { \
- return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
- }
-/* evfststlt */
-HELPER_VECTOR_SPE_CMP(fststlt);
-/* evfststgt */
-HELPER_VECTOR_SPE_CMP(fststgt);
-/* evfststeq */
-HELPER_VECTOR_SPE_CMP(fststeq);
-/* evfscmplt */
-HELPER_VECTOR_SPE_CMP(fscmplt);
-/* evfscmpgt */
-HELPER_VECTOR_SPE_CMP(fscmpgt);
-/* evfscmpeq */
-HELPER_VECTOR_SPE_CMP(fscmpeq);
-
-/* Double-precision floating-point conversion */
-uint64_t helper_efdcfsi(uint32_t val)
-{
- CPU_DoubleU u;
-
- u.d = int32_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfsid(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.d = int64_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfui(uint32_t val)
-{
- CPU_DoubleU u;
-
- u.d = uint32_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfuid(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.d = uint64_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint32_t helper_efdctsi(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_int32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctui(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_uint32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctsiz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_int32_round_to_zero(u.d, &env->vec_status);
-}
-
-uint64_t helper_efdctsidz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_int64_round_to_zero(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctuiz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
-}
-
-uint64_t helper_efdctuidz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
-}
-
-uint64_t helper_efdcfsf(uint32_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.d = int32_to_float64(val, &env->vec_status);
- tmp = int64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_div(u.d, tmp, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfuf(uint32_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.d = uint32_to_float64(val, &env->vec_status);
- tmp = int64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_div(u.d, tmp, &env->vec_status);
-
- return u.ll;
-}
-
-uint32_t helper_efdctsf(uint64_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
- tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_mul(u.d, tmp, &env->vec_status);
-
- return float64_to_int32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctuf(uint64_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
- tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_mul(u.d, tmp, &env->vec_status);
-
- return float64_to_uint32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efscfd(uint64_t val)
-{
- CPU_DoubleU u1;
- CPU_FloatU u2;
-
- u1.ll = val;
- u2.f = float64_to_float32(u1.d, &env->vec_status);
-
- return u2.l;
-}
-
-uint64_t helper_efdcfs(uint32_t val)
-{
- CPU_DoubleU u2;
- CPU_FloatU u1;
-
- u1.l = val;
- u2.d = float32_to_float64(u1.f, &env->vec_status);
-
- return u2.ll;
-}
-
-/* Double precision fixed-point arithmetic */
-uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_add(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_div(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-/* Double precision floating point helpers */
-uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
-}
-
-uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
-}
-
-uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
-}
-
-uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2)
-{
- /* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtstlt(op1, op2);
-}
-
-uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2)
-{
- /* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtstgt(op1, op2);
-}
-
-uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2)
-{
- /* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtsteq(op1, op2);
-}
-
/*****************************************************************************/
/* Softmmu support */
#if !defined(CONFIG_USER_ONLY)