*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
*/
#include "exec.h"
#include "host-utils.h"
addr = addr_add(addr, 4);
}
if (unlikely(nb > 0)) {
- for (sh = 24; nb > 0; nb--, sh -= 8)
+ for (sh = 24; nb > 0; nb--, sh -= 8) {
stb(addr, (env->gpr[reg] >> sh) & 0xFF);
- addr = addr_add(addr, 1);
+ addr = addr_add(addr, 1);
+ }
}
}
return f.l;
}
-static always_inline int fpisneg (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return u.ll >> 63 != 0;
-}
-
static always_inline int isden (float64 d)
{
CPU_DoubleU u;
return ((u.ll >> 52) & 0x7FF) == 0;
}
-static always_inline int iszero (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return (u.ll & ~0x8000000000000000ULL) == 0;
-}
-
-static always_inline int isinfinity (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return ((u.ll >> 52) & 0x7FF) == 0x7FF &&
- (u.ll & 0x000FFFFFFFFFFFFFULL) == 0;
-}
-
-#ifdef CONFIG_SOFTFLOAT
-static always_inline int isfinite (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return (((u.ll >> 52) & 0x7FF) != 0x7FF);
-}
-
-static always_inline int isnormal (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- uint32_t exp = (u.ll >> 52) & 0x7FF;
- return ((0 < exp) && (exp < 0x7FF));
-}
-#endif
-
uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
{
CPU_DoubleU farg;
int isneg;
int ret;
farg.ll = arg;
- isneg = fpisneg(farg.d);
+ isneg = float64_is_neg(farg.d);
if (unlikely(float64_is_nan(farg.d))) {
if (float64_is_signaling_nan(farg.d)) {
/* Signaling NaN: flags are undefined */
/* Quiet NaN */
ret = 0x11;
}
- } else if (unlikely(isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_infinity(farg.d))) {
/* +/- infinity */
if (isneg)
ret = 0x09;
else
ret = 0x05;
} else {
- if (iszero(farg.d)) {
+ if (float64_is_zero(farg.d)) {
/* +/- zero */
if (isneg)
ret = 0x12;
int ve;
ve = fpscr_ve;
- if (op & POWERPC_EXCP_FP_VXSNAN) {
- /* Operation on signaling NaN */
+ switch (op) {
+ case POWERPC_EXCP_FP_VXSNAN:
env->fpscr |= 1 << FPSCR_VXSNAN;
- }
- if (op & POWERPC_EXCP_FP_VXSOFT) {
- /* Software-defined condition */
+ break;
+ case POWERPC_EXCP_FP_VXSOFT:
env->fpscr |= 1 << FPSCR_VXSOFT;
- }
- switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
+ break;
case POWERPC_EXCP_FP_VXISI:
/* Magnitude subtraction of infinities */
env->fpscr |= 1 << FPSCR_VXISI;
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
if (ve == 0) {
/* Set the result to quiet NaN */
- ret = UINT64_MAX;
+ ret = 0xFFF8000000000000ULL;
env->fpscr &= ~(0xF << FPSCR_FPCC);
env->fpscr |= 0x11 << FPSCR_FPCC;
}
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
if (ve == 0) {
/* Set the result to quiet NaN */
- ret = UINT64_MAX;
+ ret = 0xFFF8000000000000ULL;
env->fpscr &= ~(0xF << FPSCR_FPCC);
env->fpscr |= 0x11 << FPSCR_FPCC;
}
return ret;
}
-static always_inline uint64_t float_zero_divide_excp (uint64_t arg1, uint64_t arg2)
+static always_inline void float_zero_divide_excp (void)
{
env->fpscr |= 1 << FPSCR_ZX;
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
}
- } else {
- /* Set the result to infinity */
- arg1 = ((arg1 ^ arg2) & 0x8000000000000000ULL);
- arg1 |= 0x7FFULL << 52;
}
- return arg1;
}
static always_inline void float_overflow_excp (void)
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;
new = (uint32_t)arg;
- new &= ~0x90000000;
- new |= prev & 0x90000000;
- for (i = 0; i < 7; i++) {
+ 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));
helper_raise_exception_err(env->exception_index, env->error_code);
} else {
int status = get_float_exception_flags(&env->fp_status);
- if (status & float_flag_overflow) {
+ 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();
float64_is_signaling_nan(farg2.d))) {
/* sNaN addition */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
- fpisneg(farg1.d) == fpisneg(farg2.d))) {
- farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
- } else {
+ } else 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 {
+ farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
}
#else
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
float64_is_signaling_nan(farg2.d))) {
/* sNaN subtraction */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
- fpisneg(farg1.d) != fpisneg(farg2.d))) {
- farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
- } else {
+ } else 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 {
+ farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
}
}
#else
float64_is_signaling_nan(farg2.d))) {
/* sNaN multiplication */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely((isinfinity(farg1.d) && iszero(farg2.d)) ||
- (iszero(farg1.d) && isinfinity(farg2.d)))) {
+ } else 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 {
float64_is_signaling_nan(farg2.d))) {
/* sNaN division */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(isinfinity(farg1.d) && isinfinity(farg2.d))) {
+ } else 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(iszero(farg2.d))) {
- if (iszero(farg1.d)) {
- /* Division of zero by zero */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
- } else {
- /* Division by zero */
- farg1.ll = float_zero_divide_excp(farg1.d, farg2.d);
- }
+ } 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 {
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
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_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
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_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
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_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
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_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
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_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity round */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else 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 {
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
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);
- 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 (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);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) + farg3.d;
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else 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 {
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
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);
- 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 (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);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) - farg3.d;
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else 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 USE_PRECISE_EMULATION
#ifdef FLOAT128
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);
- 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 (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);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) + farg3.d;
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else 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 USE_PRECISE_EMULATION
#ifdef FLOAT128
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);
- 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 (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);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) - farg3.d;
uint64_t helper_frsp (uint64_t arg)
{
CPU_DoubleU farg;
+ float32 f32;
farg.ll = arg;
#if USE_PRECISE_EMULATION
/* sNaN square root */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
} else {
- farg.d = float64_to_float32(farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
}
#else
- farg.d = float64_to_float32(farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
#endif
return farg.ll;
}
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
+ } else 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 {
/* fre - fre. */
uint64_t helper_fre (uint64_t arg)
{
- CPU_DoubleU farg;
+ CPU_DoubleU fone, farg;
+ fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(iszero(farg.d))) {
- /* Zero reciprocal */
- farg.ll = float_zero_divide_excp(1.0, farg.d);
- } else if (likely(isnormal(farg.d))) {
- farg.d = float64_div(1.0, farg.d, &env->fp_status);
} else {
- if (farg.ll == 0x8000000000000000ULL) {
- farg.ll = 0xFFF0000000000000ULL;
- } else if (farg.ll == 0x0000000000000000ULL) {
- farg.ll = 0x7FF0000000000000ULL;
- } else if (float64_is_nan(farg.d)) {
- farg.ll = 0x7FF8000000000000ULL;
- } else if (fpisneg(farg.d)) {
- farg.ll = 0x8000000000000000ULL;
- } else {
- farg.ll = 0x0000000000000000ULL;
- }
+ farg.d = float64_div(fone.d, farg.d, &env->fp_status);
}
return farg.d;
}
/* fres - fres. */
uint64_t helper_fres (uint64_t arg)
{
- CPU_DoubleU farg;
+ CPU_DoubleU fone, farg;
+ float32 f32;
+ fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(iszero(farg.d))) {
- /* Zero reciprocal */
- farg.ll = float_zero_divide_excp(1.0, farg.d);
- } else if (likely(isnormal(farg.d))) {
-#if USE_PRECISE_EMULATION
- farg.d = float64_div(1.0, farg.d, &env->fp_status);
- farg.d = float64_to_float32(farg.d, &env->fp_status);
-#else
- farg.d = float32_div(1.0, farg.d, &env->fp_status);
-#endif
} else {
- if (farg.ll == 0x8000000000000000ULL) {
- farg.ll = 0xFFF0000000000000ULL;
- } else if (farg.ll == 0x0000000000000000ULL) {
- farg.ll = 0x7FF0000000000000ULL;
- } else if (float64_is_nan(farg.d)) {
- farg.ll = 0x7FF8000000000000ULL;
- } else if (fpisneg(farg.d)) {
- farg.ll = 0x8000000000000000ULL;
- } else {
- farg.ll = 0x0000000000000000ULL;
- }
+ farg.d = float64_div(fone.d, 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;
+ CPU_DoubleU fone, farg;
+ float32 f32;
+ fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal square root */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
+ } else 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 (likely(isnormal(farg.d))) {
- farg.d = float64_sqrt(farg.d, &env->fp_status);
- farg.d = float32_div(1.0, farg.d, &env->fp_status);
} else {
- if (farg.ll == 0x8000000000000000ULL) {
- farg.ll = 0xFFF0000000000000ULL;
- } else if (farg.ll == 0x0000000000000000ULL) {
- farg.ll = 0x7FF0000000000000ULL;
- } else if (float64_is_nan(farg.d)) {
- farg.ll |= 0x000FFFFFFFFFFFFFULL;
- } else if (fpisneg(farg.d)) {
- farg.ll = 0x7FF8000000000000ULL;
- } else {
- farg.ll = 0x0000000000000000ULL;
- }
+ farg.d = float64_sqrt(farg.d, &env->fp_status);
+ farg.d = float64_div(fone.d, 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, farg2, farg3;
+ CPU_DoubleU farg1;
farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
- if (!fpisneg(farg1.d) || iszero(farg1.d))
- return farg2.ll;
+ if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
+ return arg2;
else
- return farg2.ll;
+ return arg3;
}
-uint32_t helper_fcmpu (uint64_t arg1, uint64_t arg2)
+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_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ if (unlikely(float64_is_nan(farg1.d) ||
+ float64_is_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 {
- 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;
- }
+ ret = 0x02UL;
}
+
env->fpscr &= ~(0x0F << FPSCR_FPRF);
env->fpscr |= ret << FPSCR_FPRF;
- return ret;
+ 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);
+ }
}
-uint32_t helper_fcmpo (uint64_t arg1, uint64_t arg2)
+void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
{
CPU_DoubleU farg1, farg2;
uint32_t ret = 0;
if (unlikely(float64_is_nan(farg1.d) ||
float64_is_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 */
/* qNaN comparison */
fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
}
- } 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;
- return ret;
}
#if !defined (CONFIG_USER_ONLY)
return i;
}
+/*****************************************************************************/
+/* Altivec extension helpers */
+#if defined(WORDS_BIGENDIAN)
+#define HI_IDX 0
+#define LO_IDX 1
+#else
+#define HI_IDX 1
+#define LO_IDX 0
+#endif
+
+#if defined(WORDS_BIGENDIAN)
+#define VECTOR_FOR_INORDER_I(index, element) \
+ for (index = 0; index < ARRAY_SIZE(r->element); index++)
+#else
+#define VECTOR_FOR_INORDER_I(index, element) \
+ for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
+#endif
+
+#define VARITH_DO(name, op, element) \
+void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+{ \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ r->element[i] = a->element[i] op b->element[i]; \
+ } \
+}
+#define VARITH(suffix, element) \
+ VARITH_DO(add##suffix, +, element) \
+ VARITH_DO(sub##suffix, -, element)
+VARITH(ubm, u8)
+VARITH(uhm, u16)
+VARITH(uwm, u32)
+#undef VARITH_DO
+#undef VARITH
+
+#define VAVG_DO(name, element, etype) \
+ void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
+ r->element[i] = x >> 1; \
+ } \
+ }
+
+#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
+ VAVG_DO(avgs##type, signed_element, signed_type) \
+ VAVG_DO(avgu##type, unsigned_element, unsigned_type)
+VAVG(b, s8, int16_t, u8, uint16_t)
+VAVG(h, s16, int32_t, u16, uint32_t)
+VAVG(w, s32, int64_t, u32, uint64_t)
+#undef VAVG_DO
+#undef VAVG
+
+#define VMINMAX_DO(name, compare, element) \
+ void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ if (a->element[i] compare b->element[i]) { \
+ r->element[i] = b->element[i]; \
+ } else { \
+ r->element[i] = a->element[i]; \
+ } \
+ } \
+ }
+#define VMINMAX(suffix, element) \
+ VMINMAX_DO(min##suffix, >, element) \
+ VMINMAX_DO(max##suffix, <, element)
+VMINMAX(sb, s8)
+VMINMAX(sh, s16)
+VMINMAX(sw, s32)
+VMINMAX(ub, u8)
+VMINMAX(uh, u16)
+VMINMAX(uw, u32)
+#undef VMINMAX_DO
+#undef VMINMAX
+
+#define VMRG_DO(name, element, highp) \
+ void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ ppc_avr_t result; \
+ int i; \
+ size_t n_elems = ARRAY_SIZE(r->element); \
+ for (i = 0; i < n_elems/2; i++) { \
+ if (highp) { \
+ result.element[i*2+HI_IDX] = a->element[i]; \
+ result.element[i*2+LO_IDX] = b->element[i]; \
+ } else { \
+ result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
+ result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
+ } \
+ } \
+ *r = result; \
+ }
+#if defined(WORDS_BIGENDIAN)
+#define MRGHI 0
+#define MRGL0 1
+#else
+#define MRGHI 1
+#define MRGLO 0
+#endif
+#define VMRG(suffix, element) \
+ VMRG_DO(mrgl##suffix, element, MRGHI) \
+ VMRG_DO(mrgh##suffix, element, MRGLO)
+VMRG(b, u8)
+VMRG(h, u16)
+VMRG(w, u32)
+#undef VMRG_DO
+#undef VMRG
+#undef MRGHI
+#undef MRGLO
+
+#define VMUL_DO(name, mul_element, prod_element, evenp) \
+ void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ VECTOR_FOR_INORDER_I(i, prod_element) { \
+ if (evenp) { \
+ r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
+ } else { \
+ r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
+ } \
+ } \
+ }
+#define VMUL(suffix, mul_element, prod_element) \
+ VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
+ VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
+VMUL(sb, s8, s16)
+VMUL(sh, s16, s32)
+VMUL(ub, u8, u16)
+VMUL(uh, u16, u32)
+#undef VMUL_DO
+#undef VMUL
+
+#undef VECTOR_FOR_INORDER_I
+#undef HI_IDX
+#undef LO_IDX
+
/*****************************************************************************/
/* SPE extension helpers */
/* Use a table to make this quicker */